aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKoen Kooi <koen@dominion.thruhere.net>2011-05-21 10:55:49 +0200
committerKoen Kooi <koen@dominion.thruhere.net>2011-05-21 10:55:49 +0200
commit1735237550d85da337ea57cb5d6be9ccc8c0355c (patch)
tree1f6e1ae7c5e4a3eb37b2995c58707b21d6a9ec7a
parent07e8c30da96d52798069494f17ab7f871357f3b5 (diff)
downloadopenembedded-core-contrib-1735237550d85da337ea57cb5d6be9ccc8c0355c.tar.gz
linux-omap 2.6.39: import from OE
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/beagle/0001-OMAP3-beagle-add-support-for-beagleboard-xM-revision.patch115
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/beagle/0002-OMAP3-beagle-add-support-for-expansionboards.patch354
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/beagleboard/configs/stock3490
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/beagleboard/defconfig3490
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/sakoman/0001-OMAP-DSS2-DSI-fix-use_sys_clk-highfreq.patch33
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/sakoman/0002-OMAP-DSS2-DSI-fix-dsi_dump_clocks.patch49
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/sakoman/0003-OMAP2PLUS-DSS2-Fix-Return-correct-lcd-clock-source-f.patch43
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/sakoman/0004-OMAP-DSS-DSI-Fix-DSI-PLL-power-bug.patch64
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/sakoman/0005-OMAP-DSS2-fix-panel-Kconfig-dependencies.patch61
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/sakoman/0006-OMAP-DSS2-add-bootarg-for-selecting-svideo-or-compos.patch75
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/sakoman/0007-video-add-timings-for-hd720.patch27
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/sakoman/0008-drivers-net-smsc911x-return-ENODEV-if-device-is-not-.patch29
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/sakoman/0009-drivers-input-touchscreen-ads7846-return-ENODEV-if-d.patch47
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/sakoman/0010-Revert-omap2_mcspi-Flush-posted-writes.patch25
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/sakoman/0011-Revert-omap_hsmmc-improve-interrupt-synchronisation.patch482
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/sakoman/0012-Don-t-turn-SDIO-cards-off-to-save-power.-Doing-so-wi.patch52
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/sakoman/0013-Enable-the-use-of-SDIO-card-interrupts.patch288
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/sakoman/0014-soc-codecs-Enable-audio-capture-by-default-for-twl40.patch27
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/sakoman/0015-soc-codecs-twl4030-Turn-on-mic-bias-by-default.patch25
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/sakoman/0016-RTC-add-support-for-backup-battery-recharge.patch55
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/sakoman/0017-ARM-OMAP2-mmc-twl4030-move-clock-input-selection-pri.patch39
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/sakoman/0018-Add-power-off-support-for-the-TWL4030-companion.patch103
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/sakoman/0019-ARM-OMAP-Add-twl4030-madc-support-to-Overo.patch33
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/sakoman/0020-Enabling-Hwmon-driver-for-twl4030-madc.patch46
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/sakoman/0021-mfd-twl-core-enable-madc-clock.patch54
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/sakoman/0022-ARM-OMAP-automatically-set-musb-mode-in-platform-dat.patch49
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/sakoman/0023-omap-mmc-Adjust-dto-to-eliminate-timeout-errors.patch28
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/sakoman/0024-omap-Fix-mtd-subpage-read-alignment.patch95
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/sakoman/0025-mtd-nand-omap2-Force-all-buffer-reads-to-u32-alignme.patch35
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/sakoman/0026-omap-nand-fix-subpage-ecc-issue-with-prefetch.patch63
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/sakoman/0027-OMAP-Overo-Add-support-for-spidev.patch46
-rw-r--r--recipes-kernel/linux/linux-omap-2.6.39/sakoman/0028-unionfs-Add-support-for-unionfs-2.5.9.patch11494
-rw-r--r--recipes-kernel/linux/linux-omap_2.6.39.bb54
33 files changed, 20970 insertions, 0 deletions
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/beagle/0001-OMAP3-beagle-add-support-for-beagleboard-xM-revision.patch b/recipes-kernel/linux/linux-omap-2.6.39/beagle/0001-OMAP3-beagle-add-support-for-beagleboard-xM-revision.patch
new file mode 100644
index 0000000000..c7b6230b56
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/beagle/0001-OMAP3-beagle-add-support-for-beagleboard-xM-revision.patch
@@ -0,0 +1,115 @@
+From 6597e99e0b74076530e34608e2d9a7b86a694b8e Mon Sep 17 00:00:00 2001
+From: Koen Kooi <koen@dominion.thruhere.net>
+Date: Fri, 20 May 2011 12:48:37 +0200
+Subject: [PATCH 1/2] OMAP3: beagle: add support for beagleboard xM revision C
+
+The USB enable GPIO has been inverted and the USER button moved.
+
+Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
+---
+ arch/arm/mach-omap2/board-omap3beagle.c | 32 +++++++++++++++++++++++-------
+ 1 files changed, 24 insertions(+), 8 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index 2de4b02..1eb1e8e 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -62,7 +62,9 @@
+ * AXBX = GPIO173, GPIO172, GPIO171: 1 1 1
+ * C1_3 = GPIO173, GPIO172, GPIO171: 1 1 0
+ * C4 = GPIO173, GPIO172, GPIO171: 1 0 1
+- * XM = GPIO173, GPIO172, GPIO171: 0 0 0
++ * XMA = GPIO173, GPIO172, GPIO171: 0 0 0
++ * XMB = GPIO173, GPIO172, GPIO171: 0 0 1
++ * XMC = GPIO173, GPIO172, GPIO171: 0 1 0
+ */
+ enum {
+ OMAP3BEAGLE_BOARD_UNKN = 0,
+@@ -70,6 +72,7 @@ enum {
+ OMAP3BEAGLE_BOARD_C1_3,
+ OMAP3BEAGLE_BOARD_C4,
+ OMAP3BEAGLE_BOARD_XM,
++ OMAP3BEAGLE_BOARD_XMC,
+ };
+
+ static u8 omap3_beagle_version;
+@@ -124,9 +127,17 @@ static void __init omap3_beagle_init_rev(void)
+ printk(KERN_INFO "OMAP3 Beagle Rev: xM\n");
+ omap3_beagle_version = OMAP3BEAGLE_BOARD_XM;
+ break;
++ case 1:
++ printk(KERN_INFO "OMAP3 Beagle Rev: xM B\n");
++ omap3_beagle_version = OMAP3BEAGLE_BOARD_XM;
++ break;
++ case 2:
++ printk(KERN_INFO "OMAP3 Beagle Rev: xM C\n");
++ omap3_beagle_version = OMAP3BEAGLE_BOARD_XMC;
++ break;
+ default:
+- printk(KERN_INFO "OMAP3 Beagle Rev: unknown %hd\n", beagle_rev);
+- omap3_beagle_version = OMAP3BEAGLE_BOARD_UNKN;
++ printk(KERN_INFO "OMAP3 Beagle Rev: unknown %hd, assuming xM C or newer\n", beagle_rev);
++ omap3_beagle_version = OMAP3BEAGLE_BOARD_XMC;
+ }
+
+ return;
+@@ -278,7 +289,7 @@ static int beagle_twl_gpio_setup(struct device *dev,
+ {
+ int r;
+
+- if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) {
++ if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM || omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XMC) {
+ mmc[0].gpio_wp = -EINVAL;
+ } else if ((omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_C1_3) ||
+ (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_C4)) {
+@@ -298,7 +309,7 @@ static int beagle_twl_gpio_setup(struct device *dev,
+ /* REVISIT: need ehci-omap hooks for external VBUS
+ * power switch and overcurrent detect
+ */
+- if (omap3_beagle_get_rev() != OMAP3BEAGLE_BOARD_XM) {
++ if (omap3_beagle_get_rev() != OMAP3BEAGLE_BOARD_XM && omap3_beagle_get_rev() != OMAP3BEAGLE_BOARD_XMC) {
+ r = gpio_request(gpio + 1, "EHCI_nOC");
+ if (!r) {
+ r = gpio_direction_input(gpio + 1);
+@@ -320,7 +331,7 @@ static int beagle_twl_gpio_setup(struct device *dev,
+ gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0);
+
+ /* DVI reset GPIO is different between beagle revisions */
+- if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM)
++ if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM || omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XMC)
+ beagle_dvi_device.reset_gpio = 129;
+ else
+ beagle_dvi_device.reset_gpio = 170;
+@@ -334,7 +345,7 @@ static int beagle_twl_gpio_setup(struct device *dev,
+ * P7/P8 revisions(prototype): Camera EN
+ * A2+ revisions (production): LDO (supplies DVI, serial, led blocks)
+ */
+- if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) {
++ if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM || omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XMC) {
+ r = gpio_request(gpio + 1, "nDVI_PWR_EN");
+ if (!r) {
+ r = gpio_direction_output(gpio + 1, 0);
+@@ -625,7 +636,7 @@ static void __init beagle_opp_init(void)
+ }
+
+ /* Custom OPP enabled for XM */
+- if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) {
++ if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM || omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XMC) {
+ struct omap_hwmod *mh = omap_hwmod_lookup("mpu");
+ struct omap_hwmod *dh = omap_hwmod_lookup("iva");
+ struct device *dev;
+@@ -665,6 +676,11 @@ static void __init omap3_beagle_init(void)
+ omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+ omap3_beagle_init_rev();
+ omap3_beagle_i2c_init();
++
++ if (cpu_is_omap3630()) {
++ gpio_buttons[0].gpio = 4;
++ }
++
+ platform_add_devices(omap3_beagle_devices,
+ ARRAY_SIZE(omap3_beagle_devices));
+ omap_display_init(&beagle_dss_data);
+--
+1.6.6.1
+
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/beagle/0002-OMAP3-beagle-add-support-for-expansionboards.patch b/recipes-kernel/linux/linux-omap-2.6.39/beagle/0002-OMAP3-beagle-add-support-for-expansionboards.patch
new file mode 100644
index 0000000000..68f318b8da
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/beagle/0002-OMAP3-beagle-add-support-for-expansionboards.patch
@@ -0,0 +1,354 @@
+From 70b4b60b198137ca8aebd577142ea3bb6c273a55 Mon Sep 17 00:00:00 2001
+From: Koen Kooi <koen@dominion.thruhere.net>
+Date: Fri, 20 May 2011 13:06:24 +0200
+Subject: [PATCH 2/2] OMAP3: beagle: add support for expansionboards
+
+Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
+---
+ arch/arm/mach-omap2/board-omap3beagle.c | 267 ++++++++++++++++++++++++++++++-
+ 1 files changed, 264 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index 1eb1e8e..40e54f2 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -21,6 +21,7 @@
+ #include <linux/io.h>
+ #include <linux/leds.h>
+ #include <linux/gpio.h>
++#include <linux/irq.h>
+ #include <linux/input.h>
+ #include <linux/gpio_keys.h>
+ #include <linux/opp.h>
+@@ -153,6 +154,162 @@ fail0:
+ return;
+ }
+
++char expansionboard_name[16];
++
++#if defined(CONFIG_WL12XX) || defined(CONFIG_WL12XX_MODULE)
++#include <linux/regulator/fixed.h>
++#include <linux/wl12xx.h>
++
++#define OMAP_BEAGLE_WLAN_EN_GPIO (139)
++#define OMAP_BEAGLE_BT_EN_GPIO (138)
++#define OMAP_BEAGLE_WLAN_IRQ_GPIO (137)
++#define OMAP_BEAGLE_FM_EN_BT_WU (136)
++
++struct wl12xx_platform_data omap_beagle_wlan_data __initdata = {
++ .irq = OMAP_GPIO_IRQ(OMAP_BEAGLE_WLAN_IRQ_GPIO),
++ .board_ref_clock = 2, /* 38.4 MHz */
++};
++
++static int gpios[] = {OMAP_BEAGLE_BT_EN_GPIO, OMAP_BEAGLE_FM_EN_BT_WU, -1};
++static struct platform_device wl12xx_device = {
++ .name = "kim",
++ .id = -1,
++ .dev.platform_data = &gpios,
++};
++
++static struct omap2_hsmmc_info mmcbbt[] = {
++ {
++ .mmc = 1,
++ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
++ .gpio_wp = 29,
++ },
++ {
++ .name = "wl1271",
++ .mmc = 2,
++ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_POWER_OFF_CARD,
++ .gpio_wp = -EINVAL,
++ .gpio_cd = -EINVAL,
++ .nonremovable = true,
++ },
++ {} /* Terminator */
++ };
++
++static struct regulator_consumer_supply beagle_vmmc2_supply = {
++ .supply = "vmmc",
++ .dev_name = "mmci-omap-hs.1",
++};
++
++static struct regulator_init_data beagle_vmmc2 = {
++ .constraints = {
++ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
++ },
++ .num_consumer_supplies = 1,
++ .consumer_supplies = &beagle_vmmc2_supply,
++};
++
++static struct fixed_voltage_config beagle_vwlan = {
++ .supply_name = "vwl1271",
++ .microvolts = 1800000, /* 1.8V */
++ .gpio = OMAP_BEAGLE_WLAN_EN_GPIO,
++ .startup_delay = 70000, /* 70ms */
++ .enable_high = 1,
++ .enabled_at_boot = 0,
++ .init_data = &beagle_vmmc2,
++};
++
++static struct platform_device omap_vwlan_device = {
++ .name = "reg-fixed-voltage",
++ .id = 1,
++ .dev = {
++ .platform_data = &beagle_vwlan,
++ },
++};
++#endif
++
++#if defined(CONFIG_ENC28J60) || defined(CONFIG_ENC28J60_MODULE)
++
++#include <plat/mcspi.h>
++#include <linux/spi/spi.h>
++
++#define OMAP3BEAGLE_GPIO_ENC28J60_IRQ 157
++
++static struct omap2_mcspi_device_config enc28j60_spi_chip_info = {
++ .turbo_mode = 0,
++ .single_channel = 1, /* 0: slave, 1: master */
++};
++
++static struct spi_board_info omap3beagle_zippy_spi_board_info[] __initdata = {
++ {
++ .modalias = "enc28j60",
++ .bus_num = 4,
++ .chip_select = 0,
++ .max_speed_hz = 20000000,
++ .controller_data = &enc28j60_spi_chip_info,
++ },
++};
++
++static void __init omap3beagle_enc28j60_init(void)
++{
++ if ((gpio_request(OMAP3BEAGLE_GPIO_ENC28J60_IRQ, "ENC28J60_IRQ") == 0) &&
++ (gpio_direction_input(OMAP3BEAGLE_GPIO_ENC28J60_IRQ) == 0)) {
++ gpio_export(OMAP3BEAGLE_GPIO_ENC28J60_IRQ, 0);
++ omap3beagle_zippy_spi_board_info[0].irq = OMAP_GPIO_IRQ(OMAP3BEAGLE_GPIO_ENC28J60_IRQ);
++ irq_set_irq_type(omap3beagle_zippy_spi_board_info[0].irq, IRQ_TYPE_EDGE_FALLING);
++ } else {
++ printk(KERN_ERR "could not obtain gpio for ENC28J60_IRQ\n");
++ return;
++ }
++
++ spi_register_board_info(omap3beagle_zippy_spi_board_info,
++ ARRAY_SIZE(omap3beagle_zippy_spi_board_info));
++}
++
++#else
++static inline void __init omap3beagle_enc28j60_init(void) { return; }
++#endif
++
++#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
++
++#include <plat/mcspi.h>
++#include <linux/spi/spi.h>
++
++#define OMAP3BEAGLE_GPIO_KS8851_IRQ 157
++
++static struct omap2_mcspi_device_config ks8851_spi_chip_info = {
++ .turbo_mode = 0,
++ .single_channel = 1, /* 0: slave, 1: master */
++};
++
++static struct spi_board_info omap3beagle_zippy2_spi_board_info[] __initdata = {
++ {
++ .modalias = "ks8851",
++ .bus_num = 4,
++ .chip_select = 0,
++ .max_speed_hz = 36000000,
++ .controller_data = &ks8851_spi_chip_info,
++ },
++};
++
++static void __init omap3beagle_ks8851_init(void)
++{
++ if ((gpio_request(OMAP3BEAGLE_GPIO_KS8851_IRQ, "KS8851_IRQ") == 0) &&
++ (gpio_direction_input(OMAP3BEAGLE_GPIO_KS8851_IRQ) == 0)) {
++ gpio_export(OMAP3BEAGLE_GPIO_KS8851_IRQ, 0);
++ omap3beagle_zippy2_spi_board_info[0].irq = OMAP_GPIO_IRQ(OMAP3BEAGLE_GPIO_KS8851_IRQ);
++ irq_set_irq_type(omap3beagle_zippy2_spi_board_info[0].irq, IRQ_TYPE_EDGE_FALLING);
++ } else {
++ printk(KERN_ERR "could not obtain gpio for KS8851_IRQ\n");
++ return;
++ }
++
++ spi_register_board_info(omap3beagle_zippy2_spi_board_info,
++ ARRAY_SIZE(omap3beagle_zippy2_spi_board_info));
++}
++
++#else
++static inline void __init omap3beagle_ks8851_init(void) { return; }
++#endif
++
+ static struct mtd_partition omap3beagle_nand_partitions[] = {
+ /* All the partition sizes are listed in terms of NAND block size */
+ {
+@@ -271,6 +428,12 @@ static struct omap2_hsmmc_info mmc[] = {
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
+ .gpio_wp = 29,
+ },
++ {
++ .mmc = 2,
++ .caps = MMC_CAP_4_BIT_DATA,
++ .transceiver = true,
++ .ocr_mask = 0x00100000, /* 3.3V */
++ },
+ {} /* Terminator */
+ };
+
+@@ -300,11 +463,25 @@ static int beagle_twl_gpio_setup(struct device *dev,
+ }
+ /* gpio + 0 is "mmc0_cd" (input/IRQ) */
+ mmc[0].gpio_cd = gpio + 0;
++#if defined(CONFIG_WL12XX) || defined(CONFIG_WL12XX_MODULE)
++ if(!strcmp(expansionboard_name, "bbtoys-wifi")) {
++ omap2_hsmmc_init(mmcbbt);
++ /* link regulators to MMC adapters */
++ beagle_vmmc1_supply.dev = mmcbbt[0].dev;
++ beagle_vsim_supply.dev = mmcbbt[0].dev;
++ } else {
++ omap2_hsmmc_init(mmc);
++ /* link regulators to MMC adapters */
++ beagle_vmmc1_supply.dev = mmc[0].dev;
++ beagle_vsim_supply.dev = mmc[0].dev;
++ }
++#else
+ omap2_hsmmc_init(mmc);
+
+ /* link regulators to MMC adapters */
+ beagle_vmmc1_supply.dev = mmc[0].dev;
+ beagle_vsim_supply.dev = mmc[0].dev;
++#endif
+
+ /* REVISIT: need ehci-omap hooks for external VBUS
+ * power switch and overcurrent detect
+@@ -464,7 +641,7 @@ static struct twl4030_platform_data beagle_twldata = {
+ .vpll2 = &beagle_vpll2,
+ };
+
+-static struct i2c_board_info __initdata beagle_i2c_boardinfo[] = {
++static struct i2c_board_info __initdata beagle_i2c1_boardinfo[] = {
+ {
+ I2C_BOARD_INFO("twl4030", 0x48),
+ .flags = I2C_CLIENT_WAKE,
+@@ -479,10 +656,24 @@ static struct i2c_board_info __initdata beagle_i2c_eeprom[] = {
+ },
+ };
+
++#if defined(CONFIG_RTC_DRV_DS1307) || \
++ defined(CONFIG_RTC_DRV_DS1307_MODULE)
++
++static struct i2c_board_info __initdata beagle_i2c2_boardinfo[] = {
++ {
++ I2C_BOARD_INFO("ds1307", 0x68),
++ },
++};
++#else
++static struct i2c_board_info __initdata beagle_i2c2_boardinfo[] = {};
++#endif
++
+ static int __init omap3_beagle_i2c_init(void)
+ {
+- omap_register_i2c_bus(1, 2600, beagle_i2c_boardinfo,
+- ARRAY_SIZE(beagle_i2c_boardinfo));
++ omap_register_i2c_bus(1, 2600, beagle_i2c1_boardinfo,
++ ARRAY_SIZE(beagle_i2c1_boardinfo));
++ omap_register_i2c_bus(2, 400, beagle_i2c2_boardinfo,
++ ARRAY_SIZE(beagle_i2c2_boardinfo));
+ /* Bus 3 is attached to the DVI port where devices like the pico DLP
+ * projector don't work reliably with 400kHz */
+ omap_register_i2c_bus(3, 100, beagle_i2c_eeprom, ARRAY_SIZE(beagle_i2c_eeprom));
+@@ -625,6 +816,15 @@ static struct omap_musb_board_data musb_board_data = {
+ .power = 100,
+ };
+
++static int __init expansionboard_setup(char *str)
++{
++ if (!str)
++ return -EINVAL;
++ strncpy(expansionboard_name, str, 16);
++ printk(KERN_INFO "Beagle expansionboard: %s\n", expansionboard_name);
++ return 0;
++}
++
+ static void __init beagle_opp_init(void)
+ {
+ int r = 0;
+@@ -691,6 +891,65 @@ static void __init omap3_beagle_init(void)
+ /* REVISIT leave DVI powered down until it's needed ... */
+ gpio_direction_output(170, true);
+
++ if(!strcmp(expansionboard_name, "zippy"))
++ {
++ printk(KERN_INFO "Beagle expansionboard: initializing enc28j60\n");
++ omap3beagle_enc28j60_init();
++ printk(KERN_INFO "Beagle expansionboard: assigning GPIO 141 and 162 to MMC1\n");
++ mmc[1].gpio_wp = 141;
++ mmc[1].gpio_cd = 162;
++ }
++
++ if(!strcmp(expansionboard_name, "zippy2"))
++ {
++ printk(KERN_INFO "Beagle expansionboard: initializing ks_8851\n");
++ omap3beagle_ks8851_init();
++ printk(KERN_INFO "Beagle expansionboard: assigning GPIO 141 and 162 to MMC1\n");
++ mmc[1].gpio_wp = 141;
++ mmc[1].gpio_cd = 162;
++ }
++
++ if(!strcmp(expansionboard_name, "trainer"))
++ {
++ printk(KERN_INFO "Beagle expansionboard: exporting GPIOs 130-141,162 to userspace\n");
++ gpio_request(130, "sysfs");
++ gpio_export(130, 1);
++ gpio_request(131, "sysfs");
++ gpio_export(131, 1);
++ gpio_request(132, "sysfs");
++ gpio_export(132, 1);
++ gpio_request(133, "sysfs");
++ gpio_export(133, 1);
++ gpio_request(134, "sysfs");
++ gpio_export(134, 1);
++ gpio_request(135, "sysfs");
++ gpio_export(135, 1);
++ gpio_request(136, "sysfs");
++ gpio_export(136, 1);
++ gpio_request(137, "sysfs");
++ gpio_export(137, 1);
++ gpio_request(138, "sysfs");
++ gpio_export(138, 1);
++ gpio_request(139, "sysfs");
++ gpio_export(139, 1);
++ gpio_request(140, "sysfs");
++ gpio_export(140, 1);
++ gpio_request(141, "sysfs");
++ gpio_export(141, 1);
++ gpio_request(162, "sysfs");
++ gpio_export(162, 1);
++ }
++
++ if(!strcmp(expansionboard_name, "bbtoys-wifi"))
++ {
++ if (wl12xx_set_platform_data(&omap_beagle_wlan_data))
++ pr_err("error setting wl12xx data\n");
++ printk(KERN_INFO "Beagle expansionboard: registering wl12xx bt platform device\n");
++ platform_device_register(&wl12xx_device);
++ printk(KERN_INFO "Beagle expansionboard: registering wl12xx wifi platform device\n");
++ platform_device_register(&omap_vwlan_device);
++ }
++
+ usb_musb_init(&musb_board_data);
+ usbhs_init(&usbhs_bdata);
+ omap3beagle_flash_init();
+@@ -703,6 +962,8 @@ static void __init omap3_beagle_init(void)
+ beagle_opp_init();
+ }
+
++early_param("buddy", expansionboard_setup);
++
+ MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagle Board")
+ /* Maintainer: Syed Mohammed Khasim - http://beagleboard.org */
+ .boot_params = 0x80000100,
+--
+1.6.6.1
+
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/beagleboard/configs/stock b/recipes-kernel/linux/linux-omap-2.6.39/beagleboard/configs/stock
new file mode 100644
index 0000000000..9e81a05708
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/beagleboard/configs/stock
@@ -0,0 +1,3490 @@
+#
+# Automatically generated make config: don't edit
+# Linux/arm 2.6.39 Kernel Configuration
+# Fri May 20 13:11:13 2011
+#
+CONFIG_ARM=y
+CONFIG_HAVE_PWM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_HAVE_SCHED_CLOCK=y
+CONFIG_GENERIC_GPIO=y
+# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_KTIME_SCALAR=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_ARCH_HAS_CPUFREQ=y
+CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_VECTORS_BASE=0xffff0000
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+CONFIG_HAVE_IRQ_WORK=y
+CONFIG_IRQ_WORK=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_LZO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_FHANDLE=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+# CONFIG_AUDIT is not set
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_HAVE_SPARSE_IRQ=y
+CONFIG_GENERIC_IRQ_SHOW=y
+# CONFIG_SPARSE_IRQ is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_PREEMPT_RCU=y
+# CONFIG_TINY_RCU is not set
+# CONFIG_TINY_PREEMPT_RCU is not set
+CONFIG_PREEMPT_RCU=y
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_CGROUPS=y
+# CONFIG_CGROUP_DEBUG is not set
+CONFIG_CGROUP_NS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CPUSETS=y
+CONFIG_PROC_PID_CPUSET=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_MEM_RES_CTLR=y
+CONFIG_CGROUP_MEM_RES_CTLR_SWAP=y
+CONFIG_CGROUP_MEM_RES_CTLR_SWAP_ENABLED=y
+CONFIG_CGROUP_PERF=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+# CONFIG_BLK_CGROUP is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_MM_OWNER=y
+# CONFIG_SYSFS_DEPRECATED is not set
+# CONFIG_RELAY is not set
+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_XZ=y
+CONFIG_RD_LZO=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EXPERT=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+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_EMBEDDED=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_PERF_EVENTS=y
+# CONFIG_PERF_COUNTERS is not set
+# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
+CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_HW_BREAKPOINT=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=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+CONFIG_BLK_DEV_BSG=y
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_DEADLINE is not set
+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 is not set
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set
+# 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 is not set
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+# CONFIG_INLINE_READ_UNLOCK_IRQ is not set
+# 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 is not set
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+# CONFIG_MUTEX_SPIN_ON_OWNER is not set
+CONFIG_FREEZER=y
+
+#
+# System Type
+#
+CONFIG_MMU=y
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_VEXPRESS is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_BCMRING is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CNS3XXX is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_MXS is not set
+# CONFIG_ARCH_STMP3XXX is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_DOVE is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_LPC32XX is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_NUC93X is not set
+# CONFIG_ARCH_TEGRA is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_SHMOBILE is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5P64X0 is not set
+# CONFIG_ARCH_S5P6442 is not set
+# CONFIG_ARCH_S5PC100 is not set
+# CONFIG_ARCH_S5PV210 is not set
+# CONFIG_ARCH_EXYNOS4 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_TCC_926 is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_U8500 is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_PLAT_SPEAR is not set
+# CONFIG_ARCH_VT8500 is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_KEYBOARD_GPIO_POLLED is not set
+
+#
+# TI OMAP Common Features
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+CONFIG_ARCH_OMAP2PLUS=y
+
+#
+# OMAP Feature Selections
+#
+CONFIG_OMAP_SMARTREFLEX=y
+CONFIG_OMAP_SMARTREFLEX_CLASS3=y
+CONFIG_OMAP_RESET_CLOCKS=y
+# CONFIG_OMAP_MUX is not set
+CONFIG_OMAP_MCBSP=y
+CONFIG_OMAP_MBOX_FWK=m
+CONFIG_OMAP_MBOX_KFIFO_SIZE=256
+CONFIG_OMAP_IOMMU=y
+CONFIG_OMAP_IOMMU_DEBUG=m
+CONFIG_OMAP_32K_TIMER=y
+# CONFIG_OMAP3_L2_AUX_SECURE_SAVE_RESTORE is not set
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+# CONFIG_OMAP_PM_NONE is not set
+CONFIG_OMAP_PM_NOOP=y
+
+#
+# TI OMAP2/3/4 Specific Features
+#
+CONFIG_ARCH_OMAP2PLUS_TYPICAL=y
+# CONFIG_ARCH_OMAP2 is not set
+CONFIG_ARCH_OMAP3=y
+# CONFIG_ARCH_OMAP4 is not set
+CONFIG_SOC_OMAP3430=y
+# CONFIG_SOC_OMAPTI816X is not set
+CONFIG_OMAP_PACKAGE_CBB=y
+
+#
+# OMAP Board Type
+#
+CONFIG_MACH_OMAP3_BEAGLE=y
+# CONFIG_MACH_DEVKIT8000 is not set
+# CONFIG_MACH_OMAP_LDP is not set
+# CONFIG_MACH_OMAP3530_LV_SOM is not set
+# CONFIG_MACH_OMAP3_TORPEDO is not set
+CONFIG_MACH_OVERO=y
+CONFIG_MACH_OMAP3EVM=y
+# CONFIG_MACH_OMAP3517EVM is not set
+# CONFIG_MACH_CRANEBOARD is not set
+# CONFIG_MACH_OMAP3_PANDORA is not set
+CONFIG_MACH_OMAP3_TOUCHBOOK=y
+# CONFIG_MACH_OMAP_3430SDP is not set
+# CONFIG_MACH_NOKIA_RM680 is not set
+# CONFIG_MACH_NOKIA_RX51 is not set
+CONFIG_MACH_OMAP_ZOOM2=y
+# CONFIG_MACH_OMAP_ZOOM3 is not set
+# CONFIG_MACH_CM_T35 is not set
+# CONFIG_MACH_CM_T3517 is not set
+# CONFIG_MACH_IGEP0020 is not set
+# CONFIG_MACH_IGEP0030 is not set
+# CONFIG_MACH_SBC3530 is not set
+# CONFIG_MACH_OMAP_3630SDP is not set
+# CONFIG_OMAP3_EMU is not set
+# CONFIG_OMAP3_SDRC_AC_TIMING is not set
+
+#
+# System MMU
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+CONFIG_ARM_THUMBEE=y
+# CONFIG_SWP_EMULATE is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_ARM_L1_CACHE_SHIFT_6=y
+CONFIG_ARM_L1_CACHE_SHIFT=6
+CONFIG_ARM_DMA_MEM_BUFFERABLE=y
+CONFIG_ARM_ERRATA_430973=y
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+# CONFIG_ARM_ERRATA_743622 is not set
+# CONFIG_ARM_ERRATA_754322 is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_HZ=128
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_COMPACTION=y
+CONFIG_MIGRATION=y
+# 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_NEED_PER_CPU_KM=y
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_LEDS=y
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+# CONFIG_SECCOMP is not set
+# CONFIG_CC_STACKPROTECTOR is not set
+# CONFIG_DEPRECATED_PARAM_STRUCT is not set
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=" debug "
+# CONFIG_CMDLINE_FORCE is not set
+# CONFIG_XIP_KERNEL is not set
+CONFIG_KEXEC=y
+CONFIG_ATAGS_PROC=y
+# CONFIG_CRASH_DUMP is not set
+# CONFIG_AUTO_ZRELADDR is not set
+
+#
+# CPU Power Management
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+CONFIG_CPU_FREQ_DEBUG=y
+CONFIG_CPU_FREQ_STAT=y
+CONFIG_CPU_FREQ_STAT_DETAILS=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_NEON=y
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+CONFIG_BINFMT_AOUT=m
+CONFIG_BINFMT_MISC=y
+
+#
+# Power management options
+#
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_PM_SLEEP=y
+CONFIG_PM_RUNTIME=y
+CONFIG_PM=y
+CONFIG_PM_DEBUG=y
+# CONFIG_PM_VERBOSE is not set
+# CONFIG_PM_ADVANCED_DEBUG is not set
+# CONFIG_PM_TEST_SUSPEND is not set
+CONFIG_CAN_PM_TRACE=y
+# CONFIG_APM_EMULATION is not set
+CONFIG_ARCH_HAS_OPP=y
+CONFIG_PM_OPP=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_XFRM_IPCOMP=m
+CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_ROUTE_CLASSID=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE_DEMUX=m
+CONFIG_NET_IPGRE=m
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_TUNNEL=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_LRO=y
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_BIC=m
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=m
+CONFIG_TCP_CONG_SCALABLE=m
+CONFIG_TCP_CONG_LP=m
+CONFIG_TCP_CONG_VENO=m
+CONFIG_TCP_CONG_YEAH=m
+CONFIG_TCP_CONG_ILLINOIS=m
+CONFIG_DEFAULT_CUBIC=y
+# CONFIG_DEFAULT_RENO is not set
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+CONFIG_IPV6=m
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_MIP6=m
+CONFIG_INET6_XFRM_TUNNEL=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
+CONFIG_IPV6_SIT=m
+# CONFIG_IPV6_SIT_6RD is not set
+CONFIG_IPV6_NDISC_NODETYPE=y
+CONFIG_IPV6_TUNNEL=m
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_MROUTE=y
+CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
+# CONFIG_IPV6_PIMSM_V2 is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETWORK_PHY_TIMESTAMPING=y
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_CONNTRACK_MARK=y
+CONFIG_NF_CONNTRACK_ZONES=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CONNTRACK_TIMESTAMP=y
+CONFIG_NF_CT_PROTO_DCCP=m
+CONFIG_NF_CT_PROTO_GRE=m
+CONFIG_NF_CT_PROTO_SCTP=m
+CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_BROADCAST=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+CONFIG_NF_CONNTRACK_SNMP=m
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_SANE=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NF_CT_NETLINK=m
+# CONFIG_NETFILTER_TPROXY is not set
+CONFIG_NETFILTER_XTABLES=m
+
+#
+# Xtables combined modules
+#
+CONFIG_NETFILTER_XT_MARK=m
+CONFIG_NETFILTER_XT_CONNMARK=m
+CONFIG_NETFILTER_XT_SET=m
+
+#
+# Xtables targets
+#
+CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_CT=m
+# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
+CONFIG_NETFILTER_XT_TARGET_HL=m
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
+# CONFIG_NETFILTER_XT_TARGET_LED is not set
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
+CONFIG_NETFILTER_XT_TARGET_RATEEST=m
+CONFIG_NETFILTER_XT_TARGET_TEE=m
+# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set
+
+#
+# Xtables matches
+#
+CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
+# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_CPU=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_HL=m
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
+CONFIG_NETFILTER_XT_MATCH_IPVS=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+# CONFIG_NETFILTER_XT_MATCH_OSF is not set
+CONFIG_NETFILTER_XT_MATCH_OWNER=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_RECENT=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_TIME=m
+CONFIG_NETFILTER_XT_MATCH_U32=m
+CONFIG_IP_SET=m
+CONFIG_IP_SET_MAX=256
+# CONFIG_IP_SET_BITMAP_IP is not set
+# CONFIG_IP_SET_BITMAP_IPMAC is not set
+# CONFIG_IP_SET_BITMAP_PORT is not set
+# CONFIG_IP_SET_HASH_IP is not set
+# CONFIG_IP_SET_HASH_IPPORT is not set
+# CONFIG_IP_SET_HASH_IPPORTIP is not set
+# CONFIG_IP_SET_HASH_IPPORTNET is not set
+# CONFIG_IP_SET_HASH_NET is not set
+# CONFIG_IP_SET_HASH_NETPORT is not set
+# CONFIG_IP_SET_LIST_SET is not set
+CONFIG_IP_VS=m
+CONFIG_IP_VS_IPV6=y
+CONFIG_IP_VS_DEBUG=y
+CONFIG_IP_VS_TAB_BITS=12
+
+#
+# IPVS transport protocol load balancing support
+#
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_AH_ESP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+# CONFIG_IP_VS_PROTO_SCTP is not set
+
+#
+# IPVS scheduler
+#
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+
+#
+# IPVS application helper
+#
+CONFIG_IP_VS_FTP=m
+CONFIG_IP_VS_NFCT=y
+CONFIG_IP_VS_PE_SIP=m
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV4=m
+CONFIG_NF_CONNTRACK_IPV4=m
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_NF_NAT=m
+CONFIG_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_NF_NAT_SNMP_BASIC=m
+CONFIG_NF_NAT_PROTO_DCCP=m
+CONFIG_NF_NAT_PROTO_GRE=m
+CONFIG_NF_NAT_PROTO_UDPLITE=m
+CONFIG_NF_NAT_PROTO_SCTP=m
+CONFIG_NF_NAT_FTP=m
+CONFIG_NF_NAT_IRC=m
+CONFIG_NF_NAT_TFTP=m
+CONFIG_NF_NAT_AMANDA=m
+CONFIG_NF_NAT_PPTP=m
+CONFIG_NF_NAT_H323=m
+CONFIG_NF_NAT_SIP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV6=m
+CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_MH=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_RAW=m
+# CONFIG_BRIDGE_NF_EBTABLES is not set
+CONFIG_IP_DCCP=m
+CONFIG_INET_DCCP_DIAG=m
+
+#
+# DCCP CCIDs Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP_CCID2_DEBUG is not set
+CONFIG_IP_DCCP_CCID3=y
+# CONFIG_IP_DCCP_CCID3_DEBUG is not set
+CONFIG_IP_DCCP_TFRC_LIB=y
+
+#
+# DCCP Kernel Hacking
+#
+# CONFIG_IP_DCCP_DEBUG is not set
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+# CONFIG_RDS is not set
+CONFIG_TIPC=m
+# CONFIG_TIPC_ADVANCED is not set
+# CONFIG_TIPC_DEBUG is not set
+CONFIG_ATM=m
+CONFIG_ATM_CLIP=m
+# CONFIG_ATM_CLIP_NO_ICMP is not set
+CONFIG_ATM_LANE=m
+CONFIG_ATM_MPOA=m
+CONFIG_ATM_BR2684=m
+# CONFIG_ATM_BR2684_IPFILTER is not set
+CONFIG_L2TP=m
+CONFIG_L2TP_DEBUGFS=m
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=m
+CONFIG_L2TP_ETH=m
+CONFIG_STP=m
+CONFIG_GARP=m
+CONFIG_BRIDGE=m
+CONFIG_BRIDGE_IGMP_SNOOPING=y
+# CONFIG_NET_DSA is not set
+CONFIG_VLAN_8021Q=m
+CONFIG_VLAN_8021Q_GVRP=y
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# 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=m
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+CONFIG_NET_SCHED=y
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_ATM=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_MULTIQ=m
+CONFIG_NET_SCH_RED=m
+# CONFIG_NET_SCH_SFB is not set
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_DRR=m
+CONFIG_NET_SCH_MQPRIO=m
+CONFIG_NET_SCH_CHOKE=m
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_PERF=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_FLOW=m
+CONFIG_NET_CLS_CGROUP=m
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_CLS_ACT is not set
+CONFIG_NET_CLS_IND=y
+CONFIG_NET_SCH_FIFO=y
+# CONFIG_DCB is not set
+CONFIG_DNS_RESOLVER=y
+# CONFIG_BATMAN_ADV is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+CONFIG_CAN=m
+CONFIG_CAN_RAW=m
+CONFIG_CAN_BCM=m
+
+#
+# CAN Device Drivers
+#
+CONFIG_CAN_VCAN=m
+CONFIG_CAN_SLCAN=m
+# CONFIG_CAN_DEV is not set
+# CONFIG_CAN_DEBUG_DEVICES is not set
+CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRCOMM=m
+CONFIG_IRDA_ULTRA=y
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+CONFIG_IRDA_DEBUG=y
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+CONFIG_IRTTY_SIR=m
+
+#
+# Dongle support
+#
+CONFIG_DONGLE=y
+CONFIG_ESI_DONGLE=m
+CONFIG_ACTISYS_DONGLE=m
+CONFIG_TEKRAM_DONGLE=m
+CONFIG_TOIM3232_DONGLE=m
+CONFIG_LITELINK_DONGLE=m
+CONFIG_MA600_DONGLE=m
+CONFIG_GIRBIL_DONGLE=m
+CONFIG_MCP2120_DONGLE=m
+CONFIG_OLD_BELKIN_DONGLE=m
+# CONFIG_ACT200L_DONGLE is not set
+CONFIG_KINGSUN_DONGLE=m
+CONFIG_KSDAZZLE_DONGLE=m
+CONFIG_KS959_DONGLE=m
+
+#
+# FIR device drivers
+#
+CONFIG_USB_IRDA=m
+CONFIG_SIGMATEL_FIR=m
+CONFIG_MCS_FIR=m
+CONFIG_BT=m
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=m
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIBTUSB=m
+CONFIG_BT_HCIBTSDIO=m
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIUART_ATH3K=y
+CONFIG_BT_HCIUART_LL=y
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_BT_HCIBFUSB=m
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_BT_MRVL is not set
+CONFIG_BT_ATH3K=m
+CONFIG_BT_WILINK=m
+CONFIG_AF_RXRPC=m
+# CONFIG_AF_RXRPC_DEBUG is not set
+# CONFIG_RXKAD is not set
+CONFIG_FIB_RULES=y
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_WEXT_CORE=y
+CONFIG_WEXT_PROC=y
+CONFIG_WEXT_SPY=y
+CONFIG_WEXT_PRIV=y
+CONFIG_CFG80211=m
+CONFIG_NL80211_TESTMODE=y
+# 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_CRYPT_WEP=m
+CONFIG_LIB80211_CRYPT_CCMP=m
+CONFIG_LIB80211_CRYPT_TKIP=m
+# CONFIG_LIB80211_DEBUG is not set
+CONFIG_MAC80211=m
+CONFIG_MAC80211_HAS_RC=y
+CONFIG_MAC80211_RC_PID=y
+# CONFIG_MAC80211_RC_MINSTREL is not set
+CONFIG_MAC80211_RC_DEFAULT_PID=y
+CONFIG_MAC80211_RC_DEFAULT="pid"
+# CONFIG_MAC80211_MESH is not set
+CONFIG_MAC80211_LEDS=y
+# CONFIG_MAC80211_DEBUGFS is not set
+# CONFIG_MAC80211_DEBUG_MENU is not set
+CONFIG_WIMAX=m
+CONFIG_WIMAX_DEBUG_LEVEL=8
+CONFIG_RFKILL=m
+CONFIG_RFKILL_LEDS=y
+CONFIG_RFKILL_INPUT=y
+CONFIG_NET_9P=m
+# CONFIG_NET_9P_DEBUG is not set
+# CONFIG_CAIF is not set
+CONFIG_CEPH_LIB=m
+# CONFIG_CEPH_LIB_PRETTYDEBUG is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH=""
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# 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_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+# 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=m
+# CONFIG_MTD_OOPS is not set
+CONFIG_MTD_SWAP=m
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE 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_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# 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_NAND_ECC_BCH is not set
+# CONFIG_MTD_SM_COMMON is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_GPIO is not set
+CONFIG_MTD_NAND_OMAP2=y
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+CONFIG_MTD_NAND_PLATFORM=y
+# 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 is not set
+# 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=m
+
+#
+# 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=16384
+# CONFIG_BLK_DEV_XIP is not set
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MG_DISK is not set
+# CONFIG_BLK_DEV_RBD is not set
+# CONFIG_SENSORS_LIS3LV02D 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=m
+# CONFIG_SENSORS_BH1770 is not set
+# CONFIG_SENSORS_APDS990X is not set
+CONFIG_HMC6352=m
+# CONFIG_DS1682 is not set
+# CONFIG_TI_DAC7512 is not set
+CONFIG_BMP085=m
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+CONFIG_EEPROM_AT24=m
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+CONFIG_EEPROM_93CX6=y
+CONFIG_IWMC3200TOP=m
+# CONFIG_IWMC3200TOP_DEBUG is not set
+# CONFIG_IWMC3200TOP_DEBUGFS is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+CONFIG_TI_ST=m
+# CONFIG_SENSORS_LIS3_SPI is not set
+# CONFIG_SENSORS_LIS3_I2C is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+CONFIG_RAID_ATTRS=m
+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=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=m
+CONFIG_SCSI_MULTI_LUN=y
+# 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=m
+# 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=m
+CONFIG_ISCSI_BOOT_SYSFS=m
+# 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 is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID456=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_FAULTY=m
+CONFIG_BLK_DEV_DM=m
+# CONFIG_DM_DEBUG is not set
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_RAID=m
+# CONFIG_DM_LOG_USERSPACE is not set
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+# CONFIG_DM_MULTIPATH_QL is not set
+# CONFIG_DM_MULTIPATH_ST is not set
+CONFIG_DM_DELAY=m
+# CONFIG_DM_UEVENT is not set
+CONFIG_DM_FLAKEY=m
+CONFIG_TARGET_CORE=m
+CONFIG_TCM_IBLOCK=m
+CONFIG_TCM_FILEIO=m
+CONFIG_TCM_PSCSI=m
+CONFIG_LOOPBACK_TARGET=m
+# CONFIG_LOOPBACK_TARGET_CDB_DEBUG is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+CONFIG_MACVLAN=m
+CONFIG_MACVTAP=m
+CONFIG_EQUALIZER=m
+CONFIG_TUN=m
+CONFIG_VETH=m
+CONFIG_MII=y
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+CONFIG_BCM63XX_PHY=m
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+CONFIG_MICREL_PHY=m
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_AX88796 is not set
+CONFIG_SMC91X=y
+# CONFIG_TI_DAVINCI_EMAC is not set
+CONFIG_TI_DAVINCI_MDIO=m
+CONFIG_TI_DAVINCI_CPDMA=m
+# CONFIG_DM9000 is not set
+CONFIG_ENC28J60=y
+# CONFIG_ENC28J60_WRITEVERIFY is not set
+# CONFIG_ETHOC is not set
+CONFIG_SMC911X=y
+CONFIG_SMSC911X=y
+# CONFIG_SMSC911X_ARCH_HOOKS 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_KS8842=m
+CONFIG_KS8851=y
+# CONFIG_KS8851_MLL is not set
+# CONFIG_FTMAC100 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+CONFIG_WLAN=y
+# CONFIG_LIBERTAS_THINFIRM is not set
+CONFIG_AT76C50X_USB=m
+CONFIG_USB_ZD1201=m
+CONFIG_USB_NET_RNDIS_WLAN=m
+CONFIG_RTL8187=m
+CONFIG_RTL8187_LEDS=y
+# CONFIG_MAC80211_HWSIM is not set
+# CONFIG_ATH_COMMON is not set
+CONFIG_B43=m
+# CONFIG_B43_SDIO is not set
+CONFIG_B43_PIO=y
+CONFIG_B43_PHY_N=y
+CONFIG_B43_PHY_LP=y
+CONFIG_B43_LEDS=y
+CONFIG_B43_HWRNG=y
+# CONFIG_B43_DEBUG is not set
+# CONFIG_B43LEGACY is not set
+CONFIG_HOSTAP=m
+CONFIG_HOSTAP_FIRMWARE=y
+CONFIG_HOSTAP_FIRMWARE_NVRAM=y
+# CONFIG_IWM is not set
+CONFIG_LIBERTAS=m
+CONFIG_LIBERTAS_USB=m
+# CONFIG_LIBERTAS_SDIO is not set
+# CONFIG_LIBERTAS_SPI is not set
+# CONFIG_LIBERTAS_DEBUG is not set
+# CONFIG_LIBERTAS_MESH is not set
+CONFIG_P54_COMMON=m
+CONFIG_P54_USB=m
+# CONFIG_P54_SPI is not set
+CONFIG_P54_LEDS=y
+CONFIG_RT2X00=m
+CONFIG_RT2500USB=m
+CONFIG_RT73USB=m
+# CONFIG_RT2800USB is not set
+CONFIG_RT2X00_LIB_USB=m
+CONFIG_RT2X00_LIB=m
+CONFIG_RT2X00_LIB_FIRMWARE=y
+CONFIG_RT2X00_LIB_CRYPTO=y
+CONFIG_RT2X00_LIB_LEDS=y
+# CONFIG_RT2X00_DEBUG is not set
+CONFIG_RTL8192CU=m
+CONFIG_RTLWIFI=m
+CONFIG_RTL8192C_COMMON=m
+CONFIG_WL1251=m
+CONFIG_WL1251_SPI=m
+CONFIG_WL1251_SDIO=m
+CONFIG_WL12XX_MENU=m
+CONFIG_WL12XX=m
+CONFIG_WL12XX_HT=y
+CONFIG_WL12XX_SPI=m
+CONFIG_WL12XX_SDIO=m
+# CONFIG_WL12XX_SDIO_TEST is not set
+CONFIG_WL12XX_PLATFORM_DATA=y
+CONFIG_ZD1211RW=m
+# CONFIG_ZD1211RW_DEBUG is not set
+
+#
+# WiMAX Wireless Broadband devices
+#
+CONFIG_WIMAX_I2400M=m
+CONFIG_WIMAX_I2400M_USB=m
+CONFIG_WIMAX_I2400M_SDIO=m
+CONFIG_WIMAX_IWMC3200_SDIO=y
+CONFIG_WIMAX_I2400M_DEBUG_LEVEL=8
+
+#
+# USB Network Adapters
+#
+CONFIG_USB_CATC=y
+CONFIG_USB_KAWETH=y
+CONFIG_USB_PEGASUS=y
+CONFIG_USB_RTL8150=y
+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_CDC_NCM=m
+CONFIG_USB_NET_DM9601=y
+CONFIG_USB_NET_SMSC75XX=m
+CONFIG_USB_NET_SMSC95XX=y
+CONFIG_USB_NET_GL620A=y
+CONFIG_USB_NET_NET1080=y
+CONFIG_USB_NET_PLUSB=y
+CONFIG_USB_NET_MCS7830=y
+CONFIG_USB_NET_RNDIS_HOST=y
+CONFIG_USB_NET_CDC_SUBSET=y
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_KC2190=y
+CONFIG_USB_NET_ZAURUS=y
+CONFIG_USB_NET_CX82310_ETH=m
+CONFIG_USB_HSO=m
+CONFIG_USB_NET_INT51X1=m
+CONFIG_USB_IPHETH=m
+CONFIG_USB_SIERRA_NET=m
+CONFIG_USB_VL600=m
+# CONFIG_WAN is not set
+CONFIG_ATM_DRIVERS=y
+# CONFIG_ATM_DUMMY is not set
+# CONFIG_ATM_TCP is not set
+
+#
+# CAIF transport drivers
+#
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_PPTP=m
+# CONFIG_PPPOATM is not set
+CONFIG_PPPOL2TP=m
+# CONFIG_SLIP is not set
+CONFIG_SLHC=m
+CONFIG_NETCONSOLE=m
+CONFIG_NETCONSOLE_DYNAMIC=y
+CONFIG_NETPOLL=y
+CONFIG_NETPOLL_TRAP=y
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+CONFIG_INPUT_FF_MEMLESS=y
+CONFIG_INPUT_POLLDEV=y
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+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=y
+# CONFIG_KEYBOARD_ADP5588 is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_QT1070=m
+CONFIG_KEYBOARD_QT2160=m
+# CONFIG_KEYBOARD_LKKBD is not set
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_KEYBOARD_TCA6416 is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_LM8323 is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+CONFIG_KEYBOARD_MCS=m
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_TWL4030 is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_ELANTECH is not set
+# CONFIG_MOUSE_PS2_SENTELIC is not set
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_BCM5974 is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_MOUSE_GPIO is not set
+# CONFIG_MOUSE_SYNAPTICS_I2C is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_AD714X=m
+CONFIG_INPUT_AD714X_I2C=m
+CONFIG_INPUT_AD714X_SPI=m
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_CM109 is not set
+CONFIG_INPUT_TWL4030_PWRBUTTON=y
+CONFIG_INPUT_TWL4030_VIBRA=m
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_PCF8574=m
+CONFIG_INPUT_PWM_BEEPER=m
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+CONFIG_INPUT_ADXL34X=m
+CONFIG_INPUT_ADXL34X_I2C=m
+CONFIG_INPUT_ADXL34X_SPI=m
+CONFIG_INPUT_CMA3000=m
+CONFIG_INPUT_CMA3000_I2C=m
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_ALTERA_PS2 is not set
+# CONFIG_SERIO_PS2MULT is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_N_GSM=m
+CONFIG_DEVKMEM=y
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# 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_OMAP=y
+CONFIG_SERIAL_OMAP_CONSOLE=y
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+CONFIG_SERIAL_IFX6X60=m
+CONFIG_TTY_PRINTK=y
+# CONFIG_HVC_DCC 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=m
+
+#
+# Multiplexer I2C Chip support
+#
+CONFIG_I2C_MUX_GPIO=m
+# CONFIG_I2C_MUX_PCA9541 is not set
+# CONFIG_I2C_MUX_PCA954x is not set
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_ALGOBIT=m
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_DESIGNWARE is not set
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_PXA_PCI is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+CONFIG_I2C_DIOLAN_U2C=m
+# 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_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_ALTERA is not set
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
+# CONFIG_SPI_OC_TINY is not set
+CONFIG_SPI_OMAP24XX=y
+# CONFIG_SPI_PXA2XX_PCI is not set
+# CONFIG_SPI_XILINX is not set
+# CONFIG_SPI_DESIGNWARE is not set
+
+#
+# SPI Protocol Masters
+#
+CONFIG_SPI_SPIDEV=y
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+
+#
+# PPS generators support
+#
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_MAX730X=m
+
+#
+# Memory mapped GPIO expanders:
+#
+# CONFIG_GPIO_BASIC_MMIO is not set
+# CONFIG_GPIO_IT8761E is not set
+
+#
+# I2C GPIO expanders:
+#
+CONFIG_GPIO_MAX7300=m
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_SX150X is not set
+CONFIG_GPIO_TWL4030=y
+CONFIG_GPIO_ADP5588=m
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+# CONFIG_GPIO_74X164 is not set
+
+#
+# AC97 GPIO expanders:
+#
+
+#
+# MODULbus GPIO expanders:
+#
+# CONFIG_W1 is not set
+CONFIG_POWER_SUPPLY=m
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+CONFIG_TEST_POWER=m
+# CONFIG_BATTERY_DS2782 is not set
+# CONFIG_BATTERY_BQ20Z75 is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_BATTERY_MAX17040 is not set
+CONFIG_BATTERY_MAX17042=m
+CONFIG_CHARGER_ISP1704=m
+CONFIG_CHARGER_TWL4030=m
+CONFIG_CHARGER_GPIO=m
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADCXX is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+CONFIG_SENSORS_ADT7411=m
+# CONFIG_SENSORS_ADT7462 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7475 is not set
+CONFIG_SENSORS_ASC7621=m
+# CONFIG_SENSORS_ATXP1 is not set
+CONFIG_SENSORS_DS620=m
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_G760A is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+CONFIG_SENSORS_GPIO_FAN=m
+# CONFIG_SENSORS_IT87 is not set
+CONFIG_SENSORS_JC42=m
+# CONFIG_SENSORS_LINEAGE is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM73 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LTC4151 is not set
+# CONFIG_SENSORS_LTC4215 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LTC4261 is not set
+# CONFIG_SENSORS_LM95241 is not set
+# CONFIG_SENSORS_MAX1111 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6639 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_PMBUS is not set
+# CONFIG_SENSORS_SHT15 is not set
+# CONFIG_SENSORS_SHT21 is not set
+CONFIG_SENSORS_SMM665=m
+# CONFIG_SENSORS_DME1737 is not set
+CONFIG_SENSORS_EMC1403=m
+CONFIG_SENSORS_EMC2103=m
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SCH5627 is not set
+# CONFIG_SENSORS_ADS1015 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+CONFIG_SENSORS_ADS7871=m
+CONFIG_SENSORS_AMC6821=m
+# CONFIG_SENSORS_THMC50 is not set
+CONFIG_SENSORS_TMP102=m
+# CONFIG_SENSORS_TMP401 is not set
+# CONFIG_SENSORS_TMP421 is not set
+CONFIG_SENSORS_TWL4030_MADC=m
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83795 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+CONFIG_THERMAL=y
+CONFIG_THERMAL_HWMON=y
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+# CONFIG_TWL4030_WATCHDOG is not set
+# CONFIG_MAX63XX_WATCHDOG is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB=y
+CONFIG_SSB_BLOCKIO=y
+CONFIG_SSB_SDIOHOST_POSSIBLE=y
+# CONFIG_SSB_SDIOHOST is not set
+# CONFIG_SSB_SILENT is not set
+# CONFIG_SSB_DEBUG is not set
+CONFIG_MFD_SUPPORT=y
+CONFIG_MFD_CORE=y
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_HTC_I2CPLD is not set
+CONFIG_TPS6105X=m
+# CONFIG_TPS65010 is not set
+CONFIG_TPS6507X=m
+CONFIG_TWL4030_CORE=y
+CONFIG_TWL4030_MADC=m
+CONFIG_TWL4030_POWER=y
+CONFIG_TWL4030_CODEC=y
+CONFIG_TWL4030_POWEROFF=y
+CONFIG_TWL6030_PWM=m
+# CONFIG_MFD_STMPE is not set
+# CONFIG_MFD_TC3589X is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_MAX8997 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_MFD_TPS6586X=y
+CONFIG_MFD_WL1273_CORE=m
+CONFIG_MFD_OMAP_USB_HOST=y
+CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_DEBUG is not set
+CONFIG_REGULATOR_DUMMY=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+# CONFIG_REGULATOR_MAX8649 is not set
+# CONFIG_REGULATOR_MAX8660 is not set
+# CONFIG_REGULATOR_MAX8952 is not set
+CONFIG_REGULATOR_TWL4030=y
+# CONFIG_REGULATOR_LP3971 is not set
+# CONFIG_REGULATOR_LP3972 is not set
+CONFIG_REGULATOR_TPS6105X=m
+# CONFIG_REGULATOR_TPS65023 is not set
+# CONFIG_REGULATOR_TPS6507X is not set
+# CONFIG_REGULATOR_ISL6271A is not set
+# CONFIG_REGULATOR_AD5398 is not set
+CONFIG_REGULATOR_TPS6586X=m
+CONFIG_REGULATOR_TPS6524X=m
+CONFIG_MEDIA_SUPPORT=y
+
+#
+# Multimedia core support
+#
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_COMMON=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_DVB_CORE=m
+CONFIG_VIDEO_MEDIA=m
+
+#
+# Multimedia drivers
+#
+CONFIG_RC_CORE=m
+CONFIG_LIRC=m
+CONFIG_RC_MAP=m
+CONFIG_IR_NEC_DECODER=m
+CONFIG_IR_RC5_DECODER=m
+CONFIG_IR_RC6_DECODER=m
+CONFIG_IR_JVC_DECODER=m
+CONFIG_IR_SONY_DECODER=m
+CONFIG_IR_RC5_SZ_DECODER=m
+CONFIG_IR_LIRC_CODEC=m
+# CONFIG_IR_IMON is not set
+# CONFIG_IR_MCEUSB is not set
+# CONFIG_IR_STREAMZAP is not set
+CONFIG_RC_LOOPBACK=m
+CONFIG_MEDIA_ATTACH=y
+CONFIG_MEDIA_TUNER=m
+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_VIDEO_V4L2=y
+CONFIG_VIDEOBUF_GEN=y
+CONFIG_VIDEOBUF_VMALLOC=m
+CONFIG_VIDEOBUF_DMA_CONTIG=y
+CONFIG_VIDEOBUF_DVB=m
+CONFIG_VIDEO_TVEEPROM=m
+CONFIG_VIDEO_TUNER=m
+CONFIG_V4L2_MEM2MEM_DEV=m
+CONFIG_VIDEOBUF2_CORE=m
+CONFIG_VIDEOBUF2_MEMOPS=m
+CONFIG_VIDEOBUF2_VMALLOC=m
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
+# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set
+CONFIG_VIDEO_IR_I2C=m
+
+#
+# Encoders/decoders and other helper chips
+#
+
+#
+# Audio decoders
+#
+# CONFIG_VIDEO_TVAUDIO is not set
+# CONFIG_VIDEO_TDA7432 is not set
+# CONFIG_VIDEO_TDA9840 is not set
+# CONFIG_VIDEO_TEA6415C is not set
+# CONFIG_VIDEO_TEA6420 is not set
+CONFIG_VIDEO_MSP3400=m
+# CONFIG_VIDEO_CS5345 is not set
+CONFIG_VIDEO_CS53L32A=m
+# CONFIG_VIDEO_M52790 is not set
+# CONFIG_VIDEO_TLV320AIC23B is not set
+CONFIG_VIDEO_WM8775=m
+# CONFIG_VIDEO_WM8739 is not set
+# CONFIG_VIDEO_VP27SMPX is not set
+
+#
+# RDS decoders
+#
+# CONFIG_VIDEO_SAA6588 is not set
+
+#
+# Video decoders
+#
+CONFIG_VIDEO_ADV7180=m
+# CONFIG_VIDEO_BT819 is not set
+# CONFIG_VIDEO_BT856 is not set
+# CONFIG_VIDEO_BT866 is not set
+# CONFIG_VIDEO_KS0127 is not set
+# CONFIG_VIDEO_OV7670 is not set
+CONFIG_VIDEO_MT9V011=m
+# CONFIG_VIDEO_TCM825X is not set
+# CONFIG_VIDEO_SAA7110 is not set
+CONFIG_VIDEO_SAA711X=m
+# CONFIG_VIDEO_SAA717X is not set
+# CONFIG_VIDEO_SAA7191 is not set
+# CONFIG_VIDEO_TVP514X is not set
+# CONFIG_VIDEO_TVP5150 is not set
+# CONFIG_VIDEO_TVP7002 is not set
+# CONFIG_VIDEO_VPX3220 is not set
+
+#
+# Video and audio decoders
+#
+CONFIG_VIDEO_CX25840=m
+
+#
+# MPEG video encoders
+#
+CONFIG_VIDEO_CX2341X=m
+
+#
+# Video encoders
+#
+# CONFIG_VIDEO_SAA7127 is not set
+# CONFIG_VIDEO_SAA7185 is not set
+# CONFIG_VIDEO_ADV7170 is not set
+# CONFIG_VIDEO_ADV7175 is not set
+# CONFIG_VIDEO_THS7303 is not set
+# CONFIG_VIDEO_ADV7343 is not set
+# CONFIG_VIDEO_AK881X is not set
+
+#
+# Video improvement chips
+#
+# CONFIG_VIDEO_UPD64031A is not set
+# CONFIG_VIDEO_UPD64083 is not set
+CONFIG_VIDEO_VIVI=m
+CONFIG_VIDEO_VPFE_CAPTURE=y
+# CONFIG_VIDEO_DM6446_CCDC is not set
+CONFIG_VIDEO_OMAP2_VOUT=y
+# CONFIG_VIDEO_CPIA2 is not set
+CONFIG_VIDEO_TIMBERDALE=m
+# CONFIG_VIDEO_AU0828 is not set
+CONFIG_VIDEO_SR030PC30=m
+CONFIG_VIDEO_NOON010PC30=m
+CONFIG_VIDEO_OMAP3=y
+# CONFIG_VIDEO_OMAP3_DEBUG is not set
+# CONFIG_SOC_CAMERA is not set
+CONFIG_V4L_USB_DRIVERS=y
+CONFIG_USB_VIDEO_CLASS=m
+CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
+CONFIG_USB_GSPCA=m
+CONFIG_USB_M5602=m
+CONFIG_USB_STV06XX=m
+# CONFIG_USB_GL860 is not set
+CONFIG_USB_GSPCA_BENQ=m
+CONFIG_USB_GSPCA_CONEX=m
+CONFIG_USB_GSPCA_CPIA1=m
+CONFIG_USB_GSPCA_ETOMS=m
+CONFIG_USB_GSPCA_FINEPIX=m
+# CONFIG_USB_GSPCA_JEILINJ is not set
+CONFIG_USB_GSPCA_KONICA=m
+CONFIG_USB_GSPCA_MARS=m
+# CONFIG_USB_GSPCA_MR97310A is not set
+CONFIG_USB_GSPCA_NW80X=m
+CONFIG_USB_GSPCA_OV519=m
+CONFIG_USB_GSPCA_OV534=m
+CONFIG_USB_GSPCA_OV534_9=m
+CONFIG_USB_GSPCA_PAC207=m
+# CONFIG_USB_GSPCA_PAC7302 is not set
+CONFIG_USB_GSPCA_PAC7311=m
+CONFIG_USB_GSPCA_SN9C2028=m
+# CONFIG_USB_GSPCA_SN9C20X is not set
+CONFIG_USB_GSPCA_SONIXB=m
+CONFIG_USB_GSPCA_SONIXJ=m
+CONFIG_USB_GSPCA_SPCA500=m
+CONFIG_USB_GSPCA_SPCA501=m
+CONFIG_USB_GSPCA_SPCA505=m
+CONFIG_USB_GSPCA_SPCA506=m
+CONFIG_USB_GSPCA_SPCA508=m
+CONFIG_USB_GSPCA_SPCA561=m
+CONFIG_USB_GSPCA_SPCA1528=m
+# CONFIG_USB_GSPCA_SQ905 is not set
+# CONFIG_USB_GSPCA_SQ905C is not set
+CONFIG_USB_GSPCA_SQ930X=m
+CONFIG_USB_GSPCA_STK014=m
+# CONFIG_USB_GSPCA_STV0680 is not set
+CONFIG_USB_GSPCA_SUNPLUS=m
+CONFIG_USB_GSPCA_T613=m
+CONFIG_USB_GSPCA_TV8532=m
+CONFIG_USB_GSPCA_VC032X=m
+CONFIG_USB_GSPCA_VICAM=m
+CONFIG_USB_GSPCA_XIRLINK_CIT=m
+CONFIG_USB_GSPCA_ZC3XX=m
+CONFIG_VIDEO_PVRUSB2=m
+CONFIG_VIDEO_PVRUSB2_SYSFS=y
+CONFIG_VIDEO_PVRUSB2_DVB=y
+# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set
+CONFIG_VIDEO_HDPVR=m
+CONFIG_VIDEO_EM28XX=m
+CONFIG_VIDEO_EM28XX_ALSA=m
+CONFIG_VIDEO_EM28XX_DVB=m
+CONFIG_VIDEO_TLG2300=m
+CONFIG_VIDEO_CX231XX=m
+CONFIG_VIDEO_CX231XX_RC=y
+# CONFIG_VIDEO_CX231XX_ALSA is not set
+CONFIG_VIDEO_CX231XX_DVB=m
+CONFIG_VIDEO_USBVISION=m
+CONFIG_USB_ET61X251=m
+CONFIG_USB_SN9C102=m
+CONFIG_USB_PWC=m
+# CONFIG_USB_PWC_DEBUG is not set
+CONFIG_USB_PWC_INPUT_EVDEV=y
+CONFIG_USB_ZR364XX=m
+CONFIG_USB_STKWEBCAM=m
+CONFIG_USB_S2255=m
+CONFIG_V4L_MEM2MEM_DRIVERS=y
+CONFIG_VIDEO_MEM2MEM_TESTDEV=m
+CONFIG_RADIO_ADAPTERS=y
+# CONFIG_I2C_SI4713 is not set
+# CONFIG_RADIO_SI4713 is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_RADIO_SI470X is not set
+# CONFIG_USB_MR800 is not set
+# CONFIG_RADIO_TEA5764 is not set
+CONFIG_RADIO_SAA7706H=m
+# CONFIG_RADIO_TEF6862 is not set
+CONFIG_RADIO_WL1273=m
+
+#
+# Texas Instruments WL128x FM driver (ST based)
+#
+CONFIG_RADIO_WL128X=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=m
+# CONFIG_DVB_USB_DEBUG is not set
+CONFIG_DVB_USB_A800=m
+CONFIG_DVB_USB_DIBUSB_MB=m
+# CONFIG_DVB_USB_DIBUSB_MB_FAULTY is not set
+CONFIG_DVB_USB_DIBUSB_MC=m
+CONFIG_DVB_USB_DIB0700=m
+CONFIG_DVB_USB_UMT_010=m
+CONFIG_DVB_USB_CXUSB=m
+CONFIG_DVB_USB_M920X=m
+CONFIG_DVB_USB_GL861=m
+CONFIG_DVB_USB_AU6610=m
+CONFIG_DVB_USB_DIGITV=m
+CONFIG_DVB_USB_VP7045=m
+CONFIG_DVB_USB_VP702X=m
+CONFIG_DVB_USB_GP8PSK=m
+CONFIG_DVB_USB_NOVA_T_USB2=m
+CONFIG_DVB_USB_TTUSB2=m
+CONFIG_DVB_USB_DTT200U=m
+CONFIG_DVB_USB_OPERA1=m
+CONFIG_DVB_USB_AF9005=m
+CONFIG_DVB_USB_AF9005_REMOTE=m
+CONFIG_DVB_USB_DW2102=m
+CONFIG_DVB_USB_CINERGY_T2=m
+CONFIG_DVB_USB_ANYSEE=m
+CONFIG_DVB_USB_DTV5100=m
+CONFIG_DVB_USB_AF9015=m
+# CONFIG_DVB_USB_CE6230 is not set
+# CONFIG_DVB_USB_FRIIO is not set
+# CONFIG_DVB_USB_EC168 is not set
+CONFIG_DVB_USB_AZ6027=m
+CONFIG_DVB_USB_LME2510=m
+CONFIG_DVB_USB_TECHNISAT_USB2=m
+# CONFIG_SMS_SIANO_MDTV is not set
+
+#
+# Supported FlexCopII (B2C2) Adapters
+#
+CONFIG_DVB_B2C2_FLEXCOP=m
+CONFIG_DVB_B2C2_FLEXCOP_USB=m
+# CONFIG_DVB_B2C2_FLEXCOP_DEBUG is not set
+
+#
+# Supported DVB Frontends
+#
+# CONFIG_DVB_FE_CUSTOMISE is not set
+
+#
+# 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_CX24123=m
+CONFIG_DVB_MT312=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_TDA10086=m
+CONFIG_DVB_TUNER_ITD1000=m
+CONFIG_DVB_TUNER_CX24113=m
+CONFIG_DVB_TDA826X=m
+CONFIG_DVB_CX24116=m
+CONFIG_DVB_SI21XX=m
+CONFIG_DVB_DS3000=m
+
+#
+# DVB-T (terrestrial) frontends
+#
+CONFIG_DVB_CX22702=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
+
+#
+# DVB-C (cable) frontends
+#
+CONFIG_DVB_TDA10023=m
+CONFIG_DVB_STV0297=m
+
+#
+# ATSC (North American/Korean Terrestrial/Cable DTV) frontends
+#
+CONFIG_DVB_NXT200X=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
+CONFIG_DVB_MB86A20S=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_ISL6421=m
+CONFIG_DVB_LGS8GXX=m
+CONFIG_DVB_ATBM8830=m
+CONFIG_DVB_IX2505V=m
+
+#
+# Tools to develop new frontends
+#
+# CONFIG_DVB_DUMMY_FE is not set
+
+#
+# Graphics support
+#
+CONFIG_DRM=m
+# 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=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+CONFIG_FB_SYS_FILLRECT=m
+CONFIG_FB_SYS_COPYAREA=m
+CONFIG_FB_SYS_IMAGEBLIT=m
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+CONFIG_FB_SYS_FOPS=m
+# CONFIG_FB_WMT_GE_ROPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_TMIO is not set
+CONFIG_FB_UDL=m
+# 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_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_OMAP2_VRAM=y
+CONFIG_OMAP2_VRFB=y
+CONFIG_OMAP2_DSS=y
+CONFIG_OMAP2_VRAM_SIZE=14
+CONFIG_OMAP2_DSS_DEBUG_SUPPORT=y
+# CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS is not set
+CONFIG_OMAP2_DSS_DPI=y
+# CONFIG_OMAP2_DSS_RFBI is not set
+CONFIG_OMAP2_DSS_VENC=y
+# CONFIG_OMAP2_DSS_SDI is not set
+CONFIG_OMAP2_DSS_DSI=y
+CONFIG_OMAP2_DSS_USE_DSI_PLL=y
+# CONFIG_OMAP2_DSS_FAKE_VSYNC is not set
+CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=0
+CONFIG_FB_OMAP2=y
+CONFIG_FB_OMAP2_DEBUG_SUPPORT=y
+CONFIG_FB_OMAP2_NUM_FBS=2
+
+#
+# OMAP2/3 Display Device Drivers
+#
+CONFIG_PANEL_GENERIC_DPI=y
+# CONFIG_PANEL_LGPHILIPS_LB035Q02 is not set
+CONFIG_PANEL_SHARP_LS037V7DW01=y
+CONFIG_PANEL_NEC_NL8048HL11_01B=y
+# CONFIG_PANEL_TAAL is not set
+CONFIG_PANEL_TPO_TD043MTEA1=m
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+
+#
+# Display device support
+#
+CONFIG_DISPLAY_SUPPORT=y
+
+#
+# Display hardware drivers
+#
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_SOUND=y
+CONFIG_SOUND_OSS_CORE=y
+CONFIG_SOUND_OSS_CORE_PRECLAIM=y
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_HWDEP=y
+CONFIG_SND_RAWMIDI=y
+CONFIG_SND_JACK=y
+CONFIG_SND_SEQUENCER=m
+# CONFIG_SND_SEQ_DUMMY 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_SEQUENCER_OSS=y
+CONFIG_SND_HRTIMER=m
+CONFIG_SND_SEQ_HRTIMER_DEFAULT=y
+CONFIG_SND_DYNAMIC_MINORS=y
+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=m
+# 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=m
+# CONFIG_SND_VIRMIDI is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+# CONFIG_SND_ARM is not set
+CONFIG_SND_SPI=y
+CONFIG_SND_USB=y
+CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_USB_UA101=m
+CONFIG_SND_USB_CAIAQ=m
+CONFIG_SND_USB_CAIAQ_INPUT=y
+CONFIG_SND_USB_6FIRE=m
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_CACHE_LZO=y
+CONFIG_SND_OMAP_SOC=y
+CONFIG_SND_OMAP_SOC_MCBSP=y
+CONFIG_SND_OMAP_SOC_OVERO=y
+CONFIG_SND_OMAP_SOC_OMAP3EVM=y
+CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE=y
+CONFIG_SND_OMAP_SOC_ZOOM2=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+# CONFIG_SND_SOC_ALL_CODECS is not set
+CONFIG_SND_SOC_TWL4030=y
+# 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=y
+CONFIG_HID_ACRUX=m
+# CONFIG_HID_ACRUX_FF is not set
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+# CONFIG_HID_CANDO is not set
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+# CONFIG_HID_PRODIKEYS is not set
+CONFIG_HID_CYPRESS=y
+# CONFIG_HID_DRAGONRISE is not set
+CONFIG_HID_EMS_FF=m
+# CONFIG_HID_ELECOM is not set
+CONFIG_HID_EZKEY=y
+CONFIG_HID_KEYTOUCH=m
+# CONFIG_HID_KYE is not set
+CONFIG_HID_UCLOGIC=m
+CONFIG_HID_WALTOP=m
+CONFIG_HID_GYRATION=y
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
+CONFIG_HID_LCPOWER=m
+CONFIG_HID_LOGITECH=y
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+# CONFIG_LOGIG940_FF is not set
+# CONFIG_LOGIWII_FF is not set
+CONFIG_HID_MAGICMOUSE=m
+CONFIG_HID_MICROSOFT=y
+# CONFIG_HID_MOSART is not set
+CONFIG_HID_MONTEREY=y
+CONFIG_HID_MULTITOUCH=m
+CONFIG_HID_NTRIG=y
+# CONFIG_HID_ORTEK is not set
+CONFIG_HID_PANTHERLORD=y
+# CONFIG_PANTHERLORD_FF is not set
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_PICOLCD=m
+CONFIG_HID_PICOLCD_FB=y
+CONFIG_HID_PICOLCD_BACKLIGHT=y
+CONFIG_HID_PICOLCD_LEDS=y
+CONFIG_HID_QUANTA=m
+CONFIG_HID_ROCCAT=m
+CONFIG_HID_ROCCAT_COMMON=m
+CONFIG_HID_ROCCAT_ARVO=m
+CONFIG_HID_ROCCAT_KONE=m
+CONFIG_HID_ROCCAT_KONEPLUS=m
+CONFIG_HID_ROCCAT_KOVAPLUS=m
+# CONFIG_HID_ROCCAT_PYRA is not set
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_STANTUM=m
+CONFIG_HID_SUNPLUS=y
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+CONFIG_HID_TOPSEED=y
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_WACOM 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=y
+
+#
+# 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=y
+# 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=y
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+CONFIG_USB_EHCI_TT_NEWSCHED=y
+CONFIG_USB_EHCI_HCD_OMAP=y
+# 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_U132_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
+CONFIG_USB_MUSB_HDRC=y
+# CONFIG_USB_MUSB_TUSB6010 is not set
+CONFIG_USB_MUSB_OMAP2PLUS=y
+# CONFIG_USB_MUSB_AM35X is not set
+# CONFIG_USB_MUSB_HOST is not set
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+CONFIG_USB_MUSB_OTG=y
+CONFIG_USB_GADGET_MUSB_HDRC=y
+CONFIG_USB_MUSB_HDRC_HCD=y
+# CONFIG_MUSB_PIO_ONLY is not set
+CONFIG_USB_INVENTRA_DMA=y
+# CONFIG_USB_TI_CPPI_DMA is not set
+# CONFIG_USB_MUSB_DEBUG is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+CONFIG_USB_WDM=m
+CONFIG_USB_TMC=m
+
+#
+# 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_REALTEK=m
+# 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_STORAGE_ENE_UB6250=m
+CONFIG_USB_UAS=m
+# 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=m
+CONFIG_USB_EZUSB=y
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_AIRCABLE=m
+CONFIG_USB_SERIAL_ARK3116=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_CH341=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+# CONFIG_USB_SERIAL_CP210X is not set
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_FUNSOFT=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_IUU=m
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+CONFIG_USB_SERIAL_KEYSPAN_MPR=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19=y
+CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_MOS7720=m
+CONFIG_USB_SERIAL_MOS7840=m
+CONFIG_USB_SERIAL_MOTOROLA=m
+CONFIG_USB_SERIAL_NAVMAN=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_OTI6858=m
+CONFIG_USB_SERIAL_QCAUX=m
+# CONFIG_USB_SERIAL_QUALCOMM is not set
+CONFIG_USB_SERIAL_SPCP8X5=m
+CONFIG_USB_SERIAL_HP4X=m
+CONFIG_USB_SERIAL_SAFE=m
+# CONFIG_USB_SERIAL_SAFE_PADDED is not set
+CONFIG_USB_SERIAL_SAMBA=m
+CONFIG_USB_SERIAL_SIEMENS_MPI=m
+CONFIG_USB_SERIAL_SIERRAWIRELESS=m
+# CONFIG_USB_SERIAL_SYMBOL is not set
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+# CONFIG_USB_SERIAL_OPTION is not set
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_SERIAL_OPTICON=m
+CONFIG_USB_SERIAL_VIVOPAY_SERIAL=m
+CONFIG_USB_SERIAL_ZIO=m
+CONFIG_USB_SERIAL_SSU100=m
+CONFIG_USB_SERIAL_DEBUG=m
+
+#
+# USB Miscellaneous drivers
+#
+CONFIG_USB_EMI62=m
+CONFIG_USB_EMI26=m
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+CONFIG_USB_LEGOTOWER=m
+CONFIG_USB_LCD=m
+CONFIG_USB_LED=m
+CONFIG_USB_CYPRESS_CY7C63=m
+CONFIG_USB_CYTHERM=m
+CONFIG_USB_IDMOUSE=m
+CONFIG_USB_FTDI_ELAN=m
+# CONFIG_USB_APPLEDISPLAY is not set
+CONFIG_USB_SISUSBVGA=m
+CONFIG_USB_SISUSBVGA_CON=y
+CONFIG_USB_LD=m
+CONFIG_USB_TRANCEVIBRATOR=m
+# CONFIG_USB_IOWARRIOR is not set
+CONFIG_USB_TEST=m
+# CONFIG_USB_ISIGHTFW is not set
+CONFIG_USB_YUREX=m
+CONFIG_USB_ATM=m
+CONFIG_USB_SPEEDTOUCH=m
+CONFIG_USB_CXACRU=m
+CONFIG_USB_UEAGLEATM=m
+CONFIG_USB_XUSBATM=m
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_DEBUG_FS=y
+CONFIG_USB_GADGET_VBUS_DRAW=480
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_FUSB300 is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_R8A66597 is not set
+# CONFIG_USB_GADGET_PXA_U2O is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_AUDIO is not set
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_ETH_EEM is not set
+CONFIG_USB_G_NCM=m
+# CONFIG_USB_GADGETFS is not set
+CONFIG_USB_FUNCTIONFS=m
+# CONFIG_USB_FUNCTIONFS_ETH is not set
+CONFIG_USB_FUNCTIONFS_RNDIS=y
+# CONFIG_USB_FUNCTIONFS_GENERIC is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_MASS_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+# CONFIG_USB_G_MULTI is not set
+CONFIG_USB_G_HID=m
+CONFIG_USB_G_DBGP=m
+# CONFIG_USB_G_DBGP_PRINTK is not set
+CONFIG_USB_G_DBGP_SERIAL=y
+CONFIG_USB_G_WEBCAM=m
+
+#
+# OTG and related infrastructure
+#
+CONFIG_USB_OTG_UTILS=y
+CONFIG_USB_GPIO_VBUS=y
+# CONFIG_ISP1301_OMAP is not set
+# CONFIG_USB_ULPI is not set
+CONFIG_TWL4030_USB=y
+CONFIG_TWL6030_USB=m
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_UNSAFE_RESUME=y
+# CONFIG_MMC_CLKGATE 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=y
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_OMAP is not set
+CONFIG_MMC_OMAP_HS=y
+CONFIG_MMC_SPI=m
+# CONFIG_MMC_DW is not set
+CONFIG_MMC_USHC=m
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_LM3530 is not set
+# CONFIG_LEDS_PCA9532 is not set
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_GPIO_PLATFORM=y
+# CONFIG_LEDS_LP3944 is not set
+CONFIG_LEDS_LP5521=m
+CONFIG_LEDS_LP5523=m
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_DAC124S085 is not set
+CONFIG_LEDS_PWM=m
+CONFIG_LEDS_REGULATOR=m
+# CONFIG_LEDS_BD2802 is not set
+# CONFIG_LEDS_LT3593 is not set
+CONFIG_LEDS_TRIGGERS=y
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGER_TIMER=m
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=m
+CONFIG_LEDS_TRIGGER_GPIO=m
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=m
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
+CONFIG_NFC_DEVICES=y
+CONFIG_PN544_NFC=m
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+CONFIG_RTC_DRV_DS1307=y
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_DS3232 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_ISL12022 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+CONFIG_RTC_DRV_BQ32K=m
+CONFIG_RTC_DRV_TWL4030=m
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_DMADEVICES is not set
+CONFIG_TIMB_DMA=m
+CONFIG_DMA_ENGINE=y
+# CONFIG_AUXDISPLAY is not set
+CONFIG_UIO=m
+CONFIG_UIO_PDRV=m
+CONFIG_UIO_PDRV_GENIRQ=m
+CONFIG_STAGING=y
+# CONFIG_STAGING_EXCLUDE_BUILD is not set
+# CONFIG_VIDEO_TM6000 is not set
+# CONFIG_USB_IP_COMMON is not set
+CONFIG_W35UND=m
+CONFIG_PRISM2_USB=m
+CONFIG_ECHO=m
+CONFIG_BRCM80211=m
+CONFIG_BRCMFMAC=y
+# CONFIG_BRCMDBG is not set
+CONFIG_RT2870=m
+# CONFIG_COMEDI is not set
+# CONFIG_ASUS_OLED is not set
+CONFIG_R8712U=m
+CONFIG_R8712_AP=y
+# CONFIG_TRANZPORT is not set
+# CONFIG_POHMELFS is not set
+# CONFIG_LINE6_USB is not set
+# CONFIG_USB_SERIAL_QUATECH2 is not set
+# CONFIG_USB_SERIAL_QUATECH_USB2 is not set
+# CONFIG_VT6656 is not set
+# CONFIG_IIO is not set
+CONFIG_XVMALLOC=y
+CONFIG_ZRAM=m
+# CONFIG_ZRAM_DEBUG is not set
+# CONFIG_FB_SM7XX is not set
+# CONFIG_LIRC_STAGING is not set
+# CONFIG_EASYCAP is not set
+# CONFIG_TIDSPBRIDGE is not set
+# CONFIG_MACH_OMAP3_WESTBRIDGE_AST_PNAND_HAL is not set
+CONFIG_MACH_NO_WESTBRIDGE=y
+# CONFIG_ATH6K_LEGACY is not set
+CONFIG_USB_ENESTORAGE=m
+CONFIG_BCM_WIMAX=m
+CONFIG_FT1000=m
+CONFIG_FT1000_USB=m
+
+#
+# Speakup console speech
+#
+# CONFIG_SPEAKUP is not set
+CONFIG_TOUCHSCREEN_CLEARPAD_TM1217=m
+CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=m
+
+#
+# Altera FPGA firmware download module
+#
+# CONFIG_ALTERA_STAPL is not set
+CONFIG_CLKDEV_LOOKUP=y
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_XATTR=y
+# CONFIG_EXT4_FS_POSIX_ACL is not set
+# CONFIG_EXT4_FS_SECURITY is not set
+# CONFIG_EXT4_DEBUG is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_JBD2=y
+# CONFIG_JBD2_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+CONFIG_REISERFS_PROC_INFO=y
+CONFIG_REISERFS_FS_XATTR=y
+# CONFIG_REISERFS_FS_POSIX_ACL is not set
+# CONFIG_REISERFS_FS_SECURITY is not set
+CONFIG_JFS_FS=m
+# CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_SECURITY is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_XFS_FS=m
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_POSIX_ACL is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_DEBUG is not set
+CONFIG_GFS2_FS=m
+# CONFIG_GFS2_FS_LOCKING_DLM is not set
+CONFIG_OCFS2_FS=m
+CONFIG_OCFS2_FS_O2CB=m
+CONFIG_OCFS2_FS_USERSPACE_CLUSTER=m
+CONFIG_OCFS2_FS_STATS=y
+CONFIG_OCFS2_DEBUG_MASKLOG=y
+# CONFIG_OCFS2_DEBUG_FS is not set
+CONFIG_BTRFS_FS=m
+# CONFIG_BTRFS_FS_POSIX_ACL is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_EXPORTFS=y
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_FANOTIFY=y
+CONFIG_QUOTA=y
+# CONFIG_QUOTA_NETLINK_INTERFACE is not set
+CONFIG_PRINT_QUOTA_WARNING=y
+# CONFIG_QUOTA_DEBUG is not set
+CONFIG_QUOTA_TREE=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+CONFIG_AUTOFS4_FS=m
+CONFIG_FUSE_FS=m
+# CONFIG_CUSE is not set
+CONFIG_GENERIC_ACL=y
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+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=m
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_CONFIGFS_FS=m
+CONFIG_MISC_FILESYSTEMS=y
+CONFIG_ADFS_FS=m
+# CONFIG_ADFS_FS_RW is not set
+CONFIG_AFFS_FS=m
+# CONFIG_ECRYPT_FS is not set
+CONFIG_UNION_FS=m
+CONFIG_UNION_FS_XATTR=y
+# CONFIG_UNION_FS_DEBUG is not set
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_BEFS_FS=m
+# CONFIG_BEFS_DEBUG is not set
+CONFIG_BFS_FS=m
+CONFIG_EFS_FS=m
+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=y
+CONFIG_JFFS2_FS_XATTR=y
+CONFIG_JFFS2_FS_POSIX_ACL=y
+CONFIG_JFFS2_FS_SECURITY=y
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_LZO=y
+CONFIG_JFFS2_RTIME=y
+CONFIG_JFFS2_RUBIN=y
+# CONFIG_JFFS2_CMODE_NONE is not set
+# CONFIG_JFFS2_CMODE_PRIORITY is not set
+# CONFIG_JFFS2_CMODE_SIZE is not set
+CONFIG_JFFS2_CMODE_FAVOURLZO=y
+CONFIG_UBIFS_FS=y
+CONFIG_UBIFS_FS_XATTR=y
+CONFIG_UBIFS_FS_ADVANCED_COMPR=y
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+# CONFIG_UBIFS_FS_DEBUG is not set
+CONFIG_LOGFS=m
+CONFIG_CRAMFS=m
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_XATTR is not set
+CONFIG_SQUASHFS_LZO=y
+CONFIG_SQUASHFS_XZ=y
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+CONFIG_VXFS_FS=m
+CONFIG_MINIX_FS=m
+CONFIG_OMFS_FS=m
+CONFIG_HPFS_FS=m
+CONFIG_QNX4FS_FS=m
+CONFIG_ROMFS_FS=m
+CONFIG_ROMFS_BACKED_BY_BLOCK=y
+# CONFIG_ROMFS_BACKED_BY_MTD is not set
+# CONFIG_ROMFS_BACKED_BY_BOTH is not set
+CONFIG_ROMFS_ON_BLOCK=y
+CONFIG_PSTORE=y
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+# CONFIG_UFS_DEBUG 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=y
+# CONFIG_NFS_V4_1 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFS_USE_LEGACY_DNS is not set
+CONFIG_NFS_USE_KERNEL_DNS=y
+# CONFIG_NFS_USE_NEW_IDMAPPER is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_DEPRECATED=y
+CONFIG_NFSD_V2_ACL=y
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=m
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=m
+CONFIG_CEPH_FS=m
+CONFIG_CIFS=m
+CONFIG_CIFS_STATS=y
+CONFIG_CIFS_STATS2=y
+# CONFIG_CIFS_WEAK_PW_HASH is not set
+# CONFIG_CIFS_UPCALL is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_DFS_UPCALL is not set
+CONFIG_CIFS_EXPERIMENTAL=y
+CONFIG_NCP_FS=m
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+CONFIG_CODA_FS=m
+CONFIG_AFS_FS=m
+# CONFIG_AFS_DEBUG is not set
+CONFIG_9P_FS=m
+# CONFIG_9P_FS_POSIX_ACL 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=y
+CONFIG_MSDOS_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+# CONFIG_UNIXWARE_DISKLABEL is not set
+CONFIG_LDM_PARTITION=y
+CONFIG_LDM_DEBUG=y
+# 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=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=y
+CONFIG_DLM=m
+# CONFIG_DLM_DEBUG is not set
+
+#
+# Kernel hacking
+#
+CONFIG_PRINTK_TIME=y
+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# 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_SECTION_MISMATCH is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_LOCKUP_DETECTOR is not set
+# CONFIG_HARDLOCKUP_DETECTOR is not set
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_TEST_LIST_SORT is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_LKDTM is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_RING_BUFFER=y
+CONFIG_RING_BUFFER_ALLOW_SWAP=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_RING_BUFFER_BENCHMARK is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_ASYNC_RAID6_TEST is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_TEST_KSTRTOX is not set
+# CONFIG_STRICT_DEVMEM is not set
+CONFIG_ARM_UNWIND=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_LL is not set
+# CONFIG_OC_ETM is not set
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_DEBUG_PROC_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_XOR_BLOCKS=m
+CONFIG_ASYNC_CORE=m
+CONFIG_ASYNC_MEMCPY=m
+CONFIG_ASYNC_XOR=m
+CONFIG_ASYNC_PQ=m
+CONFIG_ASYNC_RAID6_RECOV=m
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD=m
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG=m
+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=m
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_CRYPTO_CRYPTD=m
+CONFIG_CRYPTO_AUTHENC=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Authenticated Encryption with Associated Data
+#
+CONFIG_CRYPTO_CCM=m
+CONFIG_CRYPTO_GCM=m
+CONFIG_CRYPTO_SEQIV=m
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_CTR=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=m
+CONFIG_CRYPTO_XCBC=m
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+CONFIG_CRYPTO_GHASH=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=y
+CONFIG_CRYPTO_RMD128=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_RMD256=m
+CONFIG_CRYPTO_RMD320=m
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CAMELLIA=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_FCRYPT=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_SALSA20=m
+CONFIG_CRYPTO_SEED=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_ZLIB is not set
+CONFIG_CRYPTO_LZO=y
+
+#
+# Random Number Generation
+#
+CONFIG_CRYPTO_ANSI_CPRNG=m
+CONFIG_CRYPTO_USER_API=m
+CONFIG_CRYPTO_USER_API_HASH=m
+CONFIG_CRYPTO_USER_API_SKCIPHER=m
+CONFIG_CRYPTO_HW=y
+CONFIG_CRYPTO_DEV_OMAP_SHAM=m
+CONFIG_CRYPTO_DEV_OMAP_AES=m
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_RAID6_PQ=m
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+CONFIG_CRC_T10DIF=y
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC32=y
+CONFIG_CRC7=y
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_XZ_DEC=y
+CONFIG_XZ_DEC_X86=y
+CONFIG_XZ_DEC_POWERPC=y
+CONFIG_XZ_DEC_IA64=y
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_ARMTHUMB=y
+CONFIG_XZ_DEC_SPARC=y
+CONFIG_XZ_DEC_BCJ=y
+CONFIG_XZ_DEC_TEST=m
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_XZ=y
+CONFIG_DECOMPRESS_LZO=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+CONFIG_BTREE=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
+CONFIG_AVERAGE=y
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/beagleboard/defconfig b/recipes-kernel/linux/linux-omap-2.6.39/beagleboard/defconfig
new file mode 100644
index 0000000000..9e81a05708
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/beagleboard/defconfig
@@ -0,0 +1,3490 @@
+#
+# Automatically generated make config: don't edit
+# Linux/arm 2.6.39 Kernel Configuration
+# Fri May 20 13:11:13 2011
+#
+CONFIG_ARM=y
+CONFIG_HAVE_PWM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_HAVE_SCHED_CLOCK=y
+CONFIG_GENERIC_GPIO=y
+# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_KTIME_SCALAR=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_ARCH_HAS_CPUFREQ=y
+CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_VECTORS_BASE=0xffff0000
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+CONFIG_HAVE_IRQ_WORK=y
+CONFIG_IRQ_WORK=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_LZO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_FHANDLE=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+# CONFIG_AUDIT is not set
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_HAVE_SPARSE_IRQ=y
+CONFIG_GENERIC_IRQ_SHOW=y
+# CONFIG_SPARSE_IRQ is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_PREEMPT_RCU=y
+# CONFIG_TINY_RCU is not set
+# CONFIG_TINY_PREEMPT_RCU is not set
+CONFIG_PREEMPT_RCU=y
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_CGROUPS=y
+# CONFIG_CGROUP_DEBUG is not set
+CONFIG_CGROUP_NS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CPUSETS=y
+CONFIG_PROC_PID_CPUSET=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_MEM_RES_CTLR=y
+CONFIG_CGROUP_MEM_RES_CTLR_SWAP=y
+CONFIG_CGROUP_MEM_RES_CTLR_SWAP_ENABLED=y
+CONFIG_CGROUP_PERF=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+# CONFIG_BLK_CGROUP is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_MM_OWNER=y
+# CONFIG_SYSFS_DEPRECATED is not set
+# CONFIG_RELAY is not set
+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_XZ=y
+CONFIG_RD_LZO=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EXPERT=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+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_EMBEDDED=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_PERF_EVENTS=y
+# CONFIG_PERF_COUNTERS is not set
+# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
+CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_HW_BREAKPOINT=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=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+CONFIG_BLK_DEV_BSG=y
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_DEADLINE is not set
+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 is not set
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set
+# 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 is not set
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+# CONFIG_INLINE_READ_UNLOCK_IRQ is not set
+# 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 is not set
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+# CONFIG_MUTEX_SPIN_ON_OWNER is not set
+CONFIG_FREEZER=y
+
+#
+# System Type
+#
+CONFIG_MMU=y
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_VEXPRESS is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_BCMRING is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CNS3XXX is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_MXS is not set
+# CONFIG_ARCH_STMP3XXX is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_DOVE is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_LPC32XX is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_NUC93X is not set
+# CONFIG_ARCH_TEGRA is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_SHMOBILE is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5P64X0 is not set
+# CONFIG_ARCH_S5P6442 is not set
+# CONFIG_ARCH_S5PC100 is not set
+# CONFIG_ARCH_S5PV210 is not set
+# CONFIG_ARCH_EXYNOS4 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_TCC_926 is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_U8500 is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_PLAT_SPEAR is not set
+# CONFIG_ARCH_VT8500 is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_KEYBOARD_GPIO_POLLED is not set
+
+#
+# TI OMAP Common Features
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+CONFIG_ARCH_OMAP2PLUS=y
+
+#
+# OMAP Feature Selections
+#
+CONFIG_OMAP_SMARTREFLEX=y
+CONFIG_OMAP_SMARTREFLEX_CLASS3=y
+CONFIG_OMAP_RESET_CLOCKS=y
+# CONFIG_OMAP_MUX is not set
+CONFIG_OMAP_MCBSP=y
+CONFIG_OMAP_MBOX_FWK=m
+CONFIG_OMAP_MBOX_KFIFO_SIZE=256
+CONFIG_OMAP_IOMMU=y
+CONFIG_OMAP_IOMMU_DEBUG=m
+CONFIG_OMAP_32K_TIMER=y
+# CONFIG_OMAP3_L2_AUX_SECURE_SAVE_RESTORE is not set
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+# CONFIG_OMAP_PM_NONE is not set
+CONFIG_OMAP_PM_NOOP=y
+
+#
+# TI OMAP2/3/4 Specific Features
+#
+CONFIG_ARCH_OMAP2PLUS_TYPICAL=y
+# CONFIG_ARCH_OMAP2 is not set
+CONFIG_ARCH_OMAP3=y
+# CONFIG_ARCH_OMAP4 is not set
+CONFIG_SOC_OMAP3430=y
+# CONFIG_SOC_OMAPTI816X is not set
+CONFIG_OMAP_PACKAGE_CBB=y
+
+#
+# OMAP Board Type
+#
+CONFIG_MACH_OMAP3_BEAGLE=y
+# CONFIG_MACH_DEVKIT8000 is not set
+# CONFIG_MACH_OMAP_LDP is not set
+# CONFIG_MACH_OMAP3530_LV_SOM is not set
+# CONFIG_MACH_OMAP3_TORPEDO is not set
+CONFIG_MACH_OVERO=y
+CONFIG_MACH_OMAP3EVM=y
+# CONFIG_MACH_OMAP3517EVM is not set
+# CONFIG_MACH_CRANEBOARD is not set
+# CONFIG_MACH_OMAP3_PANDORA is not set
+CONFIG_MACH_OMAP3_TOUCHBOOK=y
+# CONFIG_MACH_OMAP_3430SDP is not set
+# CONFIG_MACH_NOKIA_RM680 is not set
+# CONFIG_MACH_NOKIA_RX51 is not set
+CONFIG_MACH_OMAP_ZOOM2=y
+# CONFIG_MACH_OMAP_ZOOM3 is not set
+# CONFIG_MACH_CM_T35 is not set
+# CONFIG_MACH_CM_T3517 is not set
+# CONFIG_MACH_IGEP0020 is not set
+# CONFIG_MACH_IGEP0030 is not set
+# CONFIG_MACH_SBC3530 is not set
+# CONFIG_MACH_OMAP_3630SDP is not set
+# CONFIG_OMAP3_EMU is not set
+# CONFIG_OMAP3_SDRC_AC_TIMING is not set
+
+#
+# System MMU
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+CONFIG_ARM_THUMBEE=y
+# CONFIG_SWP_EMULATE is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_ARM_L1_CACHE_SHIFT_6=y
+CONFIG_ARM_L1_CACHE_SHIFT=6
+CONFIG_ARM_DMA_MEM_BUFFERABLE=y
+CONFIG_ARM_ERRATA_430973=y
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+# CONFIG_ARM_ERRATA_743622 is not set
+# CONFIG_ARM_ERRATA_754322 is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_HZ=128
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_COMPACTION=y
+CONFIG_MIGRATION=y
+# 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_NEED_PER_CPU_KM=y
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_LEDS=y
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+# CONFIG_SECCOMP is not set
+# CONFIG_CC_STACKPROTECTOR is not set
+# CONFIG_DEPRECATED_PARAM_STRUCT is not set
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=" debug "
+# CONFIG_CMDLINE_FORCE is not set
+# CONFIG_XIP_KERNEL is not set
+CONFIG_KEXEC=y
+CONFIG_ATAGS_PROC=y
+# CONFIG_CRASH_DUMP is not set
+# CONFIG_AUTO_ZRELADDR is not set
+
+#
+# CPU Power Management
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+CONFIG_CPU_FREQ_DEBUG=y
+CONFIG_CPU_FREQ_STAT=y
+CONFIG_CPU_FREQ_STAT_DETAILS=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_NEON=y
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+CONFIG_BINFMT_AOUT=m
+CONFIG_BINFMT_MISC=y
+
+#
+# Power management options
+#
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_PM_SLEEP=y
+CONFIG_PM_RUNTIME=y
+CONFIG_PM=y
+CONFIG_PM_DEBUG=y
+# CONFIG_PM_VERBOSE is not set
+# CONFIG_PM_ADVANCED_DEBUG is not set
+# CONFIG_PM_TEST_SUSPEND is not set
+CONFIG_CAN_PM_TRACE=y
+# CONFIG_APM_EMULATION is not set
+CONFIG_ARCH_HAS_OPP=y
+CONFIG_PM_OPP=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_XFRM_IPCOMP=m
+CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_ROUTE_CLASSID=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE_DEMUX=m
+CONFIG_NET_IPGRE=m
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_TUNNEL=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_LRO=y
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_BIC=m
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=m
+CONFIG_TCP_CONG_SCALABLE=m
+CONFIG_TCP_CONG_LP=m
+CONFIG_TCP_CONG_VENO=m
+CONFIG_TCP_CONG_YEAH=m
+CONFIG_TCP_CONG_ILLINOIS=m
+CONFIG_DEFAULT_CUBIC=y
+# CONFIG_DEFAULT_RENO is not set
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+CONFIG_IPV6=m
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_MIP6=m
+CONFIG_INET6_XFRM_TUNNEL=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
+CONFIG_IPV6_SIT=m
+# CONFIG_IPV6_SIT_6RD is not set
+CONFIG_IPV6_NDISC_NODETYPE=y
+CONFIG_IPV6_TUNNEL=m
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_MROUTE=y
+CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
+# CONFIG_IPV6_PIMSM_V2 is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETWORK_PHY_TIMESTAMPING=y
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_CONNTRACK_MARK=y
+CONFIG_NF_CONNTRACK_ZONES=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CONNTRACK_TIMESTAMP=y
+CONFIG_NF_CT_PROTO_DCCP=m
+CONFIG_NF_CT_PROTO_GRE=m
+CONFIG_NF_CT_PROTO_SCTP=m
+CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_BROADCAST=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+CONFIG_NF_CONNTRACK_SNMP=m
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_SANE=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NF_CT_NETLINK=m
+# CONFIG_NETFILTER_TPROXY is not set
+CONFIG_NETFILTER_XTABLES=m
+
+#
+# Xtables combined modules
+#
+CONFIG_NETFILTER_XT_MARK=m
+CONFIG_NETFILTER_XT_CONNMARK=m
+CONFIG_NETFILTER_XT_SET=m
+
+#
+# Xtables targets
+#
+CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_CT=m
+# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
+CONFIG_NETFILTER_XT_TARGET_HL=m
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
+# CONFIG_NETFILTER_XT_TARGET_LED is not set
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
+CONFIG_NETFILTER_XT_TARGET_RATEEST=m
+CONFIG_NETFILTER_XT_TARGET_TEE=m
+# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set
+
+#
+# Xtables matches
+#
+CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
+# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_CPU=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_HL=m
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
+CONFIG_NETFILTER_XT_MATCH_IPVS=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+# CONFIG_NETFILTER_XT_MATCH_OSF is not set
+CONFIG_NETFILTER_XT_MATCH_OWNER=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_RECENT=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_TIME=m
+CONFIG_NETFILTER_XT_MATCH_U32=m
+CONFIG_IP_SET=m
+CONFIG_IP_SET_MAX=256
+# CONFIG_IP_SET_BITMAP_IP is not set
+# CONFIG_IP_SET_BITMAP_IPMAC is not set
+# CONFIG_IP_SET_BITMAP_PORT is not set
+# CONFIG_IP_SET_HASH_IP is not set
+# CONFIG_IP_SET_HASH_IPPORT is not set
+# CONFIG_IP_SET_HASH_IPPORTIP is not set
+# CONFIG_IP_SET_HASH_IPPORTNET is not set
+# CONFIG_IP_SET_HASH_NET is not set
+# CONFIG_IP_SET_HASH_NETPORT is not set
+# CONFIG_IP_SET_LIST_SET is not set
+CONFIG_IP_VS=m
+CONFIG_IP_VS_IPV6=y
+CONFIG_IP_VS_DEBUG=y
+CONFIG_IP_VS_TAB_BITS=12
+
+#
+# IPVS transport protocol load balancing support
+#
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_AH_ESP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+# CONFIG_IP_VS_PROTO_SCTP is not set
+
+#
+# IPVS scheduler
+#
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+
+#
+# IPVS application helper
+#
+CONFIG_IP_VS_FTP=m
+CONFIG_IP_VS_NFCT=y
+CONFIG_IP_VS_PE_SIP=m
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV4=m
+CONFIG_NF_CONNTRACK_IPV4=m
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_NF_NAT=m
+CONFIG_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_NF_NAT_SNMP_BASIC=m
+CONFIG_NF_NAT_PROTO_DCCP=m
+CONFIG_NF_NAT_PROTO_GRE=m
+CONFIG_NF_NAT_PROTO_UDPLITE=m
+CONFIG_NF_NAT_PROTO_SCTP=m
+CONFIG_NF_NAT_FTP=m
+CONFIG_NF_NAT_IRC=m
+CONFIG_NF_NAT_TFTP=m
+CONFIG_NF_NAT_AMANDA=m
+CONFIG_NF_NAT_PPTP=m
+CONFIG_NF_NAT_H323=m
+CONFIG_NF_NAT_SIP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV6=m
+CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_MH=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_RAW=m
+# CONFIG_BRIDGE_NF_EBTABLES is not set
+CONFIG_IP_DCCP=m
+CONFIG_INET_DCCP_DIAG=m
+
+#
+# DCCP CCIDs Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP_CCID2_DEBUG is not set
+CONFIG_IP_DCCP_CCID3=y
+# CONFIG_IP_DCCP_CCID3_DEBUG is not set
+CONFIG_IP_DCCP_TFRC_LIB=y
+
+#
+# DCCP Kernel Hacking
+#
+# CONFIG_IP_DCCP_DEBUG is not set
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+# CONFIG_RDS is not set
+CONFIG_TIPC=m
+# CONFIG_TIPC_ADVANCED is not set
+# CONFIG_TIPC_DEBUG is not set
+CONFIG_ATM=m
+CONFIG_ATM_CLIP=m
+# CONFIG_ATM_CLIP_NO_ICMP is not set
+CONFIG_ATM_LANE=m
+CONFIG_ATM_MPOA=m
+CONFIG_ATM_BR2684=m
+# CONFIG_ATM_BR2684_IPFILTER is not set
+CONFIG_L2TP=m
+CONFIG_L2TP_DEBUGFS=m
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=m
+CONFIG_L2TP_ETH=m
+CONFIG_STP=m
+CONFIG_GARP=m
+CONFIG_BRIDGE=m
+CONFIG_BRIDGE_IGMP_SNOOPING=y
+# CONFIG_NET_DSA is not set
+CONFIG_VLAN_8021Q=m
+CONFIG_VLAN_8021Q_GVRP=y
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# 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=m
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+CONFIG_NET_SCHED=y
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_ATM=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_MULTIQ=m
+CONFIG_NET_SCH_RED=m
+# CONFIG_NET_SCH_SFB is not set
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_DRR=m
+CONFIG_NET_SCH_MQPRIO=m
+CONFIG_NET_SCH_CHOKE=m
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_PERF=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_FLOW=m
+CONFIG_NET_CLS_CGROUP=m
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_CLS_ACT is not set
+CONFIG_NET_CLS_IND=y
+CONFIG_NET_SCH_FIFO=y
+# CONFIG_DCB is not set
+CONFIG_DNS_RESOLVER=y
+# CONFIG_BATMAN_ADV is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+CONFIG_CAN=m
+CONFIG_CAN_RAW=m
+CONFIG_CAN_BCM=m
+
+#
+# CAN Device Drivers
+#
+CONFIG_CAN_VCAN=m
+CONFIG_CAN_SLCAN=m
+# CONFIG_CAN_DEV is not set
+# CONFIG_CAN_DEBUG_DEVICES is not set
+CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRCOMM=m
+CONFIG_IRDA_ULTRA=y
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+CONFIG_IRDA_DEBUG=y
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+CONFIG_IRTTY_SIR=m
+
+#
+# Dongle support
+#
+CONFIG_DONGLE=y
+CONFIG_ESI_DONGLE=m
+CONFIG_ACTISYS_DONGLE=m
+CONFIG_TEKRAM_DONGLE=m
+CONFIG_TOIM3232_DONGLE=m
+CONFIG_LITELINK_DONGLE=m
+CONFIG_MA600_DONGLE=m
+CONFIG_GIRBIL_DONGLE=m
+CONFIG_MCP2120_DONGLE=m
+CONFIG_OLD_BELKIN_DONGLE=m
+# CONFIG_ACT200L_DONGLE is not set
+CONFIG_KINGSUN_DONGLE=m
+CONFIG_KSDAZZLE_DONGLE=m
+CONFIG_KS959_DONGLE=m
+
+#
+# FIR device drivers
+#
+CONFIG_USB_IRDA=m
+CONFIG_SIGMATEL_FIR=m
+CONFIG_MCS_FIR=m
+CONFIG_BT=m
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=m
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIBTUSB=m
+CONFIG_BT_HCIBTSDIO=m
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIUART_ATH3K=y
+CONFIG_BT_HCIUART_LL=y
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_BT_HCIBFUSB=m
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_BT_MRVL is not set
+CONFIG_BT_ATH3K=m
+CONFIG_BT_WILINK=m
+CONFIG_AF_RXRPC=m
+# CONFIG_AF_RXRPC_DEBUG is not set
+# CONFIG_RXKAD is not set
+CONFIG_FIB_RULES=y
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_WEXT_CORE=y
+CONFIG_WEXT_PROC=y
+CONFIG_WEXT_SPY=y
+CONFIG_WEXT_PRIV=y
+CONFIG_CFG80211=m
+CONFIG_NL80211_TESTMODE=y
+# 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_CRYPT_WEP=m
+CONFIG_LIB80211_CRYPT_CCMP=m
+CONFIG_LIB80211_CRYPT_TKIP=m
+# CONFIG_LIB80211_DEBUG is not set
+CONFIG_MAC80211=m
+CONFIG_MAC80211_HAS_RC=y
+CONFIG_MAC80211_RC_PID=y
+# CONFIG_MAC80211_RC_MINSTREL is not set
+CONFIG_MAC80211_RC_DEFAULT_PID=y
+CONFIG_MAC80211_RC_DEFAULT="pid"
+# CONFIG_MAC80211_MESH is not set
+CONFIG_MAC80211_LEDS=y
+# CONFIG_MAC80211_DEBUGFS is not set
+# CONFIG_MAC80211_DEBUG_MENU is not set
+CONFIG_WIMAX=m
+CONFIG_WIMAX_DEBUG_LEVEL=8
+CONFIG_RFKILL=m
+CONFIG_RFKILL_LEDS=y
+CONFIG_RFKILL_INPUT=y
+CONFIG_NET_9P=m
+# CONFIG_NET_9P_DEBUG is not set
+# CONFIG_CAIF is not set
+CONFIG_CEPH_LIB=m
+# CONFIG_CEPH_LIB_PRETTYDEBUG is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH=""
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# 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_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+# 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=m
+# CONFIG_MTD_OOPS is not set
+CONFIG_MTD_SWAP=m
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE 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_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# 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_NAND_ECC_BCH is not set
+# CONFIG_MTD_SM_COMMON is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_GPIO is not set
+CONFIG_MTD_NAND_OMAP2=y
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+CONFIG_MTD_NAND_PLATFORM=y
+# 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 is not set
+# 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=m
+
+#
+# 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=16384
+# CONFIG_BLK_DEV_XIP is not set
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MG_DISK is not set
+# CONFIG_BLK_DEV_RBD is not set
+# CONFIG_SENSORS_LIS3LV02D 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=m
+# CONFIG_SENSORS_BH1770 is not set
+# CONFIG_SENSORS_APDS990X is not set
+CONFIG_HMC6352=m
+# CONFIG_DS1682 is not set
+# CONFIG_TI_DAC7512 is not set
+CONFIG_BMP085=m
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+CONFIG_EEPROM_AT24=m
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+CONFIG_EEPROM_93CX6=y
+CONFIG_IWMC3200TOP=m
+# CONFIG_IWMC3200TOP_DEBUG is not set
+# CONFIG_IWMC3200TOP_DEBUGFS is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+CONFIG_TI_ST=m
+# CONFIG_SENSORS_LIS3_SPI is not set
+# CONFIG_SENSORS_LIS3_I2C is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+CONFIG_RAID_ATTRS=m
+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=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=m
+CONFIG_SCSI_MULTI_LUN=y
+# 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=m
+# 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=m
+CONFIG_ISCSI_BOOT_SYSFS=m
+# 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 is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID456=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_FAULTY=m
+CONFIG_BLK_DEV_DM=m
+# CONFIG_DM_DEBUG is not set
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_RAID=m
+# CONFIG_DM_LOG_USERSPACE is not set
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+# CONFIG_DM_MULTIPATH_QL is not set
+# CONFIG_DM_MULTIPATH_ST is not set
+CONFIG_DM_DELAY=m
+# CONFIG_DM_UEVENT is not set
+CONFIG_DM_FLAKEY=m
+CONFIG_TARGET_CORE=m
+CONFIG_TCM_IBLOCK=m
+CONFIG_TCM_FILEIO=m
+CONFIG_TCM_PSCSI=m
+CONFIG_LOOPBACK_TARGET=m
+# CONFIG_LOOPBACK_TARGET_CDB_DEBUG is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+CONFIG_MACVLAN=m
+CONFIG_MACVTAP=m
+CONFIG_EQUALIZER=m
+CONFIG_TUN=m
+CONFIG_VETH=m
+CONFIG_MII=y
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+CONFIG_BCM63XX_PHY=m
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+CONFIG_MICREL_PHY=m
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_AX88796 is not set
+CONFIG_SMC91X=y
+# CONFIG_TI_DAVINCI_EMAC is not set
+CONFIG_TI_DAVINCI_MDIO=m
+CONFIG_TI_DAVINCI_CPDMA=m
+# CONFIG_DM9000 is not set
+CONFIG_ENC28J60=y
+# CONFIG_ENC28J60_WRITEVERIFY is not set
+# CONFIG_ETHOC is not set
+CONFIG_SMC911X=y
+CONFIG_SMSC911X=y
+# CONFIG_SMSC911X_ARCH_HOOKS 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_KS8842=m
+CONFIG_KS8851=y
+# CONFIG_KS8851_MLL is not set
+# CONFIG_FTMAC100 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+CONFIG_WLAN=y
+# CONFIG_LIBERTAS_THINFIRM is not set
+CONFIG_AT76C50X_USB=m
+CONFIG_USB_ZD1201=m
+CONFIG_USB_NET_RNDIS_WLAN=m
+CONFIG_RTL8187=m
+CONFIG_RTL8187_LEDS=y
+# CONFIG_MAC80211_HWSIM is not set
+# CONFIG_ATH_COMMON is not set
+CONFIG_B43=m
+# CONFIG_B43_SDIO is not set
+CONFIG_B43_PIO=y
+CONFIG_B43_PHY_N=y
+CONFIG_B43_PHY_LP=y
+CONFIG_B43_LEDS=y
+CONFIG_B43_HWRNG=y
+# CONFIG_B43_DEBUG is not set
+# CONFIG_B43LEGACY is not set
+CONFIG_HOSTAP=m
+CONFIG_HOSTAP_FIRMWARE=y
+CONFIG_HOSTAP_FIRMWARE_NVRAM=y
+# CONFIG_IWM is not set
+CONFIG_LIBERTAS=m
+CONFIG_LIBERTAS_USB=m
+# CONFIG_LIBERTAS_SDIO is not set
+# CONFIG_LIBERTAS_SPI is not set
+# CONFIG_LIBERTAS_DEBUG is not set
+# CONFIG_LIBERTAS_MESH is not set
+CONFIG_P54_COMMON=m
+CONFIG_P54_USB=m
+# CONFIG_P54_SPI is not set
+CONFIG_P54_LEDS=y
+CONFIG_RT2X00=m
+CONFIG_RT2500USB=m
+CONFIG_RT73USB=m
+# CONFIG_RT2800USB is not set
+CONFIG_RT2X00_LIB_USB=m
+CONFIG_RT2X00_LIB=m
+CONFIG_RT2X00_LIB_FIRMWARE=y
+CONFIG_RT2X00_LIB_CRYPTO=y
+CONFIG_RT2X00_LIB_LEDS=y
+# CONFIG_RT2X00_DEBUG is not set
+CONFIG_RTL8192CU=m
+CONFIG_RTLWIFI=m
+CONFIG_RTL8192C_COMMON=m
+CONFIG_WL1251=m
+CONFIG_WL1251_SPI=m
+CONFIG_WL1251_SDIO=m
+CONFIG_WL12XX_MENU=m
+CONFIG_WL12XX=m
+CONFIG_WL12XX_HT=y
+CONFIG_WL12XX_SPI=m
+CONFIG_WL12XX_SDIO=m
+# CONFIG_WL12XX_SDIO_TEST is not set
+CONFIG_WL12XX_PLATFORM_DATA=y
+CONFIG_ZD1211RW=m
+# CONFIG_ZD1211RW_DEBUG is not set
+
+#
+# WiMAX Wireless Broadband devices
+#
+CONFIG_WIMAX_I2400M=m
+CONFIG_WIMAX_I2400M_USB=m
+CONFIG_WIMAX_I2400M_SDIO=m
+CONFIG_WIMAX_IWMC3200_SDIO=y
+CONFIG_WIMAX_I2400M_DEBUG_LEVEL=8
+
+#
+# USB Network Adapters
+#
+CONFIG_USB_CATC=y
+CONFIG_USB_KAWETH=y
+CONFIG_USB_PEGASUS=y
+CONFIG_USB_RTL8150=y
+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_CDC_NCM=m
+CONFIG_USB_NET_DM9601=y
+CONFIG_USB_NET_SMSC75XX=m
+CONFIG_USB_NET_SMSC95XX=y
+CONFIG_USB_NET_GL620A=y
+CONFIG_USB_NET_NET1080=y
+CONFIG_USB_NET_PLUSB=y
+CONFIG_USB_NET_MCS7830=y
+CONFIG_USB_NET_RNDIS_HOST=y
+CONFIG_USB_NET_CDC_SUBSET=y
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_KC2190=y
+CONFIG_USB_NET_ZAURUS=y
+CONFIG_USB_NET_CX82310_ETH=m
+CONFIG_USB_HSO=m
+CONFIG_USB_NET_INT51X1=m
+CONFIG_USB_IPHETH=m
+CONFIG_USB_SIERRA_NET=m
+CONFIG_USB_VL600=m
+# CONFIG_WAN is not set
+CONFIG_ATM_DRIVERS=y
+# CONFIG_ATM_DUMMY is not set
+# CONFIG_ATM_TCP is not set
+
+#
+# CAIF transport drivers
+#
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_PPTP=m
+# CONFIG_PPPOATM is not set
+CONFIG_PPPOL2TP=m
+# CONFIG_SLIP is not set
+CONFIG_SLHC=m
+CONFIG_NETCONSOLE=m
+CONFIG_NETCONSOLE_DYNAMIC=y
+CONFIG_NETPOLL=y
+CONFIG_NETPOLL_TRAP=y
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+CONFIG_INPUT_FF_MEMLESS=y
+CONFIG_INPUT_POLLDEV=y
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+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=y
+# CONFIG_KEYBOARD_ADP5588 is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_QT1070=m
+CONFIG_KEYBOARD_QT2160=m
+# CONFIG_KEYBOARD_LKKBD is not set
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_KEYBOARD_TCA6416 is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_LM8323 is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+CONFIG_KEYBOARD_MCS=m
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_TWL4030 is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_ELANTECH is not set
+# CONFIG_MOUSE_PS2_SENTELIC is not set
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_BCM5974 is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_MOUSE_GPIO is not set
+# CONFIG_MOUSE_SYNAPTICS_I2C is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_AD714X=m
+CONFIG_INPUT_AD714X_I2C=m
+CONFIG_INPUT_AD714X_SPI=m
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_CM109 is not set
+CONFIG_INPUT_TWL4030_PWRBUTTON=y
+CONFIG_INPUT_TWL4030_VIBRA=m
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_PCF8574=m
+CONFIG_INPUT_PWM_BEEPER=m
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+CONFIG_INPUT_ADXL34X=m
+CONFIG_INPUT_ADXL34X_I2C=m
+CONFIG_INPUT_ADXL34X_SPI=m
+CONFIG_INPUT_CMA3000=m
+CONFIG_INPUT_CMA3000_I2C=m
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_ALTERA_PS2 is not set
+# CONFIG_SERIO_PS2MULT is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_N_GSM=m
+CONFIG_DEVKMEM=y
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# 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_OMAP=y
+CONFIG_SERIAL_OMAP_CONSOLE=y
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+CONFIG_SERIAL_IFX6X60=m
+CONFIG_TTY_PRINTK=y
+# CONFIG_HVC_DCC 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=m
+
+#
+# Multiplexer I2C Chip support
+#
+CONFIG_I2C_MUX_GPIO=m
+# CONFIG_I2C_MUX_PCA9541 is not set
+# CONFIG_I2C_MUX_PCA954x is not set
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_ALGOBIT=m
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_DESIGNWARE is not set
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_PXA_PCI is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+CONFIG_I2C_DIOLAN_U2C=m
+# 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_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_ALTERA is not set
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
+# CONFIG_SPI_OC_TINY is not set
+CONFIG_SPI_OMAP24XX=y
+# CONFIG_SPI_PXA2XX_PCI is not set
+# CONFIG_SPI_XILINX is not set
+# CONFIG_SPI_DESIGNWARE is not set
+
+#
+# SPI Protocol Masters
+#
+CONFIG_SPI_SPIDEV=y
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+
+#
+# PPS generators support
+#
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_MAX730X=m
+
+#
+# Memory mapped GPIO expanders:
+#
+# CONFIG_GPIO_BASIC_MMIO is not set
+# CONFIG_GPIO_IT8761E is not set
+
+#
+# I2C GPIO expanders:
+#
+CONFIG_GPIO_MAX7300=m
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_SX150X is not set
+CONFIG_GPIO_TWL4030=y
+CONFIG_GPIO_ADP5588=m
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+# CONFIG_GPIO_74X164 is not set
+
+#
+# AC97 GPIO expanders:
+#
+
+#
+# MODULbus GPIO expanders:
+#
+# CONFIG_W1 is not set
+CONFIG_POWER_SUPPLY=m
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+CONFIG_TEST_POWER=m
+# CONFIG_BATTERY_DS2782 is not set
+# CONFIG_BATTERY_BQ20Z75 is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_BATTERY_MAX17040 is not set
+CONFIG_BATTERY_MAX17042=m
+CONFIG_CHARGER_ISP1704=m
+CONFIG_CHARGER_TWL4030=m
+CONFIG_CHARGER_GPIO=m
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADCXX is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+CONFIG_SENSORS_ADT7411=m
+# CONFIG_SENSORS_ADT7462 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7475 is not set
+CONFIG_SENSORS_ASC7621=m
+# CONFIG_SENSORS_ATXP1 is not set
+CONFIG_SENSORS_DS620=m
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_G760A is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+CONFIG_SENSORS_GPIO_FAN=m
+# CONFIG_SENSORS_IT87 is not set
+CONFIG_SENSORS_JC42=m
+# CONFIG_SENSORS_LINEAGE is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM73 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LTC4151 is not set
+# CONFIG_SENSORS_LTC4215 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LTC4261 is not set
+# CONFIG_SENSORS_LM95241 is not set
+# CONFIG_SENSORS_MAX1111 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6639 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_PMBUS is not set
+# CONFIG_SENSORS_SHT15 is not set
+# CONFIG_SENSORS_SHT21 is not set
+CONFIG_SENSORS_SMM665=m
+# CONFIG_SENSORS_DME1737 is not set
+CONFIG_SENSORS_EMC1403=m
+CONFIG_SENSORS_EMC2103=m
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SCH5627 is not set
+# CONFIG_SENSORS_ADS1015 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+CONFIG_SENSORS_ADS7871=m
+CONFIG_SENSORS_AMC6821=m
+# CONFIG_SENSORS_THMC50 is not set
+CONFIG_SENSORS_TMP102=m
+# CONFIG_SENSORS_TMP401 is not set
+# CONFIG_SENSORS_TMP421 is not set
+CONFIG_SENSORS_TWL4030_MADC=m
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83795 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+CONFIG_THERMAL=y
+CONFIG_THERMAL_HWMON=y
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+# CONFIG_TWL4030_WATCHDOG is not set
+# CONFIG_MAX63XX_WATCHDOG is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB=y
+CONFIG_SSB_BLOCKIO=y
+CONFIG_SSB_SDIOHOST_POSSIBLE=y
+# CONFIG_SSB_SDIOHOST is not set
+# CONFIG_SSB_SILENT is not set
+# CONFIG_SSB_DEBUG is not set
+CONFIG_MFD_SUPPORT=y
+CONFIG_MFD_CORE=y
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_HTC_I2CPLD is not set
+CONFIG_TPS6105X=m
+# CONFIG_TPS65010 is not set
+CONFIG_TPS6507X=m
+CONFIG_TWL4030_CORE=y
+CONFIG_TWL4030_MADC=m
+CONFIG_TWL4030_POWER=y
+CONFIG_TWL4030_CODEC=y
+CONFIG_TWL4030_POWEROFF=y
+CONFIG_TWL6030_PWM=m
+# CONFIG_MFD_STMPE is not set
+# CONFIG_MFD_TC3589X is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_MAX8997 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_MFD_TPS6586X=y
+CONFIG_MFD_WL1273_CORE=m
+CONFIG_MFD_OMAP_USB_HOST=y
+CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_DEBUG is not set
+CONFIG_REGULATOR_DUMMY=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+# CONFIG_REGULATOR_MAX8649 is not set
+# CONFIG_REGULATOR_MAX8660 is not set
+# CONFIG_REGULATOR_MAX8952 is not set
+CONFIG_REGULATOR_TWL4030=y
+# CONFIG_REGULATOR_LP3971 is not set
+# CONFIG_REGULATOR_LP3972 is not set
+CONFIG_REGULATOR_TPS6105X=m
+# CONFIG_REGULATOR_TPS65023 is not set
+# CONFIG_REGULATOR_TPS6507X is not set
+# CONFIG_REGULATOR_ISL6271A is not set
+# CONFIG_REGULATOR_AD5398 is not set
+CONFIG_REGULATOR_TPS6586X=m
+CONFIG_REGULATOR_TPS6524X=m
+CONFIG_MEDIA_SUPPORT=y
+
+#
+# Multimedia core support
+#
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_COMMON=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_DVB_CORE=m
+CONFIG_VIDEO_MEDIA=m
+
+#
+# Multimedia drivers
+#
+CONFIG_RC_CORE=m
+CONFIG_LIRC=m
+CONFIG_RC_MAP=m
+CONFIG_IR_NEC_DECODER=m
+CONFIG_IR_RC5_DECODER=m
+CONFIG_IR_RC6_DECODER=m
+CONFIG_IR_JVC_DECODER=m
+CONFIG_IR_SONY_DECODER=m
+CONFIG_IR_RC5_SZ_DECODER=m
+CONFIG_IR_LIRC_CODEC=m
+# CONFIG_IR_IMON is not set
+# CONFIG_IR_MCEUSB is not set
+# CONFIG_IR_STREAMZAP is not set
+CONFIG_RC_LOOPBACK=m
+CONFIG_MEDIA_ATTACH=y
+CONFIG_MEDIA_TUNER=m
+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_VIDEO_V4L2=y
+CONFIG_VIDEOBUF_GEN=y
+CONFIG_VIDEOBUF_VMALLOC=m
+CONFIG_VIDEOBUF_DMA_CONTIG=y
+CONFIG_VIDEOBUF_DVB=m
+CONFIG_VIDEO_TVEEPROM=m
+CONFIG_VIDEO_TUNER=m
+CONFIG_V4L2_MEM2MEM_DEV=m
+CONFIG_VIDEOBUF2_CORE=m
+CONFIG_VIDEOBUF2_MEMOPS=m
+CONFIG_VIDEOBUF2_VMALLOC=m
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
+# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set
+CONFIG_VIDEO_IR_I2C=m
+
+#
+# Encoders/decoders and other helper chips
+#
+
+#
+# Audio decoders
+#
+# CONFIG_VIDEO_TVAUDIO is not set
+# CONFIG_VIDEO_TDA7432 is not set
+# CONFIG_VIDEO_TDA9840 is not set
+# CONFIG_VIDEO_TEA6415C is not set
+# CONFIG_VIDEO_TEA6420 is not set
+CONFIG_VIDEO_MSP3400=m
+# CONFIG_VIDEO_CS5345 is not set
+CONFIG_VIDEO_CS53L32A=m
+# CONFIG_VIDEO_M52790 is not set
+# CONFIG_VIDEO_TLV320AIC23B is not set
+CONFIG_VIDEO_WM8775=m
+# CONFIG_VIDEO_WM8739 is not set
+# CONFIG_VIDEO_VP27SMPX is not set
+
+#
+# RDS decoders
+#
+# CONFIG_VIDEO_SAA6588 is not set
+
+#
+# Video decoders
+#
+CONFIG_VIDEO_ADV7180=m
+# CONFIG_VIDEO_BT819 is not set
+# CONFIG_VIDEO_BT856 is not set
+# CONFIG_VIDEO_BT866 is not set
+# CONFIG_VIDEO_KS0127 is not set
+# CONFIG_VIDEO_OV7670 is not set
+CONFIG_VIDEO_MT9V011=m
+# CONFIG_VIDEO_TCM825X is not set
+# CONFIG_VIDEO_SAA7110 is not set
+CONFIG_VIDEO_SAA711X=m
+# CONFIG_VIDEO_SAA717X is not set
+# CONFIG_VIDEO_SAA7191 is not set
+# CONFIG_VIDEO_TVP514X is not set
+# CONFIG_VIDEO_TVP5150 is not set
+# CONFIG_VIDEO_TVP7002 is not set
+# CONFIG_VIDEO_VPX3220 is not set
+
+#
+# Video and audio decoders
+#
+CONFIG_VIDEO_CX25840=m
+
+#
+# MPEG video encoders
+#
+CONFIG_VIDEO_CX2341X=m
+
+#
+# Video encoders
+#
+# CONFIG_VIDEO_SAA7127 is not set
+# CONFIG_VIDEO_SAA7185 is not set
+# CONFIG_VIDEO_ADV7170 is not set
+# CONFIG_VIDEO_ADV7175 is not set
+# CONFIG_VIDEO_THS7303 is not set
+# CONFIG_VIDEO_ADV7343 is not set
+# CONFIG_VIDEO_AK881X is not set
+
+#
+# Video improvement chips
+#
+# CONFIG_VIDEO_UPD64031A is not set
+# CONFIG_VIDEO_UPD64083 is not set
+CONFIG_VIDEO_VIVI=m
+CONFIG_VIDEO_VPFE_CAPTURE=y
+# CONFIG_VIDEO_DM6446_CCDC is not set
+CONFIG_VIDEO_OMAP2_VOUT=y
+# CONFIG_VIDEO_CPIA2 is not set
+CONFIG_VIDEO_TIMBERDALE=m
+# CONFIG_VIDEO_AU0828 is not set
+CONFIG_VIDEO_SR030PC30=m
+CONFIG_VIDEO_NOON010PC30=m
+CONFIG_VIDEO_OMAP3=y
+# CONFIG_VIDEO_OMAP3_DEBUG is not set
+# CONFIG_SOC_CAMERA is not set
+CONFIG_V4L_USB_DRIVERS=y
+CONFIG_USB_VIDEO_CLASS=m
+CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
+CONFIG_USB_GSPCA=m
+CONFIG_USB_M5602=m
+CONFIG_USB_STV06XX=m
+# CONFIG_USB_GL860 is not set
+CONFIG_USB_GSPCA_BENQ=m
+CONFIG_USB_GSPCA_CONEX=m
+CONFIG_USB_GSPCA_CPIA1=m
+CONFIG_USB_GSPCA_ETOMS=m
+CONFIG_USB_GSPCA_FINEPIX=m
+# CONFIG_USB_GSPCA_JEILINJ is not set
+CONFIG_USB_GSPCA_KONICA=m
+CONFIG_USB_GSPCA_MARS=m
+# CONFIG_USB_GSPCA_MR97310A is not set
+CONFIG_USB_GSPCA_NW80X=m
+CONFIG_USB_GSPCA_OV519=m
+CONFIG_USB_GSPCA_OV534=m
+CONFIG_USB_GSPCA_OV534_9=m
+CONFIG_USB_GSPCA_PAC207=m
+# CONFIG_USB_GSPCA_PAC7302 is not set
+CONFIG_USB_GSPCA_PAC7311=m
+CONFIG_USB_GSPCA_SN9C2028=m
+# CONFIG_USB_GSPCA_SN9C20X is not set
+CONFIG_USB_GSPCA_SONIXB=m
+CONFIG_USB_GSPCA_SONIXJ=m
+CONFIG_USB_GSPCA_SPCA500=m
+CONFIG_USB_GSPCA_SPCA501=m
+CONFIG_USB_GSPCA_SPCA505=m
+CONFIG_USB_GSPCA_SPCA506=m
+CONFIG_USB_GSPCA_SPCA508=m
+CONFIG_USB_GSPCA_SPCA561=m
+CONFIG_USB_GSPCA_SPCA1528=m
+# CONFIG_USB_GSPCA_SQ905 is not set
+# CONFIG_USB_GSPCA_SQ905C is not set
+CONFIG_USB_GSPCA_SQ930X=m
+CONFIG_USB_GSPCA_STK014=m
+# CONFIG_USB_GSPCA_STV0680 is not set
+CONFIG_USB_GSPCA_SUNPLUS=m
+CONFIG_USB_GSPCA_T613=m
+CONFIG_USB_GSPCA_TV8532=m
+CONFIG_USB_GSPCA_VC032X=m
+CONFIG_USB_GSPCA_VICAM=m
+CONFIG_USB_GSPCA_XIRLINK_CIT=m
+CONFIG_USB_GSPCA_ZC3XX=m
+CONFIG_VIDEO_PVRUSB2=m
+CONFIG_VIDEO_PVRUSB2_SYSFS=y
+CONFIG_VIDEO_PVRUSB2_DVB=y
+# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set
+CONFIG_VIDEO_HDPVR=m
+CONFIG_VIDEO_EM28XX=m
+CONFIG_VIDEO_EM28XX_ALSA=m
+CONFIG_VIDEO_EM28XX_DVB=m
+CONFIG_VIDEO_TLG2300=m
+CONFIG_VIDEO_CX231XX=m
+CONFIG_VIDEO_CX231XX_RC=y
+# CONFIG_VIDEO_CX231XX_ALSA is not set
+CONFIG_VIDEO_CX231XX_DVB=m
+CONFIG_VIDEO_USBVISION=m
+CONFIG_USB_ET61X251=m
+CONFIG_USB_SN9C102=m
+CONFIG_USB_PWC=m
+# CONFIG_USB_PWC_DEBUG is not set
+CONFIG_USB_PWC_INPUT_EVDEV=y
+CONFIG_USB_ZR364XX=m
+CONFIG_USB_STKWEBCAM=m
+CONFIG_USB_S2255=m
+CONFIG_V4L_MEM2MEM_DRIVERS=y
+CONFIG_VIDEO_MEM2MEM_TESTDEV=m
+CONFIG_RADIO_ADAPTERS=y
+# CONFIG_I2C_SI4713 is not set
+# CONFIG_RADIO_SI4713 is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_RADIO_SI470X is not set
+# CONFIG_USB_MR800 is not set
+# CONFIG_RADIO_TEA5764 is not set
+CONFIG_RADIO_SAA7706H=m
+# CONFIG_RADIO_TEF6862 is not set
+CONFIG_RADIO_WL1273=m
+
+#
+# Texas Instruments WL128x FM driver (ST based)
+#
+CONFIG_RADIO_WL128X=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=m
+# CONFIG_DVB_USB_DEBUG is not set
+CONFIG_DVB_USB_A800=m
+CONFIG_DVB_USB_DIBUSB_MB=m
+# CONFIG_DVB_USB_DIBUSB_MB_FAULTY is not set
+CONFIG_DVB_USB_DIBUSB_MC=m
+CONFIG_DVB_USB_DIB0700=m
+CONFIG_DVB_USB_UMT_010=m
+CONFIG_DVB_USB_CXUSB=m
+CONFIG_DVB_USB_M920X=m
+CONFIG_DVB_USB_GL861=m
+CONFIG_DVB_USB_AU6610=m
+CONFIG_DVB_USB_DIGITV=m
+CONFIG_DVB_USB_VP7045=m
+CONFIG_DVB_USB_VP702X=m
+CONFIG_DVB_USB_GP8PSK=m
+CONFIG_DVB_USB_NOVA_T_USB2=m
+CONFIG_DVB_USB_TTUSB2=m
+CONFIG_DVB_USB_DTT200U=m
+CONFIG_DVB_USB_OPERA1=m
+CONFIG_DVB_USB_AF9005=m
+CONFIG_DVB_USB_AF9005_REMOTE=m
+CONFIG_DVB_USB_DW2102=m
+CONFIG_DVB_USB_CINERGY_T2=m
+CONFIG_DVB_USB_ANYSEE=m
+CONFIG_DVB_USB_DTV5100=m
+CONFIG_DVB_USB_AF9015=m
+# CONFIG_DVB_USB_CE6230 is not set
+# CONFIG_DVB_USB_FRIIO is not set
+# CONFIG_DVB_USB_EC168 is not set
+CONFIG_DVB_USB_AZ6027=m
+CONFIG_DVB_USB_LME2510=m
+CONFIG_DVB_USB_TECHNISAT_USB2=m
+# CONFIG_SMS_SIANO_MDTV is not set
+
+#
+# Supported FlexCopII (B2C2) Adapters
+#
+CONFIG_DVB_B2C2_FLEXCOP=m
+CONFIG_DVB_B2C2_FLEXCOP_USB=m
+# CONFIG_DVB_B2C2_FLEXCOP_DEBUG is not set
+
+#
+# Supported DVB Frontends
+#
+# CONFIG_DVB_FE_CUSTOMISE is not set
+
+#
+# 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_CX24123=m
+CONFIG_DVB_MT312=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_TDA10086=m
+CONFIG_DVB_TUNER_ITD1000=m
+CONFIG_DVB_TUNER_CX24113=m
+CONFIG_DVB_TDA826X=m
+CONFIG_DVB_CX24116=m
+CONFIG_DVB_SI21XX=m
+CONFIG_DVB_DS3000=m
+
+#
+# DVB-T (terrestrial) frontends
+#
+CONFIG_DVB_CX22702=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
+
+#
+# DVB-C (cable) frontends
+#
+CONFIG_DVB_TDA10023=m
+CONFIG_DVB_STV0297=m
+
+#
+# ATSC (North American/Korean Terrestrial/Cable DTV) frontends
+#
+CONFIG_DVB_NXT200X=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
+CONFIG_DVB_MB86A20S=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_ISL6421=m
+CONFIG_DVB_LGS8GXX=m
+CONFIG_DVB_ATBM8830=m
+CONFIG_DVB_IX2505V=m
+
+#
+# Tools to develop new frontends
+#
+# CONFIG_DVB_DUMMY_FE is not set
+
+#
+# Graphics support
+#
+CONFIG_DRM=m
+# 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=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+CONFIG_FB_SYS_FILLRECT=m
+CONFIG_FB_SYS_COPYAREA=m
+CONFIG_FB_SYS_IMAGEBLIT=m
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+CONFIG_FB_SYS_FOPS=m
+# CONFIG_FB_WMT_GE_ROPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_TMIO is not set
+CONFIG_FB_UDL=m
+# 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_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_OMAP2_VRAM=y
+CONFIG_OMAP2_VRFB=y
+CONFIG_OMAP2_DSS=y
+CONFIG_OMAP2_VRAM_SIZE=14
+CONFIG_OMAP2_DSS_DEBUG_SUPPORT=y
+# CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS is not set
+CONFIG_OMAP2_DSS_DPI=y
+# CONFIG_OMAP2_DSS_RFBI is not set
+CONFIG_OMAP2_DSS_VENC=y
+# CONFIG_OMAP2_DSS_SDI is not set
+CONFIG_OMAP2_DSS_DSI=y
+CONFIG_OMAP2_DSS_USE_DSI_PLL=y
+# CONFIG_OMAP2_DSS_FAKE_VSYNC is not set
+CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=0
+CONFIG_FB_OMAP2=y
+CONFIG_FB_OMAP2_DEBUG_SUPPORT=y
+CONFIG_FB_OMAP2_NUM_FBS=2
+
+#
+# OMAP2/3 Display Device Drivers
+#
+CONFIG_PANEL_GENERIC_DPI=y
+# CONFIG_PANEL_LGPHILIPS_LB035Q02 is not set
+CONFIG_PANEL_SHARP_LS037V7DW01=y
+CONFIG_PANEL_NEC_NL8048HL11_01B=y
+# CONFIG_PANEL_TAAL is not set
+CONFIG_PANEL_TPO_TD043MTEA1=m
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+
+#
+# Display device support
+#
+CONFIG_DISPLAY_SUPPORT=y
+
+#
+# Display hardware drivers
+#
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_SOUND=y
+CONFIG_SOUND_OSS_CORE=y
+CONFIG_SOUND_OSS_CORE_PRECLAIM=y
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_HWDEP=y
+CONFIG_SND_RAWMIDI=y
+CONFIG_SND_JACK=y
+CONFIG_SND_SEQUENCER=m
+# CONFIG_SND_SEQ_DUMMY 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_SEQUENCER_OSS=y
+CONFIG_SND_HRTIMER=m
+CONFIG_SND_SEQ_HRTIMER_DEFAULT=y
+CONFIG_SND_DYNAMIC_MINORS=y
+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=m
+# 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=m
+# CONFIG_SND_VIRMIDI is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+# CONFIG_SND_ARM is not set
+CONFIG_SND_SPI=y
+CONFIG_SND_USB=y
+CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_USB_UA101=m
+CONFIG_SND_USB_CAIAQ=m
+CONFIG_SND_USB_CAIAQ_INPUT=y
+CONFIG_SND_USB_6FIRE=m
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_CACHE_LZO=y
+CONFIG_SND_OMAP_SOC=y
+CONFIG_SND_OMAP_SOC_MCBSP=y
+CONFIG_SND_OMAP_SOC_OVERO=y
+CONFIG_SND_OMAP_SOC_OMAP3EVM=y
+CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE=y
+CONFIG_SND_OMAP_SOC_ZOOM2=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+# CONFIG_SND_SOC_ALL_CODECS is not set
+CONFIG_SND_SOC_TWL4030=y
+# 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=y
+CONFIG_HID_ACRUX=m
+# CONFIG_HID_ACRUX_FF is not set
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+# CONFIG_HID_CANDO is not set
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+# CONFIG_HID_PRODIKEYS is not set
+CONFIG_HID_CYPRESS=y
+# CONFIG_HID_DRAGONRISE is not set
+CONFIG_HID_EMS_FF=m
+# CONFIG_HID_ELECOM is not set
+CONFIG_HID_EZKEY=y
+CONFIG_HID_KEYTOUCH=m
+# CONFIG_HID_KYE is not set
+CONFIG_HID_UCLOGIC=m
+CONFIG_HID_WALTOP=m
+CONFIG_HID_GYRATION=y
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
+CONFIG_HID_LCPOWER=m
+CONFIG_HID_LOGITECH=y
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+# CONFIG_LOGIG940_FF is not set
+# CONFIG_LOGIWII_FF is not set
+CONFIG_HID_MAGICMOUSE=m
+CONFIG_HID_MICROSOFT=y
+# CONFIG_HID_MOSART is not set
+CONFIG_HID_MONTEREY=y
+CONFIG_HID_MULTITOUCH=m
+CONFIG_HID_NTRIG=y
+# CONFIG_HID_ORTEK is not set
+CONFIG_HID_PANTHERLORD=y
+# CONFIG_PANTHERLORD_FF is not set
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_PICOLCD=m
+CONFIG_HID_PICOLCD_FB=y
+CONFIG_HID_PICOLCD_BACKLIGHT=y
+CONFIG_HID_PICOLCD_LEDS=y
+CONFIG_HID_QUANTA=m
+CONFIG_HID_ROCCAT=m
+CONFIG_HID_ROCCAT_COMMON=m
+CONFIG_HID_ROCCAT_ARVO=m
+CONFIG_HID_ROCCAT_KONE=m
+CONFIG_HID_ROCCAT_KONEPLUS=m
+CONFIG_HID_ROCCAT_KOVAPLUS=m
+# CONFIG_HID_ROCCAT_PYRA is not set
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_STANTUM=m
+CONFIG_HID_SUNPLUS=y
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+CONFIG_HID_TOPSEED=y
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_WACOM 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=y
+
+#
+# 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=y
+# 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=y
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+CONFIG_USB_EHCI_TT_NEWSCHED=y
+CONFIG_USB_EHCI_HCD_OMAP=y
+# 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_U132_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
+CONFIG_USB_MUSB_HDRC=y
+# CONFIG_USB_MUSB_TUSB6010 is not set
+CONFIG_USB_MUSB_OMAP2PLUS=y
+# CONFIG_USB_MUSB_AM35X is not set
+# CONFIG_USB_MUSB_HOST is not set
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+CONFIG_USB_MUSB_OTG=y
+CONFIG_USB_GADGET_MUSB_HDRC=y
+CONFIG_USB_MUSB_HDRC_HCD=y
+# CONFIG_MUSB_PIO_ONLY is not set
+CONFIG_USB_INVENTRA_DMA=y
+# CONFIG_USB_TI_CPPI_DMA is not set
+# CONFIG_USB_MUSB_DEBUG is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+CONFIG_USB_WDM=m
+CONFIG_USB_TMC=m
+
+#
+# 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_REALTEK=m
+# 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_STORAGE_ENE_UB6250=m
+CONFIG_USB_UAS=m
+# 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=m
+CONFIG_USB_EZUSB=y
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_AIRCABLE=m
+CONFIG_USB_SERIAL_ARK3116=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_CH341=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+# CONFIG_USB_SERIAL_CP210X is not set
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_FUNSOFT=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_IUU=m
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+CONFIG_USB_SERIAL_KEYSPAN_MPR=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19=y
+CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_MOS7720=m
+CONFIG_USB_SERIAL_MOS7840=m
+CONFIG_USB_SERIAL_MOTOROLA=m
+CONFIG_USB_SERIAL_NAVMAN=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_OTI6858=m
+CONFIG_USB_SERIAL_QCAUX=m
+# CONFIG_USB_SERIAL_QUALCOMM is not set
+CONFIG_USB_SERIAL_SPCP8X5=m
+CONFIG_USB_SERIAL_HP4X=m
+CONFIG_USB_SERIAL_SAFE=m
+# CONFIG_USB_SERIAL_SAFE_PADDED is not set
+CONFIG_USB_SERIAL_SAMBA=m
+CONFIG_USB_SERIAL_SIEMENS_MPI=m
+CONFIG_USB_SERIAL_SIERRAWIRELESS=m
+# CONFIG_USB_SERIAL_SYMBOL is not set
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+# CONFIG_USB_SERIAL_OPTION is not set
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_SERIAL_OPTICON=m
+CONFIG_USB_SERIAL_VIVOPAY_SERIAL=m
+CONFIG_USB_SERIAL_ZIO=m
+CONFIG_USB_SERIAL_SSU100=m
+CONFIG_USB_SERIAL_DEBUG=m
+
+#
+# USB Miscellaneous drivers
+#
+CONFIG_USB_EMI62=m
+CONFIG_USB_EMI26=m
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+CONFIG_USB_LEGOTOWER=m
+CONFIG_USB_LCD=m
+CONFIG_USB_LED=m
+CONFIG_USB_CYPRESS_CY7C63=m
+CONFIG_USB_CYTHERM=m
+CONFIG_USB_IDMOUSE=m
+CONFIG_USB_FTDI_ELAN=m
+# CONFIG_USB_APPLEDISPLAY is not set
+CONFIG_USB_SISUSBVGA=m
+CONFIG_USB_SISUSBVGA_CON=y
+CONFIG_USB_LD=m
+CONFIG_USB_TRANCEVIBRATOR=m
+# CONFIG_USB_IOWARRIOR is not set
+CONFIG_USB_TEST=m
+# CONFIG_USB_ISIGHTFW is not set
+CONFIG_USB_YUREX=m
+CONFIG_USB_ATM=m
+CONFIG_USB_SPEEDTOUCH=m
+CONFIG_USB_CXACRU=m
+CONFIG_USB_UEAGLEATM=m
+CONFIG_USB_XUSBATM=m
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_DEBUG_FS=y
+CONFIG_USB_GADGET_VBUS_DRAW=480
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_FUSB300 is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_R8A66597 is not set
+# CONFIG_USB_GADGET_PXA_U2O is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_AUDIO is not set
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_ETH_EEM is not set
+CONFIG_USB_G_NCM=m
+# CONFIG_USB_GADGETFS is not set
+CONFIG_USB_FUNCTIONFS=m
+# CONFIG_USB_FUNCTIONFS_ETH is not set
+CONFIG_USB_FUNCTIONFS_RNDIS=y
+# CONFIG_USB_FUNCTIONFS_GENERIC is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_MASS_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+# CONFIG_USB_G_MULTI is not set
+CONFIG_USB_G_HID=m
+CONFIG_USB_G_DBGP=m
+# CONFIG_USB_G_DBGP_PRINTK is not set
+CONFIG_USB_G_DBGP_SERIAL=y
+CONFIG_USB_G_WEBCAM=m
+
+#
+# OTG and related infrastructure
+#
+CONFIG_USB_OTG_UTILS=y
+CONFIG_USB_GPIO_VBUS=y
+# CONFIG_ISP1301_OMAP is not set
+# CONFIG_USB_ULPI is not set
+CONFIG_TWL4030_USB=y
+CONFIG_TWL6030_USB=m
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_UNSAFE_RESUME=y
+# CONFIG_MMC_CLKGATE 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=y
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_OMAP is not set
+CONFIG_MMC_OMAP_HS=y
+CONFIG_MMC_SPI=m
+# CONFIG_MMC_DW is not set
+CONFIG_MMC_USHC=m
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_LM3530 is not set
+# CONFIG_LEDS_PCA9532 is not set
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_GPIO_PLATFORM=y
+# CONFIG_LEDS_LP3944 is not set
+CONFIG_LEDS_LP5521=m
+CONFIG_LEDS_LP5523=m
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_DAC124S085 is not set
+CONFIG_LEDS_PWM=m
+CONFIG_LEDS_REGULATOR=m
+# CONFIG_LEDS_BD2802 is not set
+# CONFIG_LEDS_LT3593 is not set
+CONFIG_LEDS_TRIGGERS=y
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGER_TIMER=m
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=m
+CONFIG_LEDS_TRIGGER_GPIO=m
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=m
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
+CONFIG_NFC_DEVICES=y
+CONFIG_PN544_NFC=m
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+CONFIG_RTC_DRV_DS1307=y
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_DS3232 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_ISL12022 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+CONFIG_RTC_DRV_BQ32K=m
+CONFIG_RTC_DRV_TWL4030=m
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_DMADEVICES is not set
+CONFIG_TIMB_DMA=m
+CONFIG_DMA_ENGINE=y
+# CONFIG_AUXDISPLAY is not set
+CONFIG_UIO=m
+CONFIG_UIO_PDRV=m
+CONFIG_UIO_PDRV_GENIRQ=m
+CONFIG_STAGING=y
+# CONFIG_STAGING_EXCLUDE_BUILD is not set
+# CONFIG_VIDEO_TM6000 is not set
+# CONFIG_USB_IP_COMMON is not set
+CONFIG_W35UND=m
+CONFIG_PRISM2_USB=m
+CONFIG_ECHO=m
+CONFIG_BRCM80211=m
+CONFIG_BRCMFMAC=y
+# CONFIG_BRCMDBG is not set
+CONFIG_RT2870=m
+# CONFIG_COMEDI is not set
+# CONFIG_ASUS_OLED is not set
+CONFIG_R8712U=m
+CONFIG_R8712_AP=y
+# CONFIG_TRANZPORT is not set
+# CONFIG_POHMELFS is not set
+# CONFIG_LINE6_USB is not set
+# CONFIG_USB_SERIAL_QUATECH2 is not set
+# CONFIG_USB_SERIAL_QUATECH_USB2 is not set
+# CONFIG_VT6656 is not set
+# CONFIG_IIO is not set
+CONFIG_XVMALLOC=y
+CONFIG_ZRAM=m
+# CONFIG_ZRAM_DEBUG is not set
+# CONFIG_FB_SM7XX is not set
+# CONFIG_LIRC_STAGING is not set
+# CONFIG_EASYCAP is not set
+# CONFIG_TIDSPBRIDGE is not set
+# CONFIG_MACH_OMAP3_WESTBRIDGE_AST_PNAND_HAL is not set
+CONFIG_MACH_NO_WESTBRIDGE=y
+# CONFIG_ATH6K_LEGACY is not set
+CONFIG_USB_ENESTORAGE=m
+CONFIG_BCM_WIMAX=m
+CONFIG_FT1000=m
+CONFIG_FT1000_USB=m
+
+#
+# Speakup console speech
+#
+# CONFIG_SPEAKUP is not set
+CONFIG_TOUCHSCREEN_CLEARPAD_TM1217=m
+CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=m
+
+#
+# Altera FPGA firmware download module
+#
+# CONFIG_ALTERA_STAPL is not set
+CONFIG_CLKDEV_LOOKUP=y
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_XATTR=y
+# CONFIG_EXT4_FS_POSIX_ACL is not set
+# CONFIG_EXT4_FS_SECURITY is not set
+# CONFIG_EXT4_DEBUG is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_JBD2=y
+# CONFIG_JBD2_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+CONFIG_REISERFS_PROC_INFO=y
+CONFIG_REISERFS_FS_XATTR=y
+# CONFIG_REISERFS_FS_POSIX_ACL is not set
+# CONFIG_REISERFS_FS_SECURITY is not set
+CONFIG_JFS_FS=m
+# CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_SECURITY is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_XFS_FS=m
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_POSIX_ACL is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_DEBUG is not set
+CONFIG_GFS2_FS=m
+# CONFIG_GFS2_FS_LOCKING_DLM is not set
+CONFIG_OCFS2_FS=m
+CONFIG_OCFS2_FS_O2CB=m
+CONFIG_OCFS2_FS_USERSPACE_CLUSTER=m
+CONFIG_OCFS2_FS_STATS=y
+CONFIG_OCFS2_DEBUG_MASKLOG=y
+# CONFIG_OCFS2_DEBUG_FS is not set
+CONFIG_BTRFS_FS=m
+# CONFIG_BTRFS_FS_POSIX_ACL is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_EXPORTFS=y
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_FANOTIFY=y
+CONFIG_QUOTA=y
+# CONFIG_QUOTA_NETLINK_INTERFACE is not set
+CONFIG_PRINT_QUOTA_WARNING=y
+# CONFIG_QUOTA_DEBUG is not set
+CONFIG_QUOTA_TREE=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+CONFIG_AUTOFS4_FS=m
+CONFIG_FUSE_FS=m
+# CONFIG_CUSE is not set
+CONFIG_GENERIC_ACL=y
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+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=m
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_CONFIGFS_FS=m
+CONFIG_MISC_FILESYSTEMS=y
+CONFIG_ADFS_FS=m
+# CONFIG_ADFS_FS_RW is not set
+CONFIG_AFFS_FS=m
+# CONFIG_ECRYPT_FS is not set
+CONFIG_UNION_FS=m
+CONFIG_UNION_FS_XATTR=y
+# CONFIG_UNION_FS_DEBUG is not set
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_BEFS_FS=m
+# CONFIG_BEFS_DEBUG is not set
+CONFIG_BFS_FS=m
+CONFIG_EFS_FS=m
+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=y
+CONFIG_JFFS2_FS_XATTR=y
+CONFIG_JFFS2_FS_POSIX_ACL=y
+CONFIG_JFFS2_FS_SECURITY=y
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_LZO=y
+CONFIG_JFFS2_RTIME=y
+CONFIG_JFFS2_RUBIN=y
+# CONFIG_JFFS2_CMODE_NONE is not set
+# CONFIG_JFFS2_CMODE_PRIORITY is not set
+# CONFIG_JFFS2_CMODE_SIZE is not set
+CONFIG_JFFS2_CMODE_FAVOURLZO=y
+CONFIG_UBIFS_FS=y
+CONFIG_UBIFS_FS_XATTR=y
+CONFIG_UBIFS_FS_ADVANCED_COMPR=y
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+# CONFIG_UBIFS_FS_DEBUG is not set
+CONFIG_LOGFS=m
+CONFIG_CRAMFS=m
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_XATTR is not set
+CONFIG_SQUASHFS_LZO=y
+CONFIG_SQUASHFS_XZ=y
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+CONFIG_VXFS_FS=m
+CONFIG_MINIX_FS=m
+CONFIG_OMFS_FS=m
+CONFIG_HPFS_FS=m
+CONFIG_QNX4FS_FS=m
+CONFIG_ROMFS_FS=m
+CONFIG_ROMFS_BACKED_BY_BLOCK=y
+# CONFIG_ROMFS_BACKED_BY_MTD is not set
+# CONFIG_ROMFS_BACKED_BY_BOTH is not set
+CONFIG_ROMFS_ON_BLOCK=y
+CONFIG_PSTORE=y
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+# CONFIG_UFS_DEBUG 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=y
+# CONFIG_NFS_V4_1 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFS_USE_LEGACY_DNS is not set
+CONFIG_NFS_USE_KERNEL_DNS=y
+# CONFIG_NFS_USE_NEW_IDMAPPER is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_DEPRECATED=y
+CONFIG_NFSD_V2_ACL=y
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=m
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=m
+CONFIG_CEPH_FS=m
+CONFIG_CIFS=m
+CONFIG_CIFS_STATS=y
+CONFIG_CIFS_STATS2=y
+# CONFIG_CIFS_WEAK_PW_HASH is not set
+# CONFIG_CIFS_UPCALL is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_DFS_UPCALL is not set
+CONFIG_CIFS_EXPERIMENTAL=y
+CONFIG_NCP_FS=m
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+CONFIG_CODA_FS=m
+CONFIG_AFS_FS=m
+# CONFIG_AFS_DEBUG is not set
+CONFIG_9P_FS=m
+# CONFIG_9P_FS_POSIX_ACL 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=y
+CONFIG_MSDOS_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+# CONFIG_UNIXWARE_DISKLABEL is not set
+CONFIG_LDM_PARTITION=y
+CONFIG_LDM_DEBUG=y
+# 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=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=y
+CONFIG_DLM=m
+# CONFIG_DLM_DEBUG is not set
+
+#
+# Kernel hacking
+#
+CONFIG_PRINTK_TIME=y
+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# 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_SECTION_MISMATCH is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_LOCKUP_DETECTOR is not set
+# CONFIG_HARDLOCKUP_DETECTOR is not set
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_TEST_LIST_SORT is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_LKDTM is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_RING_BUFFER=y
+CONFIG_RING_BUFFER_ALLOW_SWAP=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_RING_BUFFER_BENCHMARK is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_ASYNC_RAID6_TEST is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_TEST_KSTRTOX is not set
+# CONFIG_STRICT_DEVMEM is not set
+CONFIG_ARM_UNWIND=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_LL is not set
+# CONFIG_OC_ETM is not set
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_DEBUG_PROC_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_XOR_BLOCKS=m
+CONFIG_ASYNC_CORE=m
+CONFIG_ASYNC_MEMCPY=m
+CONFIG_ASYNC_XOR=m
+CONFIG_ASYNC_PQ=m
+CONFIG_ASYNC_RAID6_RECOV=m
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD=m
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG=m
+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=m
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_CRYPTO_CRYPTD=m
+CONFIG_CRYPTO_AUTHENC=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Authenticated Encryption with Associated Data
+#
+CONFIG_CRYPTO_CCM=m
+CONFIG_CRYPTO_GCM=m
+CONFIG_CRYPTO_SEQIV=m
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_CTR=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=m
+CONFIG_CRYPTO_XCBC=m
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+CONFIG_CRYPTO_GHASH=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=y
+CONFIG_CRYPTO_RMD128=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_RMD256=m
+CONFIG_CRYPTO_RMD320=m
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CAMELLIA=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_FCRYPT=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_SALSA20=m
+CONFIG_CRYPTO_SEED=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_ZLIB is not set
+CONFIG_CRYPTO_LZO=y
+
+#
+# Random Number Generation
+#
+CONFIG_CRYPTO_ANSI_CPRNG=m
+CONFIG_CRYPTO_USER_API=m
+CONFIG_CRYPTO_USER_API_HASH=m
+CONFIG_CRYPTO_USER_API_SKCIPHER=m
+CONFIG_CRYPTO_HW=y
+CONFIG_CRYPTO_DEV_OMAP_SHAM=m
+CONFIG_CRYPTO_DEV_OMAP_AES=m
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_RAID6_PQ=m
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+CONFIG_CRC_T10DIF=y
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC32=y
+CONFIG_CRC7=y
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_XZ_DEC=y
+CONFIG_XZ_DEC_X86=y
+CONFIG_XZ_DEC_POWERPC=y
+CONFIG_XZ_DEC_IA64=y
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_ARMTHUMB=y
+CONFIG_XZ_DEC_SPARC=y
+CONFIG_XZ_DEC_BCJ=y
+CONFIG_XZ_DEC_TEST=m
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_XZ=y
+CONFIG_DECOMPRESS_LZO=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+CONFIG_BTREE=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
+CONFIG_AVERAGE=y
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0001-OMAP-DSS2-DSI-fix-use_sys_clk-highfreq.patch b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0001-OMAP-DSS2-DSI-fix-use_sys_clk-highfreq.patch
new file mode 100644
index 0000000000..248d3312f9
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0001-OMAP-DSS2-DSI-fix-use_sys_clk-highfreq.patch
@@ -0,0 +1,33 @@
+From 49958f1925489048aa5a6834f61d61c8551f8ec3 Mon Sep 17 00:00:00 2001
+From: Tomi Valkeinen <tomi.valkeinen@ti.com>
+Date: Thu, 7 Apr 2011 15:28:47 +0300
+Subject: [PATCH 01/28] OMAP: DSS2: DSI: fix use_sys_clk & highfreq
+
+use_sys_clk and highfreq fields in dsi.current_cinfo were never set.
+Luckily they weren't used anywhere so it didn't cause any problems.
+
+This patch fixes those fields and they are now set at the same time as
+the rest of the fields.
+
+Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
+---
+ drivers/video/omap2/dss/dsi.c | 3 +++
+ 1 files changed, 3 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
+index 0a7f1a4..8604153 100644
+--- a/drivers/video/omap2/dss/dsi.c
++++ b/drivers/video/omap2/dss/dsi.c
+@@ -1276,6 +1276,9 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo)
+
+ DSSDBGF();
+
++ dsi.current_cinfo.use_sys_clk = cinfo->use_sys_clk;
++ dsi.current_cinfo.highfreq = cinfo->highfreq;
++
+ dsi.current_cinfo.fint = cinfo->fint;
+ dsi.current_cinfo.clkin4ddr = cinfo->clkin4ddr;
+ dsi.current_cinfo.dsi_pll_hsdiv_dispc_clk =
+--
+1.6.6.1
+
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0002-OMAP-DSS2-DSI-fix-dsi_dump_clocks.patch b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0002-OMAP-DSS2-DSI-fix-dsi_dump_clocks.patch
new file mode 100644
index 0000000000..01fdd7276a
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0002-OMAP-DSS2-DSI-fix-dsi_dump_clocks.patch
@@ -0,0 +1,49 @@
+From ccf7f535d7e809e563812f1c4897bdb9a1ff9233 Mon Sep 17 00:00:00 2001
+From: Tomi Valkeinen <tomi.valkeinen@ti.com>
+Date: Mon, 4 Apr 2011 10:02:53 +0300
+Subject: [PATCH 02/28] OMAP: DSS2: DSI: fix dsi_dump_clocks()
+
+On OMAP4, reading DSI_PLL_CONFIGURATION2 register requires the L3 clock
+(CIO_CLK_ICG) to PLL. Currently dsi_dump_clocks() tries to read that
+register without enabling the L3 clock, leading to crash if DSI is not
+in use.
+
+The status of the bit being read from DSI_PLL_CONFIGURATION2 is
+available from dsi_clock_info->use_sys_clk, so we can avoid the whole
+problem by just using that.
+
+Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
+---
+ drivers/video/omap2/dss/dsi.c | 6 +-----
+ 1 files changed, 1 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
+index 8604153..1464ac4 100644
+--- a/drivers/video/omap2/dss/dsi.c
++++ b/drivers/video/omap2/dss/dsi.c
+@@ -1491,7 +1491,6 @@ void dsi_pll_uninit(void)
+
+ void dsi_dump_clocks(struct seq_file *s)
+ {
+- int clksel;
+ struct dsi_clock_info *cinfo = &dsi.current_cinfo;
+ enum dss_clk_source dispc_clk_src, dsi_clk_src;
+
+@@ -1500,13 +1499,10 @@ void dsi_dump_clocks(struct seq_file *s)
+
+ enable_clocks(1);
+
+- clksel = REG_GET(DSI_PLL_CONFIGURATION2, 11, 11);
+-
+ seq_printf(s, "- DSI PLL -\n");
+
+ seq_printf(s, "dsi pll source = %s\n",
+- clksel == 0 ?
+- "dss_sys_clk" : "pclkfree");
++ cinfo->use_sys_clk ? "dss_sys_clk" : "pclkfree");
+
+ seq_printf(s, "Fint\t\t%-16luregn %u\n", cinfo->fint, cinfo->regn);
+
+--
+1.6.6.1
+
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0003-OMAP2PLUS-DSS2-Fix-Return-correct-lcd-clock-source-f.patch b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0003-OMAP2PLUS-DSS2-Fix-Return-correct-lcd-clock-source-f.patch
new file mode 100644
index 0000000000..fb49a3efe6
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0003-OMAP2PLUS-DSS2-Fix-Return-correct-lcd-clock-source-f.patch
@@ -0,0 +1,43 @@
+From 2ffa7a6c3cafb4f2a48ae274b2952ad48ae78eeb Mon Sep 17 00:00:00 2001
+From: Archit Taneja <archit@ti.com>
+Date: Thu, 31 Mar 2011 13:23:35 +0530
+Subject: [PATCH 03/28] OMAP2PLUS: DSS2: Fix: Return correct lcd clock source for OMAP2/3
+
+dss.lcd_clk_source is set to the default value DSS_CLK_SRC_FCK at dss_init.
+For OMAP2 and OMAP3, the dss.lcd_clk_source should always be the same as
+dss.dispc_clk_source. The function dss_get_lcd_clk_source() always returns the
+default value DSS_CLK_SRC_FCK for OMAP2/3. This leads to wrong clock dumps when
+dispc_clk_source is not DSS_CLK_SRC_FCK.
+
+Correct this function to always return dss.dispc_clk_source for OMAP2/3.
+
+Signed-off-by: Archit Taneja <archit@ti.com>
+Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
+---
+ drivers/video/omap2/dss/dss.c | 10 ++++++++--
+ 1 files changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
+index 3f1fee6..c3b48a0 100644
+--- a/drivers/video/omap2/dss/dss.c
++++ b/drivers/video/omap2/dss/dss.c
+@@ -385,8 +385,14 @@ enum dss_clk_source dss_get_dsi_clk_source(void)
+
+ enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
+ {
+- int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1;
+- return dss.lcd_clk_source[ix];
++ if (dss_has_feature(FEAT_LCD_CLK_SRC)) {
++ int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1;
++ return dss.lcd_clk_source[ix];
++ } else {
++ /* LCD_CLK source is the same as DISPC_FCLK source for
++ * OMAP2 and OMAP3 */
++ return dss.dispc_clk_source;
++ }
+ }
+
+ /* calculate clock rates using dividers in cinfo */
+--
+1.6.6.1
+
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0004-OMAP-DSS-DSI-Fix-DSI-PLL-power-bug.patch b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0004-OMAP-DSS-DSI-Fix-DSI-PLL-power-bug.patch
new file mode 100644
index 0000000000..81f82e7caa
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0004-OMAP-DSS-DSI-Fix-DSI-PLL-power-bug.patch
@@ -0,0 +1,64 @@
+From ee251e5c35b1325d696df35d297f34a9ccd6f5af Mon Sep 17 00:00:00 2001
+From: Tomi Valkeinen <tomi.valkeinen@ti.com>
+Date: Fri, 15 Apr 2011 10:42:59 +0300
+Subject: [PATCH 04/28] OMAP: DSS: DSI: Fix DSI PLL power bug
+
+OMAP3630 has a HW bug causing DSI PLL power command POWER_ON_DIV (0x3)
+to not work properly. The bug prevents us from enabling DSI PLL power
+only to HS divider block.
+
+This patch adds a dss feature for the bug and converts POWER_ON_DIV
+requests to POWER_ON_ALL (0x2).
+
+Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
+---
+ drivers/video/omap2/dss/dsi.c | 5 +++++
+ drivers/video/omap2/dss/dss_features.c | 2 +-
+ drivers/video/omap2/dss/dss_features.h | 2 ++
+ 3 files changed, 8 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
+index 1464ac4..cbd9ca4 100644
+--- a/drivers/video/omap2/dss/dsi.c
++++ b/drivers/video/omap2/dss/dsi.c
+@@ -1059,6 +1059,11 @@ static int dsi_pll_power(enum dsi_pll_power_state state)
+ {
+ int t = 0;
+
++ /* DSI-PLL power command 0x3 is not working */
++ if (dss_has_feature(FEAT_DSI_PLL_PWR_BUG) &&
++ state == DSI_PLL_POWER_ON_DIV)
++ state = DSI_PLL_POWER_ON_ALL;
++
+ REG_FLD_MOD(DSI_CLK_CTRL, state, 31, 30); /* PLL_PWR_CMD */
+
+ /* PLL_PWR_STATUS */
+diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c
+index aa16222..8c50e18 100644
+--- a/drivers/video/omap2/dss/dss_features.c
++++ b/drivers/video/omap2/dss/dss_features.c
+@@ -271,7 +271,7 @@ static struct omap_dss_features omap3630_dss_features = {
+ FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
+ FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED |
+ FEAT_ROWREPEATENABLE | FEAT_LINEBUFFERSPLIT |
+- FEAT_RESIZECONF,
++ FEAT_RESIZECONF | FEAT_DSI_PLL_PWR_BUG,
+
+ .num_mgrs = 2,
+ .num_ovls = 3,
+diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h
+index 12e9c4e..37922ce 100644
+--- a/drivers/video/omap2/dss/dss_features.h
++++ b/drivers/video/omap2/dss/dss_features.h
+@@ -40,6 +40,8 @@ enum dss_feat_id {
+ /* Independent core clk divider */
+ FEAT_CORE_CLK_DIV = 1 << 11,
+ FEAT_LCD_CLK_SRC = 1 << 12,
++ /* DSI-PLL power command 0x3 is not working */
++ FEAT_DSI_PLL_PWR_BUG = 1 << 13,
+ };
+
+ /* DSS register field id */
+--
+1.6.6.1
+
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0005-OMAP-DSS2-fix-panel-Kconfig-dependencies.patch b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0005-OMAP-DSS2-fix-panel-Kconfig-dependencies.patch
new file mode 100644
index 0000000000..b1845e928f
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0005-OMAP-DSS2-fix-panel-Kconfig-dependencies.patch
@@ -0,0 +1,61 @@
+From c479d815f14b4b5ed7871660027d043a432968a8 Mon Sep 17 00:00:00 2001
+From: Tomi Valkeinen <tomi.valkeinen@ti.com>
+Date: Fri, 8 Apr 2011 09:30:27 +0300
+Subject: [PATCH 05/28] OMAP: DSS2: fix panel Kconfig dependencies
+
+All DPI panels were missing dependency to OMAP2_DSS_DPI. Add the
+dependency.
+
+Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
+---
+ drivers/video/omap2/displays/Kconfig | 9 +++++----
+ 1 files changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig
+index d18ad6b..609a280 100644
+--- a/drivers/video/omap2/displays/Kconfig
++++ b/drivers/video/omap2/displays/Kconfig
+@@ -3,6 +3,7 @@ menu "OMAP2/3 Display Device Drivers"
+
+ config PANEL_GENERIC_DPI
+ tristate "Generic DPI Panel"
++ depends on OMAP2_DSS_DPI
+ help
+ Generic DPI panel driver.
+ Supports DVI output for Beagle and OMAP3 SDP.
+@@ -11,20 +12,20 @@ config PANEL_GENERIC_DPI
+
+ config PANEL_LGPHILIPS_LB035Q02
+ tristate "LG.Philips LB035Q02 LCD Panel"
+- depends on OMAP2_DSS && SPI
++ depends on OMAP2_DSS_DPI && SPI
+ help
+ LCD Panel used on the Gumstix Overo Palo35
+
+ config PANEL_SHARP_LS037V7DW01
+ tristate "Sharp LS037V7DW01 LCD Panel"
+- depends on OMAP2_DSS
++ depends on OMAP2_DSS_DPI
+ select BACKLIGHT_CLASS_DEVICE
+ help
+ LCD Panel used in TI's SDP3430 and EVM boards
+
+ config PANEL_NEC_NL8048HL11_01B
+ tristate "NEC NL8048HL11-01B Panel"
+- depends on OMAP2_DSS
++ depends on OMAP2_DSS_DPI
+ help
+ This NEC NL8048HL11-01B panel is TFT LCD
+ used in the Zoom2/3/3630 sdp boards.
+@@ -37,7 +38,7 @@ config PANEL_TAAL
+
+ config PANEL_TPO_TD043MTEA1
+ tristate "TPO TD043MTEA1 LCD Panel"
+- depends on OMAP2_DSS && SPI
++ depends on OMAP2_DSS_DPI && SPI
+ help
+ LCD Panel used in OMAP3 Pandora
+
+--
+1.6.6.1
+
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0006-OMAP-DSS2-add-bootarg-for-selecting-svideo-or-compos.patch b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0006-OMAP-DSS2-add-bootarg-for-selecting-svideo-or-compos.patch
new file mode 100644
index 0000000000..4b89760749
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0006-OMAP-DSS2-add-bootarg-for-selecting-svideo-or-compos.patch
@@ -0,0 +1,75 @@
+From 661c19e763f0bda0a07bc64159c6b0c5f2f52b60 Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Tue, 19 Jan 2010 21:19:15 -0800
+Subject: [PATCH 06/28] OMAP: DSS2: add bootarg for selecting svideo or composite for tv output
+
+also add pal-16 and ntsc-16 omapfb.mode settings for 16bpp
+---
+ drivers/video/omap2/dss/venc.c | 22 ++++++++++++++++++++++
+ drivers/video/omap2/omapfb/omapfb-main.c | 10 +++++++++-
+ 2 files changed, 31 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
+index 8e35a5b..827723f 100644
+--- a/drivers/video/omap2/dss/venc.c
++++ b/drivers/video/omap2/dss/venc.c
+@@ -85,6 +85,11 @@
+ #define VENC_OUTPUT_TEST 0xC8
+ #define VENC_DAC_B__DAC_C 0xC8
+
++static char *tv_connection;
++
++module_param_named(tvcable, tv_connection, charp, 0);
++MODULE_PARM_DESC(tvcable, "TV connection type (svideo, composite)");
++
+ struct venc_config {
+ u32 f_control;
+ u32 vidout_ctrl;
+@@ -458,6 +463,23 @@ static int venc_panel_probe(struct omap_dss_device *dssdev)
+ {
+ dssdev->panel.timings = omap_dss_pal_timings;
+
++ /* Allow the TV output to be overriden */
++ if (tv_connection) {
++ if (strcmp(tv_connection, "svideo") == 0) {
++ printk(KERN_INFO
++ "omapdss: tv output is svideo.\n");
++ dssdev->phy.venc.type = OMAP_DSS_VENC_TYPE_SVIDEO;
++ } else if (strcmp(tv_connection, "composite") == 0) {
++ printk(KERN_INFO
++ "omapdss: tv output is composite.\n");
++ dssdev->phy.venc.type = OMAP_DSS_VENC_TYPE_COMPOSITE;
++ } else {
++ printk(KERN_INFO
++ "omapdss: unsupported output type'%s'.\n",
++ tv_connection);
++ }
++ }
++
+ return 0;
+ }
+
+diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
+index 505ec66..eaeded5 100644
+--- a/drivers/video/omap2/omapfb/omapfb-main.c
++++ b/drivers/video/omap2/omapfb/omapfb-main.c
+@@ -2036,7 +2036,15 @@ static int omapfb_mode_to_timings(const char *mode_str,
+ int r;
+
+ #ifdef CONFIG_OMAP2_DSS_VENC
+- if (strcmp(mode_str, "pal") == 0) {
++ if (strcmp(mode_str, "pal-16") == 0) {
++ *timings = omap_dss_pal_timings;
++ *bpp = 16;
++ return 0;
++ } else if (strcmp(mode_str, "ntsc-16") == 0) {
++ *timings = omap_dss_ntsc_timings;
++ *bpp = 16;
++ return 0;
++ } else if (strcmp(mode_str, "pal") == 0) {
+ *timings = omap_dss_pal_timings;
+ *bpp = 24;
+ return 0;
+--
+1.6.6.1
+
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0007-video-add-timings-for-hd720.patch b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0007-video-add-timings-for-hd720.patch
new file mode 100644
index 0000000000..f624d58a12
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0007-video-add-timings-for-hd720.patch
@@ -0,0 +1,27 @@
+From 14ea4d9f0f90726b653b42697043e73ef699b4ba Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Sat, 19 Dec 2009 06:52:43 -0800
+Subject: [PATCH 07/28] video: add timings for hd720
+
+---
+ drivers/video/modedb.c | 4 ++++
+ 1 files changed, 4 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c
+index 48c3ea8..b320a30 100644
+--- a/drivers/video/modedb.c
++++ b/drivers/video/modedb.c
+@@ -103,6 +103,10 @@ static const struct fb_videomode modedb[] = {
+ { NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6, 0,
+ FB_VMODE_NONINTERLACED },
+
++ /* 1280x720 @ 60 Hz, 45 kHz hsync, CEA 681-E Format 4 */
++ { "hd720", 60, 1280, 720, 13468, 220, 110, 20, 5, 40, 5, 0,
++ FB_VMODE_NONINTERLACED },
++
+ /* 1280x1024 @ 87 Hz interlaced, 51 kHz hsync */
+ { NULL, 87, 1280, 1024, 12500, 56, 16, 128, 1, 216, 12, 0,
+ FB_VMODE_INTERLACED },
+--
+1.6.6.1
+
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0008-drivers-net-smsc911x-return-ENODEV-if-device-is-not-.patch b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0008-drivers-net-smsc911x-return-ENODEV-if-device-is-not-.patch
new file mode 100644
index 0000000000..af14160d7e
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0008-drivers-net-smsc911x-return-ENODEV-if-device-is-not-.patch
@@ -0,0 +1,29 @@
+From b62ecb49cfe8978390b7c8848e13555c4c699b0f Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <sakoman@gmail.com>
+Date: Tue, 15 Dec 2009 15:17:44 -0800
+Subject: [PATCH 08/28] drivers: net: smsc911x: return ENODEV if device is not found
+
+Signed-off-by: Steve Sakoman <sakoman@gmail.com>
+---
+ drivers/net/smsc911x.c | 4 +++-
+ 1 files changed, 3 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c
+index 4b42ecc..5c1202b 100644
+--- a/drivers/net/smsc911x.c
++++ b/drivers/net/smsc911x.c
+@@ -2028,8 +2028,10 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
+ }
+
+ retval = smsc911x_init(dev);
+- if (retval < 0)
++ if (retval < 0) {
++ retval = -ENODEV;
+ goto out_unmap_io_3;
++ }
+
+ /* configure irq polarity and type before connecting isr */
+ if (pdata->config.irq_polarity == SMSC911X_IRQ_POLARITY_ACTIVE_HIGH)
+--
+1.6.6.1
+
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0009-drivers-input-touchscreen-ads7846-return-ENODEV-if-d.patch b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0009-drivers-input-touchscreen-ads7846-return-ENODEV-if-d.patch
new file mode 100644
index 0000000000..042ab44ad0
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0009-drivers-input-touchscreen-ads7846-return-ENODEV-if-d.patch
@@ -0,0 +1,47 @@
+From b1515f616ee48452a7cb2c5d0f31b1f8f4463f94 Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <sakoman@gmail.com>
+Date: Tue, 15 Dec 2009 15:24:10 -0800
+Subject: [PATCH 09/28] drivers: input: touchscreen: ads7846: return ENODEV if device is not found
+
+Signed-off-by: Steve Sakoman <sakoman@gmail.com>
+---
+ drivers/input/touchscreen/ads7846.c | 13 ++++++++++---
+ 1 files changed, 10 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
+index 1de1c19..097db10 100644
+--- a/drivers/input/touchscreen/ads7846.c
++++ b/drivers/input/touchscreen/ads7846.c
+@@ -1338,11 +1338,18 @@ static int __devinit ads7846_probe(struct spi_device *spi)
+ * the touchscreen, in case it's not connected.
+ */
+ if (ts->model == 7845)
+- ads7845_read12_ser(&spi->dev, PWRDOWN);
++ err = ads7845_read12_ser(&spi->dev, PWRDOWN);
+ else
+- (void) ads7846_read12_ser(&spi->dev,
++ err = ads7846_read12_ser(&spi->dev,
+ READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON);
+
++ /* if sample is all 0's or all 1's then there is no device on spi */
++ if ( (err == 0x000) || (err == 0xfff)) {
++ dev_info(&spi->dev, "no device detected, test read result was 0x%08X\n", err);
++ err = -ENODEV;
++ goto err_free_irq;
++ }
++
+ err = sysfs_create_group(&spi->dev.kobj, &ads784x_attr_group);
+ if (err)
+ goto err_remove_hwmon;
+@@ -1366,7 +1373,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
+ err_put_regulator:
+ regulator_put(ts->reg);
+ err_free_gpio:
+- if (!ts->get_pendown_state)
++ if (!ts->get_pendown_state && ts->gpio_pendown != -1)
+ gpio_free(ts->gpio_pendown);
+ err_cleanup_filter:
+ if (ts->filter_cleanup)
+--
+1.6.6.1
+
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0010-Revert-omap2_mcspi-Flush-posted-writes.patch b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0010-Revert-omap2_mcspi-Flush-posted-writes.patch
new file mode 100644
index 0000000000..f5265a342d
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0010-Revert-omap2_mcspi-Flush-posted-writes.patch
@@ -0,0 +1,25 @@
+From c2b7ff69cae57875b711eeb9cb6c97e7ba090c08 Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Thu, 3 Mar 2011 13:29:30 -0800
+Subject: [PATCH 10/28] Revert "omap2_mcspi: Flush posted writes"
+
+This reverts commit a330ce2001b290c59fe98c37e981683ef0a75fdf.
+---
+ drivers/spi/omap2_mcspi.c | 1 -
+ 1 files changed, 0 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c
+index 6f86ba0..6094be7 100644
+--- a/drivers/spi/omap2_mcspi.c
++++ b/drivers/spi/omap2_mcspi.c
+@@ -195,7 +195,6 @@ static inline void mcspi_write_chconf0(const struct spi_device *spi, u32 val)
+
+ cs->chconf0 = val;
+ mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, val);
+- mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
+ }
+
+ static void omap2_mcspi_set_dma_req(const struct spi_device *spi,
+--
+1.6.6.1
+
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0011-Revert-omap_hsmmc-improve-interrupt-synchronisation.patch b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0011-Revert-omap_hsmmc-improve-interrupt-synchronisation.patch
new file mode 100644
index 0000000000..7592bab28f
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0011-Revert-omap_hsmmc-improve-interrupt-synchronisation.patch
@@ -0,0 +1,482 @@
+From ed9bca69fdaa7edac3573e5ef3f011c7f7dc4898 Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Fri, 19 Nov 2010 15:11:19 -0800
+Subject: [PATCH 11/28] Revert "omap_hsmmc: improve interrupt synchronisation"
+
+This reverts commit b417577d3b9bbb06a4ddc9aa955af9bd503f7242.
+
+Conflicts:
+
+ drivers/mmc/host/omap_hsmmc.c
+---
+ drivers/mmc/host/omap_hsmmc.c | 267 ++++++++++++++++++++---------------------
+ 1 files changed, 128 insertions(+), 139 deletions(-)
+
+diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
+index 259ece0..15a023b 100644
+--- a/drivers/mmc/host/omap_hsmmc.c
++++ b/drivers/mmc/host/omap_hsmmc.c
+@@ -159,10 +159,12 @@ struct omap_hsmmc_host {
+ */
+ struct regulator *vcc;
+ struct regulator *vcc_aux;
++ struct semaphore sem;
+ struct work_struct mmc_carddetect_work;
+ void __iomem *base;
+ resource_size_t mapbase;
+ spinlock_t irq_lock; /* Prevent races with irq handler */
++ unsigned long flags;
+ unsigned int id;
+ unsigned int dma_len;
+ unsigned int dma_sg_idx;
+@@ -183,7 +185,6 @@ struct omap_hsmmc_host {
+ int protect_card;
+ int reqs_blocked;
+ int use_reg;
+- int req_in_progress;
+
+ struct omap_mmc_platform_data *pdata;
+ };
+@@ -556,32 +557,6 @@ static void omap_hsmmc_stop_clock(struct omap_hsmmc_host *host)
+ dev_dbg(mmc_dev(host->mmc), "MMC Clock is not stoped\n");
+ }
+
+-static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host,
+- struct mmc_command *cmd)
+-{
+- unsigned int irq_mask;
+-
+- if (host->use_dma)
+- irq_mask = INT_EN_MASK & ~(BRR_ENABLE | BWR_ENABLE);
+- else
+- irq_mask = INT_EN_MASK;
+-
+- /* Disable timeout for erases */
+- if (cmd->opcode == MMC_ERASE)
+- irq_mask &= ~DTO_ENABLE;
+-
+- OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
+- OMAP_HSMMC_WRITE(host->base, ISE, irq_mask);
+- OMAP_HSMMC_WRITE(host->base, IE, irq_mask);
+-}
+-
+-static void omap_hsmmc_disable_irq(struct omap_hsmmc_host *host)
+-{
+- OMAP_HSMMC_WRITE(host->base, ISE, 0);
+- OMAP_HSMMC_WRITE(host->base, IE, 0);
+- OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
+-}
+-
+ #ifdef CONFIG_PM
+
+ /*
+@@ -650,7 +625,9 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
+ && time_before(jiffies, timeout))
+ ;
+
+- omap_hsmmc_disable_irq(host);
++ OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
++ OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
++ OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
+
+ /* Do not initialize card-specific things if the power is off */
+ if (host->power_mode == MMC_POWER_OFF)
+@@ -753,8 +730,6 @@ static void send_init_stream(struct omap_hsmmc_host *host)
+ return;
+
+ disable_irq(host->irq);
+-
+- OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
+ OMAP_HSMMC_WRITE(host->base, CON,
+ OMAP_HSMMC_READ(host->base, CON) | INIT_STREAM);
+ OMAP_HSMMC_WRITE(host->base, CMD, INIT_STREAM_CMD);
+@@ -820,7 +795,17 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
+ mmc_hostname(host->mmc), cmd->opcode, cmd->arg);
+ host->cmd = cmd;
+
+- omap_hsmmc_enable_irq(host, cmd);
++ /*
++ * Clear status bits and enable interrupts
++ */
++ OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
++ OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
++
++ if (host->use_dma)
++ OMAP_HSMMC_WRITE(host->base, IE,
++ INT_EN_MASK & ~(BRR_ENABLE | BWR_ENABLE));
++ else
++ OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
+
+ host->response_busy = 0;
+ if (cmd->flags & MMC_RSP_PRESENT) {
+@@ -854,7 +839,13 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
+ if (host->use_dma)
+ cmdreg |= DMA_EN;
+
+- host->req_in_progress = 1;
++ /*
++ * In an interrupt context (i.e. STOP command), the spinlock is unlocked
++ * by the interrupt handler, otherwise (i.e. for a new request) it is
++ * unlocked here.
++ */
++ if (!in_interrupt())
++ spin_unlock_irqrestore(&host->irq_lock, host->flags);
+
+ OMAP_HSMMC_WRITE(host->base, ARG, cmd->arg);
+ OMAP_HSMMC_WRITE(host->base, CMD, cmdreg);
+@@ -869,23 +860,6 @@ omap_hsmmc_get_dma_dir(struct omap_hsmmc_host *host, struct mmc_data *data)
+ return DMA_FROM_DEVICE;
+ }
+
+-static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_request *mrq)
+-{
+- int dma_ch;
+-
+- spin_lock(&host->irq_lock);
+- host->req_in_progress = 0;
+- dma_ch = host->dma_ch;
+- spin_unlock(&host->irq_lock);
+-
+- omap_hsmmc_disable_irq(host);
+- /* Do not complete the request if DMA is still in progress */
+- if (mrq->data && host->use_dma && dma_ch != -1)
+- return;
+- host->mrq = NULL;
+- mmc_request_done(host->mmc, mrq);
+-}
+-
+ /*
+ * Notify the transfer complete to MMC core
+ */
+@@ -902,19 +876,25 @@ omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data)
+ return;
+ }
+
+- omap_hsmmc_request_done(host, mrq);
++ host->mrq = NULL;
++ mmc_request_done(host->mmc, mrq);
+ return;
+ }
+
+ host->data = NULL;
+
++ if (host->use_dma && host->dma_ch != -1)
++ dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len,
++ omap_hsmmc_get_dma_dir(host, data));
++
+ if (!data->error)
+ data->bytes_xfered += data->blocks * (data->blksz);
+ else
+ data->bytes_xfered = 0;
+
+ if (!data->stop) {
+- omap_hsmmc_request_done(host, data->mrq);
++ host->mrq = NULL;
++ mmc_request_done(host->mmc, data->mrq);
+ return;
+ }
+ omap_hsmmc_start_command(host, data->stop, NULL);
+@@ -940,8 +920,10 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd)
+ cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP10);
+ }
+ }
+- if ((host->data == NULL && !host->response_busy) || cmd->error)
+- omap_hsmmc_request_done(host, cmd->mrq);
++ if ((host->data == NULL && !host->response_busy) || cmd->error) {
++ host->mrq = NULL;
++ mmc_request_done(host->mmc, cmd->mrq);
++ }
+ }
+
+ /*
+@@ -949,19 +931,14 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd)
+ */
+ static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno)
+ {
+- int dma_ch;
+-
+ host->data->error = errno;
+
+- spin_lock(&host->irq_lock);
+- dma_ch = host->dma_ch;
+- host->dma_ch = -1;
+- spin_unlock(&host->irq_lock);
+-
+- if (host->use_dma && dma_ch != -1) {
++ if (host->use_dma && host->dma_ch != -1) {
+ dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, host->dma_len,
+ omap_hsmmc_get_dma_dir(host, host->data));
+- omap_free_dma(dma_ch);
++ omap_free_dma(host->dma_ch);
++ host->dma_ch = -1;
++ up(&host->sem);
+ }
+ host->data = NULL;
+ }
+@@ -1034,21 +1011,28 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host,
+ __func__);
+ }
+
+-static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
++/*
++ * MMC controller IRQ handler
++ */
++static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
+ {
++ struct omap_hsmmc_host *host = dev_id;
+ struct mmc_data *data;
+- int end_cmd = 0, end_trans = 0;
+-
+- if (!host->req_in_progress) {
+- do {
+- OMAP_HSMMC_WRITE(host->base, STAT, status);
+- /* Flush posted write */
+- status = OMAP_HSMMC_READ(host->base, STAT);
+- } while (status & INT_EN_MASK);
+- return;
++ int end_cmd = 0, end_trans = 0, status;
++
++ spin_lock(&host->irq_lock);
++
++ if (host->mrq == NULL) {
++ OMAP_HSMMC_WRITE(host->base, STAT,
++ OMAP_HSMMC_READ(host->base, STAT));
++ /* Flush posted write */
++ OMAP_HSMMC_READ(host->base, STAT);
++ spin_unlock(&host->irq_lock);
++ return IRQ_HANDLED;
+ }
+
+ data = host->data;
++ status = OMAP_HSMMC_READ(host->base, STAT);
+ dev_dbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
+
+ if (status & ERR) {
+@@ -1101,27 +1085,15 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
+ }
+
+ OMAP_HSMMC_WRITE(host->base, STAT, status);
++ /* Flush posted write */
++ OMAP_HSMMC_READ(host->base, STAT);
+
+ if (end_cmd || ((status & CC) && host->cmd))
+ omap_hsmmc_cmd_done(host, host->cmd);
+ if ((end_trans || (status & TC)) && host->mrq)
+ omap_hsmmc_xfer_done(host, data);
+-}
+-
+-/*
+- * MMC controller IRQ handler
+- */
+-static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
+-{
+- struct omap_hsmmc_host *host = dev_id;
+- int status;
+
+- status = OMAP_HSMMC_READ(host->base, STAT);
+- do {
+- omap_hsmmc_do_irq(host, status);
+- /* Flush posted write */
+- status = OMAP_HSMMC_READ(host->base, STAT);
+- } while (status & INT_EN_MASK);
++ spin_unlock(&host->irq_lock);
+
+ return IRQ_HANDLED;
+ }
+@@ -1316,11 +1288,9 @@ static void omap_hsmmc_config_dma_params(struct omap_hsmmc_host *host,
+ /*
+ * DMA call back function
+ */
+-static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data)
++static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *data)
+ {
+- struct omap_hsmmc_host *host = cb_data;
+- struct mmc_data *data = host->mrq->data;
+- int dma_ch, req_in_progress;
++ struct omap_hsmmc_host *host = data;
+
+ if (!(ch_status & OMAP_DMA_BLOCK_IRQ)) {
+ dev_warn(mmc_dev(host->mmc), "unexpected dma status %x\n",
+@@ -1328,38 +1298,24 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data)
+ return;
+ }
+
+- spin_lock(&host->irq_lock);
+- if (host->dma_ch < 0) {
+- spin_unlock(&host->irq_lock);
++ if (host->dma_ch < 0)
+ return;
+- }
+
+ host->dma_sg_idx++;
+ if (host->dma_sg_idx < host->dma_len) {
+ /* Fire up the next transfer. */
+- omap_hsmmc_config_dma_params(host, data,
+- data->sg + host->dma_sg_idx);
+- spin_unlock(&host->irq_lock);
++ omap_hsmmc_config_dma_params(host, host->data,
++ host->data->sg + host->dma_sg_idx);
+ return;
+ }
+
+- dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len,
+- omap_hsmmc_get_dma_dir(host, data));
+-
+- req_in_progress = host->req_in_progress;
+- dma_ch = host->dma_ch;
++ omap_free_dma(host->dma_ch);
+ host->dma_ch = -1;
+- spin_unlock(&host->irq_lock);
+-
+- omap_free_dma(dma_ch);
+-
+- /* If DMA has finished after TC, complete the request */
+- if (!req_in_progress) {
+- struct mmc_request *mrq = host->mrq;
+-
+- host->mrq = NULL;
+- mmc_request_done(host->mmc, mrq);
+- }
++ /*
++ * DMA Callback: run in interrupt context.
++ * mutex_unlock will throw a kernel warning if used.
++ */
++ up(&host->sem);
+ }
+
+ /*
+@@ -1368,7 +1324,7 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data)
+ static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host,
+ struct mmc_request *req)
+ {
+- int dma_ch = 0, ret = 0, i;
++ int dma_ch = 0, ret = 0, err = 1, i;
+ struct mmc_data *data = req->data;
+
+ /* Sanity check: all the SG entries must be aligned by block size. */
+@@ -1385,7 +1341,23 @@ static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host,
+ */
+ return -EINVAL;
+
+- BUG_ON(host->dma_ch != -1);
++ /*
++ * If for some reason the DMA transfer is still active,
++ * we wait for timeout period and free the dma
++ */
++ if (host->dma_ch != -1) {
++ set_current_state(TASK_UNINTERRUPTIBLE);
++ schedule_timeout(100);
++ if (down_trylock(&host->sem)) {
++ omap_free_dma(host->dma_ch);
++ host->dma_ch = -1;
++ up(&host->sem);
++ return err;
++ }
++ } else {
++ if (down_trylock(&host->sem))
++ return err;
++ }
+
+ ret = omap_request_dma(omap_hsmmc_get_dma_sync_dev(host, data),
+ "MMC/SD", omap_hsmmc_dma_cb, host, &dma_ch);
+@@ -1485,27 +1457,37 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
+ struct omap_hsmmc_host *host = mmc_priv(mmc);
+ int err;
+
+- BUG_ON(host->req_in_progress);
+- BUG_ON(host->dma_ch != -1);
+- if (host->protect_card) {
+- if (host->reqs_blocked < 3) {
+- /*
+- * Ensure the controller is left in a consistent
+- * state by resetting the command and data state
+- * machines.
+- */
+- omap_hsmmc_reset_controller_fsm(host, SRD);
+- omap_hsmmc_reset_controller_fsm(host, SRC);
+- host->reqs_blocked += 1;
+- }
+- req->cmd->error = -EBADF;
+- if (req->data)
+- req->data->error = -EBADF;
+- req->cmd->retries = 0;
+- mmc_request_done(mmc, req);
+- return;
+- } else if (host->reqs_blocked)
+- host->reqs_blocked = 0;
++ /*
++ * Prevent races with the interrupt handler because of unexpected
++ * interrupts, but not if we are already in interrupt context i.e.
++ * retries.
++ */
++ if (!in_interrupt()) {
++ spin_lock_irqsave(&host->irq_lock, host->flags);
++ /*
++ * Protect the card from I/O if there is a possibility
++ * it can be removed.
++ */
++ if (host->protect_card) {
++ if (host->reqs_blocked < 3) {
++ /*
++ * Ensure the controller is left in a consistent
++ * state by resetting the command and data state
++ * machines.
++ */
++ omap_hsmmc_reset_controller_fsm(host, SRD);
++ omap_hsmmc_reset_controller_fsm(host, SRC);
++ host->reqs_blocked += 1;
++ }
++ req->cmd->error = -EBADF;
++ if (req->data)
++ req->data->error = -EBADF;
++ spin_unlock_irqrestore(&host->irq_lock, host->flags);
++ mmc_request_done(mmc, req);
++ return;
++ } else if (host->reqs_blocked)
++ host->reqs_blocked = 0;
++ }
+ WARN_ON(host->mrq != NULL);
+ host->mrq = req;
+ err = omap_hsmmc_prepare_data(host, req);
+@@ -1514,6 +1496,8 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
+ if (req->data)
+ req->data->error = err;
+ host->mrq = NULL;
++ if (!in_interrupt())
++ spin_unlock_irqrestore(&host->irq_lock, host->flags);
+ mmc_request_done(mmc, req);
+ return;
+ }
+@@ -2093,6 +2077,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
+ mmc->f_min = 400000;
+ mmc->f_max = 52000000;
+
++ sema_init(&host->sem, 1);
+ spin_lock_init(&host->irq_lock);
+
+ host->iclk = clk_get(&pdev->dev, "ick");
+@@ -2235,7 +2220,8 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
+ pdata->resume = omap_hsmmc_resume_cdirq;
+ }
+
+- omap_hsmmc_disable_irq(host);
++ OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
++ OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
+
+ mmc_host_lazy_disable(host->mmc);
+
+@@ -2356,7 +2342,10 @@ static int omap_hsmmc_suspend(struct device *dev)
+ ret = mmc_suspend_host(host->mmc);
+ mmc_host_enable(host->mmc);
+ if (ret == 0) {
+- omap_hsmmc_disable_irq(host);
++ OMAP_HSMMC_WRITE(host->base, ISE, 0);
++ OMAP_HSMMC_WRITE(host->base, IE, 0);
++
++
+ OMAP_HSMMC_WRITE(host->base, HCTL,
+ OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP);
+ mmc_host_disable(host->mmc);
+--
+1.6.6.1
+
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0012-Don-t-turn-SDIO-cards-off-to-save-power.-Doing-so-wi.patch b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0012-Don-t-turn-SDIO-cards-off-to-save-power.-Doing-so-wi.patch
new file mode 100644
index 0000000000..f0a3aa45f0
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0012-Don-t-turn-SDIO-cards-off-to-save-power.-Doing-so-wi.patch
@@ -0,0 +1,52 @@
+From 1d73698debdf57f9da6c3312239459c43278e064 Mon Sep 17 00:00:00 2001
+From: David Vrabel <david.vrabel@csr.com>
+Date: Fri, 2 Apr 2010 08:41:47 -0700
+Subject: [PATCH 12/28] Don't turn SDIO cards off to save power. Doing so will lose all
+ internal state in the card.
+
+Signed-off-by: David Vrabel <david.vrabel@csr.com>
+---
+ drivers/mmc/host/omap_hsmmc.c | 12 ++++++++----
+ 1 files changed, 8 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
+index 15a023b..83f93ab 100644
+--- a/drivers/mmc/host/omap_hsmmc.c
++++ b/drivers/mmc/host/omap_hsmmc.c
+@@ -29,6 +29,7 @@
+ #include <linux/mmc/host.h>
+ #include <linux/mmc/core.h>
+ #include <linux/mmc/mmc.h>
++#include <linux/mmc/card.h>
+ #include <linux/io.h>
+ #include <linux/semaphore.h>
+ #include <linux/gpio.h>
+@@ -1760,8 +1761,12 @@ static int omap_hsmmc_sleep_to_off(struct omap_hsmmc_host *host)
+ mmc_slot(host).card_detect ||
+ (mmc_slot(host).get_cover_state &&
+ mmc_slot(host).get_cover_state(host->dev, host->slot_id)))) {
+- mmc_release_host(host->mmc);
+- return 0;
++ goto out;
++ }
++
++ /* Don't turn SDIO cards off. */
++ if (host->mmc->card && mmc_card_sdio(host->mmc->card)) {
++ goto out;
+ }
+
+ mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
+@@ -1772,9 +1777,8 @@ static int omap_hsmmc_sleep_to_off(struct omap_hsmmc_host *host)
+ host->dpm_state == CARDSLEEP ? "CARDSLEEP" : "REGSLEEP");
+
+ host->dpm_state = OFF;
+-
++out:
+ mmc_release_host(host->mmc);
+-
+ return 0;
+ }
+
+--
+1.6.6.1
+
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0013-Enable-the-use-of-SDIO-card-interrupts.patch b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0013-Enable-the-use-of-SDIO-card-interrupts.patch
new file mode 100644
index 0000000000..f272276638
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0013-Enable-the-use-of-SDIO-card-interrupts.patch
@@ -0,0 +1,288 @@
+From bb4c074079c12d808367c8666cedcbba1dc456cc Mon Sep 17 00:00:00 2001
+From: David Vrabel <david.vrabel@csr.com>
+Date: Fri, 2 Apr 2010 08:42:22 -0700
+Subject: [PATCH 13/28] Enable the use of SDIO card interrupts.
+
+FCLK must be enabled while SDIO interrupts are enabled or the MMC
+module won't wake-up (even though ENAWAKEUP in SYSCONFIG and IWE in
+HTCL have been set). Enabling the MMC module to wake-up would require
+configuring the MMC module (and the mmci_dat[1] GPIO when the CORE
+power domain is OFF) as wake-up sources in the PRCM.
+
+The writes to STAT and ISE when starting a command are unnecessary and
+have been removed.
+
+Signed-off-by: David Vrabel <david.vrabel@csr.com>
+---
+ drivers/mmc/host/omap_hsmmc.c | 118 +++++++++++++++++++++++++++++------------
+ 1 files changed, 83 insertions(+), 35 deletions(-)
+
+diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
+index 83f93ab..d57686c 100644
+--- a/drivers/mmc/host/omap_hsmmc.c
++++ b/drivers/mmc/host/omap_hsmmc.c
+@@ -67,6 +67,7 @@
+ #define SDVS_MASK 0x00000E00
+ #define SDVSCLR 0xFFFFF1FF
+ #define SDVSDET 0x00000400
++#define ENAWAKEUP (1 << 2)
+ #define AUTOIDLE 0x1
+ #define SDBP (1 << 8)
+ #define DTO 0xe
+@@ -77,10 +78,13 @@
+ #define CLKD_SHIFT 6
+ #define DTO_MASK 0x000F0000
+ #define DTO_SHIFT 16
++#define CIRQ_ENABLE (1 << 8)
+ #define INT_EN_MASK 0x307F0033
+ #define BWR_ENABLE (1 << 4)
+ #define BRR_ENABLE (1 << 5)
+ #define DTO_ENABLE (1 << 20)
++#define CTPL (1 << 11)
++#define CLKEXTFREE (1 << 16)
+ #define INIT_STREAM (1 << 1)
+ #define DP_SELECT (1 << 21)
+ #define DDIR (1 << 4)
+@@ -88,10 +92,12 @@
+ #define MSBS (1 << 5)
+ #define BCE (1 << 1)
+ #define FOUR_BIT (1 << 1)
++#define IWE (1 << 24)
+ #define DW8 (1 << 5)
+ #define CC 0x1
+ #define TC 0x02
+ #define OD 0x1
++#define CIRQ (1 << 8)
+ #define ERR (1 << 15)
+ #define CMD_TIMEOUT (1 << 16)
+ #define DATA_TIMEOUT (1 << 20)
+@@ -186,6 +192,7 @@ struct omap_hsmmc_host {
+ int protect_card;
+ int reqs_blocked;
+ int use_reg;
++ int sdio_int;
+
+ struct omap_mmc_platform_data *pdata;
+ };
+@@ -598,7 +605,7 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
+ ;
+
+ OMAP_HSMMC_WRITE(host->base, SYSCONFIG,
+- OMAP_HSMMC_READ(host->base, SYSCONFIG) | AUTOIDLE);
++ OMAP_HSMMC_READ(host->base, SYSCONFIG) | AUTOIDLE | ENAWAKEUP);
+
+ if (host->id == OMAP_MMC1_DEVID) {
+ if (host->power_mode != MMC_POWER_OFF &&
+@@ -613,7 +620,7 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
+ }
+
+ OMAP_HSMMC_WRITE(host->base, HCTL,
+- OMAP_HSMMC_READ(host->base, HCTL) | hctl);
++ OMAP_HSMMC_READ(host->base, HCTL) | hctl | IWE);
+
+ OMAP_HSMMC_WRITE(host->base, CAPA,
+ OMAP_HSMMC_READ(host->base, CAPA) | capa);
+@@ -627,7 +634,7 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
+ ;
+
+ OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
+- OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
++ OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK | CIRQ);
+ OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
+
+ /* Do not initialize card-specific things if the power is off */
+@@ -791,22 +798,19 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
+ struct mmc_data *data)
+ {
+ int cmdreg = 0, resptype = 0, cmdtype = 0;
++ int int_en_mask = INT_EN_MASK;
+
+ dev_dbg(mmc_dev(host->mmc), "%s: CMD%d, argument 0x%08x\n",
+ mmc_hostname(host->mmc), cmd->opcode, cmd->arg);
+ host->cmd = cmd;
+
+- /*
+- * Clear status bits and enable interrupts
+- */
+- OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
+- OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
+-
+ if (host->use_dma)
+- OMAP_HSMMC_WRITE(host->base, IE,
+- INT_EN_MASK & ~(BRR_ENABLE | BWR_ENABLE));
+- else
+- OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
++ int_en_mask &= ~(BRR_ENABLE | BWR_ENABLE);
++
++ if (host->sdio_int)
++ int_en_mask |= CIRQ;
++
++ OMAP_HSMMC_WRITE(host->base, IE, int_en_mask);
+
+ host->response_busy = 0;
+ if (cmd->flags & MMC_RSP_PRESENT) {
+@@ -1019,23 +1023,26 @@ static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
+ {
+ struct omap_hsmmc_host *host = dev_id;
+ struct mmc_data *data;
+- int end_cmd = 0, end_trans = 0, status;
++ u32 status;
++ int end_cmd = 0, end_trans = 0;
++ bool card_irq = false;
+
+ spin_lock(&host->irq_lock);
+
+- if (host->mrq == NULL) {
+- OMAP_HSMMC_WRITE(host->base, STAT,
+- OMAP_HSMMC_READ(host->base, STAT));
+- /* Flush posted write */
+- OMAP_HSMMC_READ(host->base, STAT);
+- spin_unlock(&host->irq_lock);
+- return IRQ_HANDLED;
+- }
+-
+- data = host->data;
+ status = OMAP_HSMMC_READ(host->base, STAT);
++ OMAP_HSMMC_WRITE(host->base, STAT, status);
++ OMAP_HSMMC_READ(host->base, STAT); /* Flush posted write. */
++
+ dev_dbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
+
++ if (status & CIRQ)
++ card_irq = true;
++
++ if (host->mrq == NULL)
++ goto out;
++
++ data = host->data;
++
+ if (status & ERR) {
+ #ifdef CONFIG_MMC_DEBUG
+ omap_hsmmc_report_irq(host, status);
+@@ -1085,17 +1092,16 @@ static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
+ }
+ }
+
+- OMAP_HSMMC_WRITE(host->base, STAT, status);
+- /* Flush posted write */
+- OMAP_HSMMC_READ(host->base, STAT);
+-
+ if (end_cmd || ((status & CC) && host->cmd))
+ omap_hsmmc_cmd_done(host, host->cmd);
+ if ((end_trans || (status & TC)) && host->mrq)
+ omap_hsmmc_xfer_done(host, data);
+-
++out:
+ spin_unlock(&host->irq_lock);
+
++ if (card_irq)
++ mmc_signal_sdio_irq(host->mmc);
++
+ return IRQ_HANDLED;
+ }
+
+@@ -1643,6 +1649,47 @@ static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card)
+ mmc_slot(host).init_card(card);
+ }
+
++static void omap_hsmmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
++{
++ struct omap_hsmmc_host *host = mmc_priv(mmc);
++ u32 ie, con;
++ unsigned long flags;
++
++ spin_lock_irqsave(&host->irq_lock, flags);
++
++ /*
++ * When interrupts are enabled, CTPL must be set to enable
++ * DAT1 input buffer (or the card interrupt is always
++ * asserted) and FCLK must be enabled as wake-up does not
++ * work. Take care to disable FCLK after all the register
++ * accesses as they might not complete if FCLK is off.
++ *
++ * FIXME: if the MMC module (and the mmci_dat[1] GPIO when the
++ * CORE power domain is OFF) are configured as a wake-up
++ * sources in the PRCM, then FCLK could be switched off. This
++ * might add too much latency.
++ */
++ con = OMAP_HSMMC_READ(host->base, CON);
++ ie = OMAP_HSMMC_READ(host->base, IE);
++ if (enable) {
++ clk_enable(host->fclk);
++ ie |= CIRQ_ENABLE;
++ con |= CTPL | CLKEXTFREE;
++ host->sdio_int = 1;
++ } else {
++ ie &= ~CIRQ_ENABLE;
++ con &= ~(CTPL | CLKEXTFREE);
++ host->sdio_int = 0;
++ }
++ OMAP_HSMMC_WRITE(host->base, CON, con);
++ OMAP_HSMMC_WRITE(host->base, IE, ie);
++ OMAP_HSMMC_READ(host->base, IE); /* flush posted write */
++ if (!enable)
++ clk_disable(host->fclk);
++
++ spin_unlock_irqrestore(&host->irq_lock, flags);
++}
++
+ static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host)
+ {
+ u32 hctl, capa, value;
+@@ -1657,14 +1704,14 @@ static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host)
+ }
+
+ value = OMAP_HSMMC_READ(host->base, HCTL) & ~SDVS_MASK;
+- OMAP_HSMMC_WRITE(host->base, HCTL, value | hctl);
++ OMAP_HSMMC_WRITE(host->base, HCTL, value | hctl | IWE);
+
+ value = OMAP_HSMMC_READ(host->base, CAPA);
+ OMAP_HSMMC_WRITE(host->base, CAPA, value | capa);
+
+ /* Set the controller to AUTO IDLE mode */
+ value = OMAP_HSMMC_READ(host->base, SYSCONFIG);
+- OMAP_HSMMC_WRITE(host->base, SYSCONFIG, value | AUTOIDLE);
++ OMAP_HSMMC_WRITE(host->base, SYSCONFIG, value | AUTOIDLE | ENAWAKEUP);
+
+ /* Set SD bus power bit */
+ set_sd_bus_power(host);
+@@ -1918,7 +1965,7 @@ static const struct mmc_host_ops omap_hsmmc_ops = {
+ .get_cd = omap_hsmmc_get_cd,
+ .get_ro = omap_hsmmc_get_ro,
+ .init_card = omap_hsmmc_init_card,
+- /* NYET -- enable_sdio_irq */
++ .enable_sdio_irq = omap_hsmmc_enable_sdio_irq,
+ };
+
+ static const struct mmc_host_ops omap_hsmmc_ps_ops = {
+@@ -1929,7 +1976,7 @@ static const struct mmc_host_ops omap_hsmmc_ps_ops = {
+ .get_cd = omap_hsmmc_get_cd,
+ .get_ro = omap_hsmmc_get_ro,
+ .init_card = omap_hsmmc_init_card,
+- /* NYET -- enable_sdio_irq */
++ .enable_sdio_irq = omap_hsmmc_enable_sdio_irq,
+ };
+
+ #ifdef CONFIG_DEBUG_FS
+@@ -2145,7 +2192,8 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
+ mmc->max_seg_size = mmc->max_req_size;
+
+ mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
+- MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
++ MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE |
++ MMC_CAP_SDIO_IRQ;
+
+ mmc->caps |= mmc_slot(host).caps;
+ if (mmc->caps & MMC_CAP_8_BIT_DATA)
+@@ -2224,7 +2272,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
+ pdata->resume = omap_hsmmc_resume_cdirq;
+ }
+
+- OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
++ OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK | CIRQ);
+ OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
+
+ mmc_host_lazy_disable(host->mmc);
+--
+1.6.6.1
+
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0014-soc-codecs-Enable-audio-capture-by-default-for-twl40.patch b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0014-soc-codecs-Enable-audio-capture-by-default-for-twl40.patch
new file mode 100644
index 0000000000..12243d60c0
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0014-soc-codecs-Enable-audio-capture-by-default-for-twl40.patch
@@ -0,0 +1,27 @@
+From cee637c9d2b877dd40c5fc8c42dc70a21adb454b Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Thu, 17 Dec 2009 12:45:20 -0800
+Subject: [PATCH 14/28] soc: codecs: Enable audio capture by default for twl4030
+
+---
+ sound/soc/codecs/twl4030.c | 4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
+index 575238d..bd51f72 100644
+--- a/sound/soc/codecs/twl4030.c
++++ b/sound/soc/codecs/twl4030.c
+@@ -56,8 +56,8 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
+ 0x00, /* REG_OPTION (0x2) */
+ 0x00, /* REG_UNKNOWN (0x3) */
+ 0x00, /* REG_MICBIAS_CTL (0x4) */
+- 0x00, /* REG_ANAMICL (0x5) */
+- 0x00, /* REG_ANAMICR (0x6) */
++ 0x34, /* REG_ANAMICL (0x5) */
++ 0x14, /* REG_ANAMICR (0x6) */
+ 0x00, /* REG_AVADC_CTL (0x7) */
+ 0x00, /* REG_ADCMICSEL (0x8) */
+ 0x00, /* REG_DIGMIXING (0x9) */
+--
+1.6.6.1
+
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0015-soc-codecs-twl4030-Turn-on-mic-bias-by-default.patch b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0015-soc-codecs-twl4030-Turn-on-mic-bias-by-default.patch
new file mode 100644
index 0000000000..b3fa02ca21
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0015-soc-codecs-twl4030-Turn-on-mic-bias-by-default.patch
@@ -0,0 +1,25 @@
+From 19fbeb71b9576ecdefa7809980aa3f0eecda408c Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Wed, 29 Dec 2010 11:39:16 -0800
+Subject: [PATCH 15/28] soc: codecs: twl4030: Turn on mic bias by default
+
+---
+ sound/soc/codecs/twl4030.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
+index bd51f72..8949773 100644
+--- a/sound/soc/codecs/twl4030.c
++++ b/sound/soc/codecs/twl4030.c
+@@ -55,7 +55,7 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
+ 0x00, /* REG_CODEC_MODE (0x1) */
+ 0x00, /* REG_OPTION (0x2) */
+ 0x00, /* REG_UNKNOWN (0x3) */
+- 0x00, /* REG_MICBIAS_CTL (0x4) */
++ 0x03, /* REG_MICBIAS_CTL (0x4) */
+ 0x34, /* REG_ANAMICL (0x5) */
+ 0x14, /* REG_ANAMICR (0x6) */
+ 0x00, /* REG_AVADC_CTL (0x7) */
+--
+1.6.6.1
+
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0016-RTC-add-support-for-backup-battery-recharge.patch b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0016-RTC-add-support-for-backup-battery-recharge.patch
new file mode 100644
index 0000000000..55673b37ab
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0016-RTC-add-support-for-backup-battery-recharge.patch
@@ -0,0 +1,55 @@
+From 1c679da3fc28bd358c79b6fae05de81c9b84a681 Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Thu, 4 Feb 2010 12:26:22 -0800
+Subject: [PATCH 16/28] RTC: add support for backup battery recharge
+
+---
+ drivers/rtc/rtc-twl.c | 25 +++++++++++++++++++++++++
+ 1 files changed, 25 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c
+index f9a2799..713b8ea 100644
+--- a/drivers/rtc/rtc-twl.c
++++ b/drivers/rtc/rtc-twl.c
+@@ -30,6 +30,23 @@
+
+ #include <linux/i2c/twl.h>
+
++/*
++ * PM_RECEIVER block register offsets (use TWL4030_MODULE_PM_RECEIVER)
++ */
++#define REG_BB_CFG 0x12
++
++/* PM_RECEIVER BB_CFG bitfields */
++#define BIT_PM_RECEIVER_BB_CFG_BBCHEN 0x10
++#define BIT_PM_RECEIVER_BB_CFG_BBSEL 0x0C
++#define BIT_PM_RECEIVER_BB_CFG_BBSEL_2V5 0x00
++#define BIT_PM_RECEIVER_BB_CFG_BBSEL_3V0 0x04
++#define BIT_PM_RECEIVER_BB_CFG_BBSEL_3V1 0x08
++#define BIT_PM_RECEIVER_BB_CFG_BBSEL_3v2 0x0c
++#define BIT_PM_RECEIVER_BB_CFG_BBISEL 0x03
++#define BIT_PM_RECEIVER_BB_CFG_BBISEL_25UA 0x00
++#define BIT_PM_RECEIVER_BB_CFG_BBISEL_150UA 0x01
++#define BIT_PM_RECEIVER_BB_CFG_BBISEL_500UA 0x02
++#define BIT_PM_RECEIVER_BB_CFG_BBISEL_1MA 0x03
+
+ /*
+ * RTC block register offsets (use TWL_MODULE_RTC)
+@@ -495,6 +512,14 @@ static int __devinit twl_rtc_probe(struct platform_device *pdev)
+ if (ret < 0)
+ goto out2;
+
++ /* enable backup battery charging */
++ /* use a conservative 25uA @ 3.1V */
++ ret = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
++ BIT_PM_RECEIVER_BB_CFG_BBCHEN |
++ BIT_PM_RECEIVER_BB_CFG_BBSEL_3V1 |
++ BIT_PM_RECEIVER_BB_CFG_BBISEL_25UA,
++ REG_BB_CFG);
++
+ return ret;
+
+ out2:
+--
+1.6.6.1
+
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0017-ARM-OMAP2-mmc-twl4030-move-clock-input-selection-pri.patch b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0017-ARM-OMAP2-mmc-twl4030-move-clock-input-selection-pri.patch
new file mode 100644
index 0000000000..6aacbf7af8
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0017-ARM-OMAP2-mmc-twl4030-move-clock-input-selection-pri.patch
@@ -0,0 +1,39 @@
+From 83b4a493176cbd50c8d2503440fecfa6e499f30e Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Sun, 24 Jan 2010 09:33:56 -0800
+Subject: [PATCH 17/28] ARM: OMAP2: mmc-twl4030: move clock input selection prior to vcc test
+
+otherwise it is not executed on systems that use non-twl regulators
+---
+ arch/arm/mach-omap2/hsmmc.c | 14 ++++++--------
+ 1 files changed, 6 insertions(+), 8 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c
+index b2f30be..84d5ef6 100644
+--- a/arch/arm/mach-omap2/hsmmc.c
++++ b/arch/arm/mach-omap2/hsmmc.c
+@@ -185,15 +185,13 @@ static void hsmmc23_before_set_reg(struct device *dev, int slot,
+ if (mmc->slots[0].remux)
+ mmc->slots[0].remux(dev, slot, power_on);
+
+- if (power_on) {
+- /* Only MMC2 supports a CLKIN */
+- if (mmc->slots[0].internal_clock) {
+- u32 reg;
++ /* Only MMC2 supports a CLKIN */
++ if (mmc->slots[0].internal_clock) {
++ u32 reg;
+
+- reg = omap_ctrl_readl(control_devconf1_offset);
+- reg |= OMAP2_MMCSDIO2ADPCLKISEL;
+- omap_ctrl_writel(reg, control_devconf1_offset);
+- }
++ reg = omap_ctrl_readl(control_devconf1_offset);
++ reg |= OMAP2_MMCSDIO2ADPCLKISEL;
++ omap_ctrl_writel(reg, control_devconf1_offset);
+ }
+ }
+
+--
+1.6.6.1
+
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0018-Add-power-off-support-for-the-TWL4030-companion.patch b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0018-Add-power-off-support-for-the-TWL4030-companion.patch
new file mode 100644
index 0000000000..c5359c1b01
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0018-Add-power-off-support-for-the-TWL4030-companion.patch
@@ -0,0 +1,103 @@
+From 890a8385d7f9bee69bf22616d16b225790b1d18c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Bernhard=20W=C3=B6rndl-Aichriedler?= <bwa@xdevelop.at>
+Date: Sat, 15 May 2010 16:34:05 +0200
+Subject: [PATCH 18/28] Add power-off support for the TWL4030 companion
+
+This patch adds support for the power-off on shutdown feature of the TWL4030
+---
+ drivers/mfd/Kconfig | 6 ++++++
+ drivers/mfd/twl-core.c | 40 ++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 46 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
+index 3ed3ff0..fe2370a 100644
+--- a/drivers/mfd/Kconfig
++++ b/drivers/mfd/Kconfig
+@@ -210,6 +210,12 @@ config TWL4030_CODEC
+ select MFD_CORE
+ default n
+
++config TWL4030_POWEROFF
++ bool "TWL4030 Allow power-off on shutdown"
++ depends on TWL4030_CORE
++ help
++ Enables the CPU to power-off the system on shutdown
++
+ config TWL6030_PWM
+ tristate "TWL6030 PWM (Pulse Width Modulator) Support"
+ depends on TWL4030_CORE
+diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
+index 960b5be..8804550 100644
+--- a/drivers/mfd/twl-core.c
++++ b/drivers/mfd/twl-core.c
+@@ -122,6 +122,12 @@
+ #define twl_has_bci() false
+ #endif
+
++#if defined (CONFIG_TWL4030_POWEROFF)
++#define twl_has_poweroff() true
++#else
++#define twl_has_poweroff() false
++#endif
++
+ /* Triton Core internal information (BEGIN) */
+
+ /* Last - for index max*/
+@@ -224,6 +230,10 @@
+ #define TWL5031 BIT(2) /* twl5031 has different registers */
+ #define TWL6030_CLASS BIT(3) /* TWL6030 class */
+
++/* for pm_power_off */
++#define PWR_P1_SW_EVENTS 0x10
++#define PWR_DEVOFF (1 << 0)
++
+ /*----------------------------------------------------------------------*/
+
+ /* is driver active, bound to a chip? */
+@@ -1006,6 +1016,30 @@ static int twl_remove(struct i2c_client *client)
+ return 0;
+ }
+
++static void twl_poweroff(void)
++{
++ int err;
++ u8 val;
++
++ err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &val,
++ PWR_P1_SW_EVENTS);
++ if (err) {
++ pr_err("%s: i2c error %d while reading TWL4030"
++ "PM_MASTER P1_SW_EVENTS\n",
++ DRIVER_NAME, err);
++ return;
++ }
++
++ val |= PWR_DEVOFF;
++
++ err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, val,
++ PWR_P1_SW_EVENTS);
++ if (err)
++ pr_err("%s: i2c error %d while writing TWL4030"
++ "PM_MASTER P1_SW_EVENTS\n",
++ DRIVER_NAME, err);
++}
++
+ /* NOTE: this driver only handles a single twl4030/tps659x0 chip */
+ static int __devinit
+ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
+@@ -1093,6 +1127,12 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
+ twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
+ }
+
++ if(twl_has_poweroff())
++ {
++ /* initialize pm_power_off routine */
++ pm_power_off = twl_poweroff;
++ }
++
+ status = add_children(pdata, id->driver_data);
+ fail:
+ if (status < 0)
+--
+1.6.6.1
+
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0019-ARM-OMAP-Add-twl4030-madc-support-to-Overo.patch b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0019-ARM-OMAP-Add-twl4030-madc-support-to-Overo.patch
new file mode 100644
index 0000000000..045089e0ac
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0019-ARM-OMAP-Add-twl4030-madc-support-to-Overo.patch
@@ -0,0 +1,33 @@
+From 5b1ae684aa507a50630555d48c834a6f1fd2d1cf Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Thu, 17 Dec 2009 14:27:15 -0800
+Subject: [PATCH 19/28] ARM: OMAP: Add twl4030 madc support to Overo
+
+Signed-off-by: Steve Sakoman <steve@sakoman.com>
+---
+ arch/arm/mach-omap2/board-overo.c | 5 +++++
+ 1 files changed, 5 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
+index 59ca333..86f76e9 100644
+--- a/arch/arm/mach-omap2/board-overo.c
++++ b/arch/arm/mach-omap2/board-overo.c
+@@ -637,10 +637,15 @@ static struct twl4030_codec_data overo_codec_data = {
+ .audio = &overo_audio_data,
+ };
+
++static struct twl4030_madc_platform_data overo_madc_data = {
++ .irq_line = 1,
++};
++
+ static struct twl4030_platform_data overo_twldata = {
+ .irq_base = TWL4030_IRQ_BASE,
+ .irq_end = TWL4030_IRQ_END,
+ .gpio = &overo_gpio_data,
++ .madc = &overo_madc_data,
+ .usb = &overo_usb_data,
+ .codec = &overo_codec_data,
+ .vmmc1 = &overo_vmmc1,
+--
+1.6.6.1
+
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0020-Enabling-Hwmon-driver-for-twl4030-madc.patch b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0020-Enabling-Hwmon-driver-for-twl4030-madc.patch
new file mode 100644
index 0000000000..771c2846e2
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0020-Enabling-Hwmon-driver-for-twl4030-madc.patch
@@ -0,0 +1,46 @@
+From 79dc823c9ce624a2164a01b35a89452b22a7d174 Mon Sep 17 00:00:00 2001
+From: Keerthy <j-keerthy@ti.com>
+Date: Wed, 4 May 2011 01:14:50 +0530
+Subject: [PATCH 20/28] Enabling Hwmon driver for twl4030-madc
+
+Signed-off-by: Keerthy <j-keerthy@ti.com>
+---
+ drivers/mfd/twl-core.c | 15 +++++++++++++++
+ 1 files changed, 15 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
+index 8804550..d9435e4 100644
+--- a/drivers/mfd/twl-core.c
++++ b/drivers/mfd/twl-core.c
+@@ -83,6 +83,13 @@
+ #define twl_has_madc() false
+ #endif
+
++#if defined(CONFIG_SENSORS_TWL4030_MADC) ||\
++ defined(CONFIG_SENSORS_TWL4030_MADC_MODULE)
++#define twl_has_madc_hwmon() true
++#else
++#define twl_has_madc_hwmon() false
++#endif
++
+ #ifdef CONFIG_TWL4030_POWER
+ #define twl_has_power() true
+ #else
+@@ -619,6 +626,14 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
+ return PTR_ERR(child);
+ }
+
++if (twl_has_madc_hwmon()) {
++ child = add_child(2, "twl4030_madc_hwmon",
++ NULL, 0,
++ true, pdata->irq_base + MADC_INTR_OFFSET, 0);
++ if (IS_ERR(child))
++ return PTR_ERR(child);
++ }
++
+ if (twl_has_rtc()) {
+ /*
+ * REVISIT platform_data here currently might expose the
+--
+1.6.6.1
+
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0021-mfd-twl-core-enable-madc-clock.patch b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0021-mfd-twl-core-enable-madc-clock.patch
new file mode 100644
index 0000000000..05cd10d1fa
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0021-mfd-twl-core-enable-madc-clock.patch
@@ -0,0 +1,54 @@
+From 243d5534666eb795815f12d382cfcb77d5a43a8d Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Sat, 23 Jan 2010 06:26:54 -0800
+Subject: [PATCH 21/28] mfd: twl-core: enable madc clock
+
+Now that the madc driver has been merged it is also necessary to enable the clock to the madc block
+
+Signed-off-by: Steve Sakoman <steve@sakoman.com>
+---
+ drivers/mfd/twl-core.c | 8 ++++++++
+ include/linux/i2c/twl.h | 1 +
+ 2 files changed, 9 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
+index d9435e4..9096d7d 100644
+--- a/drivers/mfd/twl-core.c
++++ b/drivers/mfd/twl-core.c
+@@ -222,6 +222,11 @@
+
+ /* Few power values */
+ #define R_CFG_BOOT 0x05
++#define R_GPBR1 0x0C
++
++/* MADC clock values for R_GPBR1 */
++#define MADC_HFCLK_EN 0x80
++#define DEFAULT_MADC_CLK_EN 0x10
+
+ /* some fields in R_CFG_BOOT */
+ #define HFCLK_FREQ_19p2_MHZ (1 << 0)
+@@ -992,6 +997,9 @@ static void clocks_init(struct device *dev,
+
+ e |= unprotect_pm_master();
+ /* effect->MADC+USB ck en */
++ if (twl_has_madc())
++ e |= twl_i2c_write_u8(TWL_MODULE_INTBR,
++ MADC_HFCLK_EN | DEFAULT_MADC_CLK_EN, R_GPBR1);
+ e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, ctrl, R_CFG_BOOT);
+ e |= protect_pm_master();
+
+diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h
+index 0c0d1ae..cbbf3b3 100644
+--- a/include/linux/i2c/twl.h
++++ b/include/linux/i2c/twl.h
+@@ -74,6 +74,7 @@
+
+ #define TWL_MODULE_USB TWL4030_MODULE_USB
+ #define TWL_MODULE_AUDIO_VOICE TWL4030_MODULE_AUDIO_VOICE
++#define TWL_MODULE_INTBR TWL4030_MODULE_INTBR
+ #define TWL_MODULE_PIH TWL4030_MODULE_PIH
+ #define TWL_MODULE_MADC TWL4030_MODULE_MADC
+ #define TWL_MODULE_MAIN_CHARGE TWL4030_MODULE_MAIN_CHARGE
+--
+1.6.6.1
+
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0022-ARM-OMAP-automatically-set-musb-mode-in-platform-dat.patch b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0022-ARM-OMAP-automatically-set-musb-mode-in-platform-dat.patch
new file mode 100644
index 0000000000..6d2a38a785
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0022-ARM-OMAP-automatically-set-musb-mode-in-platform-dat.patch
@@ -0,0 +1,49 @@
+From df17c7eeca25cd9923828a4732a995e2c37d070b Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Wed, 24 Feb 2010 10:37:22 -0800
+Subject: [PATCH 22/28] ARM: OMAP: automatically set musb mode in platform data based on CONFIG options
+
+---
+ arch/arm/mach-omap2/board-omap3beagle.c | 6 ++++++
+ arch/arm/mach-omap2/board-overo.c | 6 ++++++
+ 2 files changed, 12 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index 33007fd..2de4b02 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -604,7 +604,13 @@ static struct omap_board_mux board_mux[] __initdata = {
+
+ static struct omap_musb_board_data musb_board_data = {
+ .interface_type = MUSB_INTERFACE_ULPI,
++#if defined(CONFIG_USB_MUSB_OTG)
+ .mode = MUSB_OTG,
++#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
++ .mode = MUSB_PERIPHERAL,
++#else
++ .mode = MUSB_HOST,
++#endif
+ .power = 100,
+ };
+
+diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
+index 86f76e9..61c59fc 100644
+--- a/arch/arm/mach-omap2/board-overo.c
++++ b/arch/arm/mach-omap2/board-overo.c
+@@ -729,7 +729,13 @@ static struct omap_board_mux board_mux[] __initdata = {
+
+ static struct omap_musb_board_data musb_board_data = {
+ .interface_type = MUSB_INTERFACE_ULPI,
++#if defined(CONFIG_USB_MUSB_OTG)
+ .mode = MUSB_OTG,
++#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
++ .mode = MUSB_PERIPHERAL,
++#else
++ .mode = MUSB_HOST,
++#endif
+ .power = 100,
+ };
+
+--
+1.6.6.1
+
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0023-omap-mmc-Adjust-dto-to-eliminate-timeout-errors.patch b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0023-omap-mmc-Adjust-dto-to-eliminate-timeout-errors.patch
new file mode 100644
index 0000000000..212c5f0264
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0023-omap-mmc-Adjust-dto-to-eliminate-timeout-errors.patch
@@ -0,0 +1,28 @@
+From c60f16ec7e69f59b3bef9f9b7041a973d144dc87 Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Wed, 12 Jan 2011 05:54:55 -0800
+Subject: [PATCH 23/28] omap: mmc: Adjust dto to eliminate timeout errors
+
+A number of SD card types were experiencing timeout errors. This
+could also lead to data corruption in some cases.
+
+This fix proposed by Sukumar Ghoral of TI.
+---
+ drivers/mmc/host/omap_hsmmc.c | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
+index d57686c..7fb03e8 100644
+--- a/drivers/mmc/host/omap_hsmmc.c
++++ b/drivers/mmc/host/omap_hsmmc.c
+@@ -1400,6 +1400,7 @@ static void set_data_timeout(struct omap_hsmmc_host *host,
+ cycle_ns = 1000000000 / (clk_get_rate(host->fclk) / clkd);
+ timeout = timeout_ns / cycle_ns;
+ timeout += timeout_clks;
++ timeout *= 2;
+ if (timeout) {
+ while ((timeout & 0x80000000) == 0) {
+ dto += 1;
+--
+1.6.6.1
+
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0024-omap-Fix-mtd-subpage-read-alignment.patch b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0024-omap-Fix-mtd-subpage-read-alignment.patch
new file mode 100644
index 0000000000..13b7631a16
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0024-omap-Fix-mtd-subpage-read-alignment.patch
@@ -0,0 +1,95 @@
+From 592fdd511dacc42bf97f249ca596ba28d0c25281 Mon Sep 17 00:00:00 2001
+From: Charles Manning <cdhmanning@gmail.com>
+Date: Tue, 18 Jan 2011 11:25:25 +1300
+Subject: [PATCH 24/28] omap: Fix mtd subpage read alignment
+
+This allows the omap2 prefetch engine to work properly for subpage
+reads. Without this ECC errors will stop UBIFS from working.
+
+Signed-off-by: Charles Manning <cdhmanning@gmail.com>
+---
+ drivers/mtd/nand/nand_base.c | 19 +++++++++++++++++++
+ drivers/mtd/nand/omap2.c | 1 +
+ include/linux/mtd/nand.h | 3 +++
+ 3 files changed, 23 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
+index c54a4cb..6ca7098 100644
+--- a/drivers/mtd/nand/nand_base.c
++++ b/drivers/mtd/nand/nand_base.c
+@@ -1157,6 +1157,22 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
+ }
+
+ /**
++ * nand_align_subpage32 - function to align subpage read to 32-bits
++ * @mtd: mtd info structure
++ * @buf: pointer to offset that needs to be aligned
++ * @len: pointer to length that needs to be aligned.
++ */
++
++void nand_align_subpage32(int *offs, int *len)
++{
++ int diff = *offs & 3;
++
++ *offs = *offs - diff;
++ *len = (*len + diff + 3) & ~3;
++}
++EXPORT_SYMBOL(nand_align_subpage32);
++
++/**
+ * nand_read_subpage - [REPLACABLE] software ecc based sub-page read function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+@@ -1221,6 +1237,9 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
+ if (eccpos[index + (num_steps * chip->ecc.bytes)] & (busw - 1))
+ aligned_len++;
+
++ if(chip->align_subpage)
++ chip->align_subpage(&aligned_pos, &aligned_len);
++
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
+ mtd->writesize + aligned_pos, -1);
+ chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len);
+diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
+index da9a351..bb89c65 100644
+--- a/drivers/mtd/nand/omap2.c
++++ b/drivers/mtd/nand/omap2.c
+@@ -1069,6 +1069,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
+ info->nand.ecc.correct = omap_correct_data;
+ info->nand.ecc.mode = NAND_ECC_HW;
+ }
++ info->nand.align_subpage = nand_align_subpage32;
+
+ /* DIP switches on some boards change between 8 and 16 bit
+ * bus widths for flash. Try the other width if the first try fails.
+diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
+index d441927..311f211 100644
+--- a/include/linux/mtd/nand.h
++++ b/include/linux/mtd/nand.h
+@@ -479,6 +479,7 @@ struct nand_buffers {
+ * additional error status checks (determine if errors are
+ * correctable).
+ * @write_page: [REPLACEABLE] High-level page write function
++ * @align_subpage: [OPTIONAL] Aligns subpage read buffer.
+ */
+
+ struct nand_chip {
+@@ -507,6 +508,7 @@ struct nand_chip {
+ int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf, int page, int cached, int raw);
+
++ void (*align_subpage)(int *offs, int *len);
+ int chip_delay;
+ unsigned int options;
+
+@@ -602,6 +604,7 @@ extern int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
+ int allowbbt);
+ extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, uint8_t *buf);
++extern void nand_align_subpage32(int *offs, int *len);
+
+ /**
+ * struct platform_nand_chip - chip level device structure
+--
+1.6.6.1
+
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0025-mtd-nand-omap2-Force-all-buffer-reads-to-u32-alignme.patch b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0025-mtd-nand-omap2-Force-all-buffer-reads-to-u32-alignme.patch
new file mode 100644
index 0000000000..dadaa1c445
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0025-mtd-nand-omap2-Force-all-buffer-reads-to-u32-alignme.patch
@@ -0,0 +1,35 @@
+From 2611e93b57147877fabb181bd86c78fd425a5467 Mon Sep 17 00:00:00 2001
+From: Charles Manning <manningc2@actrix.gen.nz>
+Date: Thu, 16 Dec 2010 20:35:56 -0800
+Subject: [PATCH 25/28] mtd: nand: omap2: Force all buffer reads to u32 alignment
+
+---
+ drivers/mtd/nand/omap2.c | 12 ++++++++++++
+ 1 files changed, 12 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
+index bb89c65..832f111 100644
+--- a/drivers/mtd/nand/omap2.c
++++ b/drivers/mtd/nand/omap2.c
+@@ -247,6 +247,18 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
+ int ret = 0;
+ u32 *p = (u32 *)buf;
+
++ /* u32 align the buffer and read */
++ /* NB: This assumes the buf ptr can be aligned *down* which is a valid.
++ * Assumption when dealing with ecc buffers etc.
++ */
++ u32 addr = (u32)p;
++
++ int diff = addr & 3;
++ addr -= diff;
++ len += diff;
++ len = (len + 3) & ~3;
++ p = (u32 *)addr;
++
+ /* take care of subpage reads */
+ if (len % 4) {
+ if (info->nand.options & NAND_BUSWIDTH_16)
+--
+1.6.6.1
+
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0026-omap-nand-fix-subpage-ecc-issue-with-prefetch.patch b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0026-omap-nand-fix-subpage-ecc-issue-with-prefetch.patch
new file mode 100644
index 0000000000..c8dacdc985
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0026-omap-nand-fix-subpage-ecc-issue-with-prefetch.patch
@@ -0,0 +1,63 @@
+From 1f0278a4f5475cc9ad67e007763368dfdd7dee29 Mon Sep 17 00:00:00 2001
+From: kishore kadiyala <kishore.kadiyala@ti.com>
+Date: Mon, 2 May 2011 11:10:38 +0000
+Subject: [PATCH 26/28] omap : nand : fix subpage ecc issue with prefetch
+
+For prefetch engine, read and write got broken in commit '2c01946c'.
+We never hit a scenario of not getting 'gpmc_prefetch_enable'
+call success.
+When reading/writing a subpage with a non divisible by 4 ecc number
+of bytes, the mis-aligned bytes gets handled first before enabling
+the Prefetch engine, then it reads/writes rest of the bytes.
+
+Signed-off-by: Kishore Kadiyala <kishore.kadiyala@ti.com>
+Signed-off-by: Vimal Singh <vimal.newwork@gmail.com>
+Reported-by: Bryan DE FARIA <bdefaria@adeneo-embedded.com>
+---
+ drivers/mtd/nand/omap2.c | 12 +++++-------
+ 1 files changed, 5 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
+index 832f111..471a39b 100644
+--- a/drivers/mtd/nand/omap2.c
++++ b/drivers/mtd/nand/omap2.c
+@@ -275,11 +275,10 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
+ if (ret) {
+ /* PFPW engine is busy, use cpu copy method */
+ if (info->nand.options & NAND_BUSWIDTH_16)
+- omap_read_buf16(mtd, buf, len);
++ omap_read_buf16(mtd, (u_char *)p, len);
+ else
+- omap_read_buf8(mtd, buf, len);
++ omap_read_buf8(mtd, (u_char *)p, len);
+ } else {
+- p = (u32 *) buf;
+ do {
+ r_count = gpmc_read_status(GPMC_PREFETCH_FIFO_CNT);
+ r_count = r_count >> 2;
+@@ -305,7 +304,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
+ struct omap_nand_info, mtd);
+ uint32_t w_count = 0;
+ int i = 0, ret = 0;
+- u16 *p;
++ u16 *p = (u16 *)buf;
+ unsigned long tim, limit;
+
+ /* take care of subpage writes */
+@@ -321,11 +320,10 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
+ if (ret) {
+ /* PFPW engine is busy, use cpu copy method */
+ if (info->nand.options & NAND_BUSWIDTH_16)
+- omap_write_buf16(mtd, buf, len);
++ omap_write_buf16(mtd, (u_char *)p, len);
+ else
+- omap_write_buf8(mtd, buf, len);
++ omap_write_buf8(mtd, (u_char *)p, len);
+ } else {
+- p = (u16 *) buf;
+ while (len) {
+ w_count = gpmc_read_status(GPMC_PREFETCH_FIFO_CNT);
+ w_count = w_count >> 1;
+--
+1.6.6.1
+
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0027-OMAP-Overo-Add-support-for-spidev.patch b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0027-OMAP-Overo-Add-support-for-spidev.patch
new file mode 100644
index 0000000000..d126ca7385
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0027-OMAP-Overo-Add-support-for-spidev.patch
@@ -0,0 +1,46 @@
+From 61e1cb7dbff3b611644d6ba811f8b83db148c1e1 Mon Sep 17 00:00:00 2001
+From: Scott Ellis <scottellis.developer@gmail.com>
+Date: Sun, 23 Jan 2011 20:39:35 -0800
+Subject: [PATCH 27/28] OMAP: Overo: Add support for spidev
+
+---
+ arch/arm/mach-omap2/board-overo.c | 16 ++++++++++++++++
+ 1 files changed, 16 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
+index 61c59fc..05dd3eb 100644
+--- a/arch/arm/mach-omap2/board-overo.c
++++ b/arch/arm/mach-omap2/board-overo.c
+@@ -683,6 +683,14 @@ static struct spi_board_info overo_spi_board_info[] __initdata = {
+ .irq = OMAP_GPIO_IRQ(OVERO_GPIO_PENDOWN),
+ .platform_data = &ads7846_config,
+ },
++#elif defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
++ {
++ .modalias = "spidev",
++ .bus_num = 1,
++ .chip_select = 0,
++ .max_speed_hz = 48000000,
++ .mode = SPI_MODE_0,
++ },
+ #endif
+ #if defined(CONFIG_PANEL_LGPHILIPS_LB035Q02) || \
+ defined(CONFIG_PANEL_LGPHILIPS_LB035Q02_MODULE)
+@@ -693,6 +701,14 @@ static struct spi_board_info overo_spi_board_info[] __initdata = {
+ .max_speed_hz = 500000,
+ .mode = SPI_MODE_3,
+ },
++#elif defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
++ {
++ .modalias = "spidev",
++ .bus_num = 1,
++ .chip_select = 1,
++ .max_speed_hz = 48000000,
++ .mode = SPI_MODE_0,
++ },
+ #endif
+ };
+
+--
+1.6.6.1
+
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0028-unionfs-Add-support-for-unionfs-2.5.9.patch b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0028-unionfs-Add-support-for-unionfs-2.5.9.patch
new file mode 100644
index 0000000000..24cc728707
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0028-unionfs-Add-support-for-unionfs-2.5.9.patch
@@ -0,0 +1,11494 @@
+From d84fb8f137d9392574422213ec6c3dc53bb00abf Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Mon, 2 May 2011 16:14:34 -0700
+Subject: [PATCH 28/28] unionfs: Add support for unionfs 2.5.9
+
+---
+ Documentation/filesystems/00-INDEX | 2 +
+ Documentation/filesystems/unionfs/00-INDEX | 10 +
+ Documentation/filesystems/unionfs/concepts.txt | 287 ++++++
+ Documentation/filesystems/unionfs/issues.txt | 28 +
+ Documentation/filesystems/unionfs/rename.txt | 31 +
+ Documentation/filesystems/unionfs/usage.txt | 134 +++
+ MAINTAINERS | 8 +
+ fs/Kconfig | 1 +
+ fs/Makefile | 1 +
+ fs/namei.c | 38 +
+ fs/splice.c | 22 +-
+ fs/stack.c | 14 +-
+ fs/unionfs/Kconfig | 24 +
+ fs/unionfs/Makefile | 17 +
+ fs/unionfs/commonfops.c | 898 +++++++++++++++++++
+ fs/unionfs/copyup.c | 896 +++++++++++++++++++
+ fs/unionfs/debug.c | 548 ++++++++++++
+ fs/unionfs/dentry.c | 406 +++++++++
+ fs/unionfs/dirfops.c | 302 +++++++
+ fs/unionfs/dirhelper.c | 158 ++++
+ fs/unionfs/fanout.h | 407 +++++++++
+ fs/unionfs/file.c | 382 ++++++++
+ fs/unionfs/inode.c | 1099 ++++++++++++++++++++++++
+ fs/unionfs/lookup.c | 569 ++++++++++++
+ fs/unionfs/main.c | 763 ++++++++++++++++
+ fs/unionfs/mmap.c | 89 ++
+ fs/unionfs/rdstate.c | 285 ++++++
+ fs/unionfs/rename.c | 522 +++++++++++
+ fs/unionfs/sioq.c | 101 +++
+ fs/unionfs/sioq.h | 91 ++
+ fs/unionfs/subr.c | 95 ++
+ fs/unionfs/super.c | 1030 ++++++++++++++++++++++
+ fs/unionfs/union.h | 679 +++++++++++++++
+ fs/unionfs/unlink.c | 278 ++++++
+ fs/unionfs/whiteout.c | 601 +++++++++++++
+ fs/unionfs/xattr.c | 173 ++++
+ include/linux/fs_stack.h | 14 +-
+ include/linux/magic.h | 2 +
+ include/linux/namei.h | 3 +
+ include/linux/splice.h | 5 +
+ include/linux/union_fs.h | 22 +
+ security/security.c | 1 +
+ 42 files changed, 11024 insertions(+), 12 deletions(-)
+ create mode 100644 Documentation/filesystems/unionfs/00-INDEX
+ create mode 100644 Documentation/filesystems/unionfs/concepts.txt
+ create mode 100644 Documentation/filesystems/unionfs/issues.txt
+ create mode 100644 Documentation/filesystems/unionfs/rename.txt
+ create mode 100644 Documentation/filesystems/unionfs/usage.txt
+ create mode 100644 fs/unionfs/Kconfig
+ create mode 100644 fs/unionfs/Makefile
+ create mode 100644 fs/unionfs/commonfops.c
+ create mode 100644 fs/unionfs/copyup.c
+ create mode 100644 fs/unionfs/debug.c
+ create mode 100644 fs/unionfs/dentry.c
+ create mode 100644 fs/unionfs/dirfops.c
+ create mode 100644 fs/unionfs/dirhelper.c
+ create mode 100644 fs/unionfs/fanout.h
+ create mode 100644 fs/unionfs/file.c
+ create mode 100644 fs/unionfs/inode.c
+ create mode 100644 fs/unionfs/lookup.c
+ create mode 100644 fs/unionfs/main.c
+ create mode 100644 fs/unionfs/mmap.c
+ create mode 100644 fs/unionfs/rdstate.c
+ create mode 100644 fs/unionfs/rename.c
+ create mode 100644 fs/unionfs/sioq.c
+ create mode 100644 fs/unionfs/sioq.h
+ create mode 100644 fs/unionfs/subr.c
+ create mode 100644 fs/unionfs/super.c
+ create mode 100644 fs/unionfs/union.h
+ create mode 100644 fs/unionfs/unlink.c
+ create mode 100644 fs/unionfs/whiteout.c
+ create mode 100644 fs/unionfs/xattr.c
+ create mode 100644 include/linux/union_fs.h
+
+diff --git a/Documentation/filesystems/00-INDEX b/Documentation/filesystems/00-INDEX
+index 8c624a1..4aa288b 100644
+--- a/Documentation/filesystems/00-INDEX
++++ b/Documentation/filesystems/00-INDEX
+@@ -110,6 +110,8 @@ udf.txt
+ - info and mount options for the UDF filesystem.
+ ufs.txt
+ - info on the ufs filesystem.
++unionfs/
++ - info on the unionfs filesystem
+ vfat.txt
+ - info on using the VFAT filesystem used in Windows NT and Windows 95
+ vfs.txt
+diff --git a/Documentation/filesystems/unionfs/00-INDEX b/Documentation/filesystems/unionfs/00-INDEX
+new file mode 100644
+index 0000000..96fdf67
+--- /dev/null
++++ b/Documentation/filesystems/unionfs/00-INDEX
+@@ -0,0 +1,10 @@
++00-INDEX
++ - this file.
++concepts.txt
++ - A brief introduction of concepts.
++issues.txt
++ - A summary of known issues with unionfs.
++rename.txt
++ - Information regarding rename operations.
++usage.txt
++ - Usage information and examples.
+diff --git a/Documentation/filesystems/unionfs/concepts.txt b/Documentation/filesystems/unionfs/concepts.txt
+new file mode 100644
+index 0000000..b853788
+--- /dev/null
++++ b/Documentation/filesystems/unionfs/concepts.txt
+@@ -0,0 +1,287 @@
++Unionfs 2.x CONCEPTS:
++=====================
++
++This file describes the concepts needed by a namespace unification file
++system.
++
++
++Branch Priority:
++================
++
++Each branch is assigned a unique priority - starting from 0 (highest
++priority). No two branches can have the same priority.
++
++
++Branch Mode:
++============
++
++Each branch is assigned a mode - read-write or read-only. This allows
++directories on media mounted read-write to be used in a read-only manner.
++
++
++Whiteouts:
++==========
++
++A whiteout removes a file name from the namespace. Whiteouts are needed when
++one attempts to remove a file on a read-only branch.
++
++Suppose we have a two-branch union, where branch 0 is read-write and branch
++1 is read-only. And a file 'foo' on branch 1:
++
++./b0/
++./b1/
++./b1/foo
++
++The unified view would simply be:
++
++./union/
++./union/foo
++
++Since 'foo' is stored on a read-only branch, it cannot be removed. A
++whiteout is used to remove the name 'foo' from the unified namespace. Again,
++since branch 1 is read-only, the whiteout cannot be created there. So, we
++try on a higher priority (lower numerically) branch and create the whiteout
++there.
++
++./b0/
++./b0/.wh.foo
++./b1/
++./b1/foo
++
++Later, when Unionfs traverses branches (due to lookup or readdir), it
++eliminate 'foo' from the namespace (as well as the whiteout itself.)
++
++
++Opaque Directories:
++===================
++
++Assume we have a unionfs mount comprising of two branches. Branch 0 is
++empty; branch 1 has the directory /a and file /a/f. Let's say we mount a
++union of branch 0 as read-write and branch 1 as read-only. Now, let's say
++we try to perform the following operation in the union:
++
++ rm -fr a
++
++Because branch 1 is not writable, we cannot physically remove the file /a/f
++or the directory /a. So instead, we will create a whiteout in branch 0
++named /.wh.a, masking out the name "a" from branch 1. Next, let's say we
++try to create a directory named "a" as follows:
++
++ mkdir a
++
++Because we have a whiteout for "a" already, Unionfs behaves as if "a"
++doesn't exist, and thus will delete the whiteout and replace it with an
++actual directory named "a".
++
++The problem now is that if you try to "ls" in the union, Unionfs will
++perform is normal directory name unification, for *all* directories named
++"a" in all branches. This will cause the file /a/f from branch 1 to
++re-appear in the union's namespace, which violates Unix semantics.
++
++To avoid this problem, we have a different form of whiteouts for
++directories, called "opaque directories" (same as BSD Union Mount does).
++Whenever we replace a whiteout with a directory, that directory is marked as
++opaque. In Unionfs 2.x, it means that we create a file named
++/a/.wh.__dir_opaque in branch 0, after having created directory /a there.
++When unionfs notices that a directory is opaque, it stops all namespace
++operations (including merging readdir contents) at that opaque directory.
++This prevents re-exposing names from masked out directories.
++
++
++Duplicate Elimination:
++======================
++
++It is possible for files on different branches to have the same name.
++Unionfs then has to select which instance of the file to show to the user.
++Given the fact that each branch has a priority associated with it, the
++simplest solution is to take the instance from the highest priority
++(numerically lowest value) and "hide" the others.
++
++
++Unlinking:
++=========
++
++Unlink operation on non-directory instances is optimized to remove the
++maximum possible objects in case multiple underlying branches have the same
++file name. The unlink operation will first try to delete file instances
++from highest priority branch and then move further to delete from remaining
++branches in order of their decreasing priority. Consider a case (F..D..F),
++where F is a file and D is a directory of the same name; here, some
++intermediate branch could have an empty directory instance with the same
++name, so this operation also tries to delete this directory instance and
++proceed further to delete from next possible lower priority branch. The
++unionfs unlink operation will smoothly delete the files with same name from
++all possible underlying branches. In case if some error occurs, it creates
++whiteout in highest priority branch that will hide file instance in rest of
++the branches. An error could occur either if an unlink operations in any of
++the underlying branch failed or if a branch has no write permission.
++
++This unlinking policy is known as "delete all" and it has the benefit of
++overall reducing the number of inodes used by duplicate files, and further
++reducing the total number of inodes consumed by whiteouts. The cost is of
++extra processing, but testing shows this extra processing is well worth the
++savings.
++
++
++Copyup:
++=======
++
++When a change is made to the contents of a file's data or meta-data, they
++have to be stored somewhere. The best way is to create a copy of the
++original file on a branch that is writable, and then redirect the write
++though to this copy. The copy must be made on a higher priority branch so
++that lookup and readdir return this newer "version" of the file rather than
++the original (see duplicate elimination).
++
++An entire unionfs mount can be read-only or read-write. If it's read-only,
++then none of the branches will be written to, even if some of the branches
++are physically writeable. If the unionfs mount is read-write, then the
++leftmost (highest priority) branch must be writeable (for copyup to take
++place); the remaining branches can be any mix of read-write and read-only.
++
++In a writeable mount, unionfs will create new files/dir in the leftmost
++branch. If one tries to modify a file in a read-only branch/media, unionfs
++will copyup the file to the leftmost branch and modify it there. If you try
++to modify a file from a writeable branch which is not the leftmost branch,
++then unionfs will modify it in that branch; this is useful if you, say,
++unify differnet packages (e.g., apache, sendmail, ftpd, etc.) and you want
++changes to specific package files to remain logically in the directory where
++they came from.
++
++Cache Coherency:
++================
++
++Unionfs users often want to be able to modify files and directories directly
++on the lower branches, and have those changes be visible at the Unionfs
++level. This means that data (e.g., pages) and meta-data (dentries, inodes,
++open files, etc.) have to be synchronized between the upper and lower
++layers. In other words, the newest changes from a layer below have to be
++propagated to the Unionfs layer above. If the two layers are not in sync, a
++cache incoherency ensues, which could lead to application failures and even
++oopses. The Linux kernel, however, has a rather limited set of mechanisms
++to ensure this inter-layer cache coherency---so Unionfs has to do most of
++the hard work on its own.
++
++Maintaining Invariants:
++
++The way Unionfs ensures cache coherency is as follows. At each entry point
++to a Unionfs file system method, we call a utility function to validate the
++primary objects of this method. Generally, we call unionfs_file_revalidate
++on open files, and __unionfs_d_revalidate_chain on dentries (which also
++validates inodes). These utility functions check to see whether the upper
++Unionfs object is in sync with any of the lower objects that it represents.
++The checks we perform include whether the Unionfs superblock has a newer
++generation number, or if any of the lower objects mtime's or ctime's are
++newer. (Note: generation numbers change when branch-management commands are
++issued, so in a way, maintaining cache coherency is also very important for
++branch-management.) If indeed we determine that any Unionfs object is no
++longer in sync with its lower counterparts, then we rebuild that object
++similarly to how we do so for branch-management.
++
++While rebuilding Unionfs's objects, we also purge any page mappings and
++truncate inode pages (see fs/unionfs/dentry.c:purge_inode_data). This is to
++ensure that Unionfs will re-get the newer data from the lower branches. We
++perform this purging only if the Unionfs operation in question is a reading
++operation; if Unionfs is performing a data writing operation (e.g., ->write,
++->commit_write, etc.) then we do NOT flush the lower mappings/pages: this is
++because (1) a self-deadlock could occur and (2) the upper Unionfs pages are
++considered more authoritative anyway, as they are newer and will overwrite
++any lower pages.
++
++Unionfs maintains the following important invariant regarding mtime's,
++ctime's, and atime's: the upper inode object's times are the max() of all of
++the lower ones. For non-directory objects, there's only one object below,
++so the mapping is simple; for directory objects, there could me multiple
++lower objects and we have to sync up with the newest one of all the lower
++ones. This invariant is important to maintain, especially for directories
++(besides, we need this to be POSIX compliant). A union could comprise
++multiple writable branches, each of which could change. If we don't reflect
++the newest possible mtime/ctime, some applications could fail. For example,
++NFSv2/v3 exports check for newer directory mtimes on the server to determine
++if the client-side attribute cache should be purged.
++
++To maintain these important invariants, of course, Unionfs carefully
++synchronizes upper and lower times in various places. For example, if we
++copy-up a file to a top-level branch, the parent directory where the file
++was copied up to will now have a new mtime: so after a successful copy-up,
++we sync up with the new top-level branch's parent directory mtime.
++
++Implementation:
++
++This cache-coherency implementation is efficient because it defers any
++synchronizing between the upper and lower layers until absolutely needed.
++Consider the example a common situation where users perform a lot of lower
++changes, such as untarring a whole package. While these take place,
++typically the user doesn't access the files via Unionfs; only after the
++lower changes are done, does the user try to access the lower files. With
++our cache-coherency implementation, the entirety of the changes to the lower
++branches will not result in a single CPU cycle spent at the Unionfs level
++until the user invokes a system call that goes through Unionfs.
++
++We have considered two alternate cache-coherency designs. (1) Using the
++dentry/inode notify functionality to register interest in finding out about
++any lower changes. This is a somewhat limited and also a heavy-handed
++approach which could result in many notifications to the Unionfs layer upon
++each small change at the lower layer (imagine a file being modified multiple
++times in rapid succession). (2) Rewriting the VFS to support explicit
++callbacks from lower objects to upper objects. We began exploring such an
++implementation, but found it to be very complicated--it would have resulted
++in massive VFS/MM changes which are unlikely to be accepted by the LKML
++community. We therefore believe that our current cache-coherency design and
++implementation represent the best approach at this time.
++
++Limitations:
++
++Our implementation works in that as long as a user process will have caused
++Unionfs to be called, directly or indirectly, even to just do
++->d_revalidate; then we will have purged the current Unionfs data and the
++process will see the new data. For example, a process that continually
++re-reads the same file's data will see the NEW data as soon as the lower
++file had changed, upon the next read(2) syscall (even if the file is still
++open!) However, this doesn't work when the process re-reads the open file's
++data via mmap(2) (unless the user unmaps/closes the file and remaps/reopens
++it). Once we respond to ->readpage(s), then the kernel maps the page into
++the process's address space and there doesn't appear to be a way to force
++the kernel to invalidate those pages/mappings, and force the process to
++re-issue ->readpage. If there's a way to invalidate active mappings and
++force a ->readpage, let us know please (invalidate_inode_pages2 doesn't do
++the trick).
++
++Our current Unionfs code has to perform many file-revalidation calls. It
++would be really nice if the VFS would export an optional file system hook
++->file_revalidate (similarly to dentry->d_revalidate) that will be called
++before each VFS op that has a "struct file" in it.
++
++Certain file systems have micro-second granularity (or better) for inode
++times, and asynchronous actions could cause those times to change with some
++small delay. In such cases, Unionfs may see a changed inode time that only
++differs by a tiny fraction of a second: such a change may be a false
++positive indication that the lower object has changed, whereas if unionfs
++waits a little longer, that false indication will not be seen. (These false
++positives are harmless, because they would at most cause unionfs to
++re-validate an object that may need no revalidation, and print a debugging
++message that clutters the console/logs.) Therefore, to minimize the chances
++of these situations, we delay the detection of changed times by a small
++factor of a few seconds, called UNIONFS_MIN_CC_TIME (which defaults to 3
++seconds, as does NFS). This means that we will detect the change, only a
++couple of seconds later, if indeed the time change persists in the lower
++file object. This delayed detection has an added performance benefit: we
++reduce the number of times that unionfs has to revalidate objects, in case
++there's a lot of concurrent activity on both the upper and lower objects,
++for the same file(s). Lastly, this delayed time attribute detection is
++similar to how NFS clients operate (e.g., acregmin).
++
++Finally, there is no way currently in Linux to prevent lower directories
++from being moved around (i.e., topology changes); there's no way to prevent
++modifications to directory sub-trees of whole file systems which are mounted
++read-write. It is therefore possible for in-flight operations in unionfs to
++take place, while a lower directory is being moved around. Therefore, if
++you try to, say, create a new file in a directory through unionfs, while the
++directory is being moved around directly, then the new file may get created
++in the new location where that directory was moved to. This is a somewhat
++similar behaviour in NFS: an NFS client could be creating a new file while
++th NFS server is moving th directory around; the file will get successfully
++created in the new location. (The one exception in unionfs is that if the
++branch is marked read-only by unionfs, then a copyup will take place.)
++
++For more information, see <http://unionfs.filesystems.org/>.
+diff --git a/Documentation/filesystems/unionfs/issues.txt b/Documentation/filesystems/unionfs/issues.txt
+new file mode 100644
+index 0000000..f4b7e7e
+--- /dev/null
++++ b/Documentation/filesystems/unionfs/issues.txt
+@@ -0,0 +1,28 @@
++KNOWN Unionfs 2.x ISSUES:
++=========================
++
++1. Unionfs should not use lookup_one_len() on the underlying f/s as it
++ confuses NFSv4. Currently, unionfs_lookup() passes lookup intents to the
++ lower file-system, this eliminates part of the problem. The remaining
++ calls to lookup_one_len may need to be changed to pass an intent. We are
++ currently introducing VFS changes to fs/namei.c's do_path_lookup() to
++ allow proper file lookup and opening in stackable file systems.
++
++2. Lockdep (a debugging feature) isn't aware of stacking, and so it
++ incorrectly complains about locking problems. The problem boils down to
++ this: Lockdep considers all objects of a certain type to be in the same
++ class, for example, all inodes. Lockdep doesn't like to see a lock held
++ on two inodes within the same task, and warns that it could lead to a
++ deadlock. However, stackable file systems do precisely that: they lock
++ an upper object, and then a lower object, in a strict order to avoid
++ locking problems; in addition, Unionfs, as a fan-out file system, may
++ have to lock several lower inodes. We are currently looking into Lockdep
++ to see how to make it aware of stackable file systems. For now, we
++ temporarily disable lockdep when calling vfs methods on lower objects,
++ but only for those places where lockdep complained. While this solution
++ may seem unclean, it is not without precedent: other places in the kernel
++ also do similar temporary disabling, of course after carefully having
++ checked that it is the right thing to do. Anyway, you get any warnings
++ from Lockdep, please report them to the Unionfs maintainers.
++
++For more information, see <http://unionfs.filesystems.org/>.
+diff --git a/Documentation/filesystems/unionfs/rename.txt b/Documentation/filesystems/unionfs/rename.txt
+new file mode 100644
+index 0000000..e20bb82
+--- /dev/null
++++ b/Documentation/filesystems/unionfs/rename.txt
+@@ -0,0 +1,31 @@
++Rename is a complex beast. The following table shows which rename(2) operations
++should succeed and which should fail.
++
++o: success
++E: error (either unionfs or vfs)
++X: EXDEV
++
++none = file does not exist
++file = file is a file
++dir = file is a empty directory
++child= file is a non-empty directory
++wh = file is a directory containing only whiteouts; this makes it logically
++ empty
++
++ none file dir child wh
++file o o E E E
++dir o E o E o
++child X E X E X
++wh o E o E o
++
++
++Renaming directories:
++=====================
++
++Whenever a empty (either physically or logically) directory is being renamed,
++the following sequence of events should take place:
++
++1) Remove whiteouts from both source and destination directory
++2) Rename source to destination
++3) Make destination opaque to prevent anything under it from showing up
++
+diff --git a/Documentation/filesystems/unionfs/usage.txt b/Documentation/filesystems/unionfs/usage.txt
+new file mode 100644
+index 0000000..1adde69
+--- /dev/null
++++ b/Documentation/filesystems/unionfs/usage.txt
+@@ -0,0 +1,134 @@
++Unionfs is a stackable unification file system, which can appear to merge
++the contents of several directories (branches), while keeping their physical
++content separate. Unionfs is useful for unified source tree management,
++merged contents of split CD-ROM, merged separate software package
++directories, data grids, and more. Unionfs allows any mix of read-only and
++read-write branches, as well as insertion and deletion of branches anywhere
++in the fan-out. To maintain Unix semantics, Unionfs handles elimination of
++duplicates, partial-error conditions, and more.
++
++GENERAL SYNTAX
++==============
++
++# mount -t unionfs -o <OPTIONS>,<BRANCH-OPTIONS> none MOUNTPOINT
++
++OPTIONS can be any legal combination of:
++
++- ro # mount file system read-only
++- rw # mount file system read-write
++- remount # remount the file system (see Branch Management below)
++- incgen # increment generation no. (see Cache Consistency below)
++
++BRANCH-OPTIONS can be either (1) a list of branches given to the "dirs="
++option, or (2) a list of individual branch manipulation commands, combined
++with the "remount" option, and is further described in the "Branch
++Management" section below.
++
++The syntax for the "dirs=" mount option is:
++
++ dirs=branch[=ro|=rw][:...]
++
++The "dirs=" option takes a colon-delimited list of directories to compose
++the union, with an optional branch mode for each of those directories.
++Directories that come earlier (specified first, on the left) in the list
++have a higher precedence than those which come later. Additionally,
++read-only or read-write permissions of the branch can be specified by
++appending =ro or =rw (default) to each directory. See the Copyup section in
++concepts.txt, for a description of Unionfs's behavior when mixing read-only
++and read-write branches and mounts.
++
++Syntax:
++
++ dirs=/branch1[=ro|=rw]:/branch2[=ro|=rw]:...:/branchN[=ro|=rw]
++
++Example:
++
++ dirs=/writable_branch=rw:/read-only_branch=ro
++
++
++BRANCH MANAGEMENT
++=================
++
++Once you mount your union for the first time, using the "dirs=" option, you
++can then change the union's overall mode or reconfigure the branches, using
++the remount option, as follows.
++
++To downgrade a union from read-write to read-only:
++
++# mount -t unionfs -o remount,ro none MOUNTPOINT
++
++To upgrade a union from read-only to read-write:
++
++# mount -t unionfs -o remount,rw none MOUNTPOINT
++
++To delete a branch /foo, regardless where it is in the current union:
++
++# mount -t unionfs -o remount,del=/foo none MOUNTPOINT
++
++To insert (add) a branch /foo before /bar:
++
++# mount -t unionfs -o remount,add=/bar:/foo none MOUNTPOINT
++
++To insert (add) a branch /foo (with the "rw" mode flag) before /bar:
++
++# mount -t unionfs -o remount,add=/bar:/foo=rw none MOUNTPOINT
++
++To insert (add) a branch /foo (in "rw" mode) at the very beginning (i.e., a
++new highest-priority branch), you can use the above syntax, or use a short
++hand version as follows:
++
++# mount -t unionfs -o remount,add=/foo none MOUNTPOINT
++
++To append a branch to the very end (new lowest-priority branch):
++
++# mount -t unionfs -o remount,add=:/foo none MOUNTPOINT
++
++To append a branch to the very end (new lowest-priority branch), in
++read-only mode:
++
++# mount -t unionfs -o remount,add=:/foo=ro none MOUNTPOINT
++
++Finally, to change the mode of one existing branch, say /foo, from read-only
++to read-write, and change /bar from read-write to read-only:
++
++# mount -t unionfs -o remount,mode=/foo=rw,mode=/bar=ro none MOUNTPOINT
++
++Note: in Unionfs 2.x, you cannot set the leftmost branch to readonly because
++then Unionfs won't have any writable place for copyups to take place.
++Moreover, the VFS can get confused when it tries to modify something in a
++file system mounted read-write, but isn't permitted to write to it.
++Instead, you should set the whole union as readonly, as described above.
++If, however, you must set the leftmost branch as readonly, perhaps so you
++can get a snapshot of it at a point in time, then you should insert a new
++writable top-level branch, and mark the one you want as readonly. This can
++be accomplished as follows, assuming that /foo is your current leftmost
++branch:
++
++# mount -t tmpfs -o size=NNN /new
++# mount -t unionfs -o remount,add=/new,mode=/foo=ro none MOUNTPOINT
++<do what you want safely in /foo>
++# mount -t unionfs -o remount,del=/new,mode=/foo=rw none MOUNTPOINT
++<check if there's anything in /new you want to preserve>
++# umount /new
++
++CACHE CONSISTENCY
++=================
++
++If you modify any file on any of the lower branches directly, while there is
++a Unionfs 2.x mounted above any of those branches, you should tell Unionfs
++to purge its caches and re-get the objects. To do that, you have to
++increment the generation number of the superblock using the following
++command:
++
++# mount -t unionfs -o remount,incgen none MOUNTPOINT
++
++Note that the older way of incrementing the generation number using an
++ioctl, is no longer supported in Unionfs 2.0 and newer. Ioctls in general
++are not encouraged. Plus, an ioctl is per-file concept, whereas the
++generation number is a per-file-system concept. Worse, such an ioctl
++requires an open file, which then has to be invalidated by the very nature
++of the generation number increase (read: the old generation increase ioctl
++was pretty racy).
++
++
++For more information, see <http://unionfs.filesystems.org/>.
+diff --git a/MAINTAINERS b/MAINTAINERS
+index 69f19f1..fd88a30 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -6319,6 +6319,14 @@ F: Documentation/cdrom/
+ F: drivers/cdrom/cdrom.c
+ F: include/linux/cdrom.h
+
++UNIONFS
++P: Erez Zadok
++M: ezk@cs.sunysb.edu
++L: unionfs@filesystems.org
++W: http://unionfs.filesystems.org/
++T: git git.kernel.org/pub/scm/linux/kernel/git/ezk/unionfs.git
++S: Maintained
++
+ UNSORTED BLOCK IMAGES (UBI)
+ M: Artem Bityutskiy <dedekind1@gmail.com>
+ W: http://www.linux-mtd.infradead.org/
+diff --git a/fs/Kconfig b/fs/Kconfig
+index f3aa9b0..0e6182c 100644
+--- a/fs/Kconfig
++++ b/fs/Kconfig
+@@ -170,6 +170,7 @@ if MISC_FILESYSTEMS
+ source "fs/adfs/Kconfig"
+ source "fs/affs/Kconfig"
+ source "fs/ecryptfs/Kconfig"
++source "fs/unionfs/Kconfig"
+ source "fs/hfs/Kconfig"
+ source "fs/hfsplus/Kconfig"
+ source "fs/befs/Kconfig"
+diff --git a/fs/Makefile b/fs/Makefile
+index fb68c2b..8ca9290 100644
+--- a/fs/Makefile
++++ b/fs/Makefile
+@@ -83,6 +83,7 @@ obj-$(CONFIG_ISO9660_FS) += isofs/
+ obj-$(CONFIG_HFSPLUS_FS) += hfsplus/ # Before hfs to find wrapped HFS+
+ obj-$(CONFIG_HFS_FS) += hfs/
+ obj-$(CONFIG_ECRYPT_FS) += ecryptfs/
++obj-$(CONFIG_UNION_FS) += unionfs/
+ obj-$(CONFIG_VXFS_FS) += freevxfs/
+ obj-$(CONFIG_NFS_FS) += nfs/
+ obj-$(CONFIG_EXPORTFS) += exportfs/
+diff --git a/fs/namei.c b/fs/namei.c
+index e3c4f11..d9f99a4 100644
+--- a/fs/namei.c
++++ b/fs/namei.c
+@@ -578,6 +578,7 @@ void release_open_intent(struct nameidata *nd)
+ fput(file);
+ }
+ }
++EXPORT_SYMBOL_GPL(release_open_intent);
+
+ static inline int d_revalidate(struct dentry *dentry, struct nameidata *nd)
+ {
+@@ -1819,6 +1820,42 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
+ return __lookup_hash(&this, base, NULL);
+ }
+
++/* pass nameidata from caller (useful for NFS) */
++struct dentry *lookup_one_len_nd(const char *name, struct dentry *base,
++ int len, struct nameidata *nd)
++{
++ struct qstr this;
++ unsigned long hash;
++ unsigned int c;
++
++ WARN_ON_ONCE(!mutex_is_locked(&base->d_inode->i_mutex));
++
++ this.name = name;
++ this.len = len;
++ if (!len)
++ return ERR_PTR(-EACCES);
++
++ hash = init_name_hash();
++ while (len--) {
++ c = *(const unsigned char *)name++;
++ if (c == '/' || c == '\0')
++ return ERR_PTR(-EACCES);
++ hash = partial_name_hash(c, hash);
++ }
++ this.hash = end_name_hash(hash);
++ /*
++ * See if the low-level filesystem might want
++ * to use its own hash..
++ */
++ if (base->d_flags & DCACHE_OP_HASH) {
++ int err = base->d_op->d_hash(base, base->d_inode, &this);
++ if (err < 0)
++ return ERR_PTR(err);
++ }
++
++ return __lookup_hash(&this, base, nd);
++}
++
+ int user_path_at(int dfd, const char __user *name, unsigned flags,
+ struct path *path)
+ {
+@@ -3422,6 +3459,7 @@ EXPORT_SYMBOL(get_write_access); /* binfmt_aout */
+ EXPORT_SYMBOL(getname);
+ EXPORT_SYMBOL(lock_rename);
+ EXPORT_SYMBOL(lookup_one_len);
++EXPORT_SYMBOL(lookup_one_len_nd);
+ EXPORT_SYMBOL(page_follow_link_light);
+ EXPORT_SYMBOL(page_put_link);
+ EXPORT_SYMBOL(page_readlink);
+diff --git a/fs/splice.c b/fs/splice.c
+index 50a5d97..a3af841 100644
+--- a/fs/splice.c
++++ b/fs/splice.c
+@@ -1081,8 +1081,8 @@ EXPORT_SYMBOL(generic_splice_sendpage);
+ /*
+ * Attempt to initiate a splice from pipe to file.
+ */
+-static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
+- loff_t *ppos, size_t len, unsigned int flags)
++long vfs_splice_from(struct pipe_inode_info *pipe, struct file *out,
++ loff_t *ppos, size_t len, unsigned int flags)
+ {
+ ssize_t (*splice_write)(struct pipe_inode_info *, struct file *,
+ loff_t *, size_t, unsigned int);
+@@ -1105,13 +1105,14 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
+
+ return splice_write(pipe, out, ppos, len, flags);
+ }
++EXPORT_SYMBOL_GPL(vfs_splice_from);
+
+ /*
+ * Attempt to initiate a splice from a file to a pipe.
+ */
+-static long do_splice_to(struct file *in, loff_t *ppos,
+- struct pipe_inode_info *pipe, size_t len,
+- unsigned int flags)
++long vfs_splice_to(struct file *in, loff_t *ppos,
++ struct pipe_inode_info *pipe, size_t len,
++ unsigned int flags)
+ {
+ ssize_t (*splice_read)(struct file *, loff_t *,
+ struct pipe_inode_info *, size_t, unsigned int);
+@@ -1131,6 +1132,7 @@ static long do_splice_to(struct file *in, loff_t *ppos,
+
+ return splice_read(in, ppos, pipe, len, flags);
+ }
++EXPORT_SYMBOL_GPL(vfs_splice_to);
+
+ /**
+ * splice_direct_to_actor - splices data directly between two non-pipes
+@@ -1200,7 +1202,7 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd,
+ size_t read_len;
+ loff_t pos = sd->pos, prev_pos = pos;
+
+- ret = do_splice_to(in, &pos, pipe, len, flags);
++ ret = vfs_splice_to(in, &pos, pipe, len, flags);
+ if (unlikely(ret <= 0))
+ goto out_release;
+
+@@ -1259,8 +1261,8 @@ static int direct_splice_actor(struct pipe_inode_info *pipe,
+ {
+ struct file *file = sd->u.file;
+
+- return do_splice_from(pipe, file, &file->f_pos, sd->total_len,
+- sd->flags);
++ return vfs_splice_from(pipe, file, &file->f_pos, sd->total_len,
++ sd->flags);
+ }
+
+ /**
+@@ -1345,7 +1347,7 @@ static long do_splice(struct file *in, loff_t __user *off_in,
+ } else
+ off = &out->f_pos;
+
+- ret = do_splice_from(ipipe, out, off, len, flags);
++ ret = vfs_splice_from(ipipe, out, off, len, flags);
+
+ if (off_out && copy_to_user(off_out, off, sizeof(loff_t)))
+ ret = -EFAULT;
+@@ -1365,7 +1367,7 @@ static long do_splice(struct file *in, loff_t __user *off_in,
+ } else
+ off = &in->f_pos;
+
+- ret = do_splice_to(in, off, opipe, len, flags);
++ ret = vfs_splice_to(in, off, opipe, len, flags);
+
+ if (off_in && copy_to_user(off_in, off, sizeof(loff_t)))
+ ret = -EFAULT;
+diff --git a/fs/stack.c b/fs/stack.c
+index 4a6f7f4..7eeef12 100644
+--- a/fs/stack.c
++++ b/fs/stack.c
+@@ -1,8 +1,20 @@
++/*
++ * Copyright (c) 2006-2009 Erez Zadok
++ * Copyright (c) 2006-2007 Josef 'Jeff' Sipek
++ * Copyright (c) 2006-2009 Stony Brook University
++ * Copyright (c) 2006-2009 The Research Foundation of SUNY
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
+ #include <linux/module.h>
+ #include <linux/fs.h>
+ #include <linux/fs_stack.h>
+
+-/* does _NOT_ require i_mutex to be held.
++/*
++ * does _NOT_ require i_mutex to be held.
+ *
+ * This function cannot be inlined since i_size_{read,write} is rather
+ * heavy-weight on 32-bit systems
+diff --git a/fs/unionfs/Kconfig b/fs/unionfs/Kconfig
+new file mode 100644
+index 0000000..f3c1ac4
+--- /dev/null
++++ b/fs/unionfs/Kconfig
+@@ -0,0 +1,24 @@
++config UNION_FS
++ tristate "Union file system (EXPERIMENTAL)"
++ depends on EXPERIMENTAL
++ help
++ Unionfs is a stackable unification file system, which appears to
++ merge the contents of several directories (branches), while keeping
++ their physical content separate.
++
++ See <http://unionfs.filesystems.org> for details
++
++config UNION_FS_XATTR
++ bool "Unionfs extended attributes"
++ depends on UNION_FS
++ help
++ Extended attributes are name:value pairs associated with inodes by
++ the kernel or by users (see the attr(5) manual page).
++
++ If unsure, say N.
++
++config UNION_FS_DEBUG
++ bool "Debug Unionfs"
++ depends on UNION_FS
++ help
++ If you say Y here, you can turn on debugging output from Unionfs.
+diff --git a/fs/unionfs/Makefile b/fs/unionfs/Makefile
+new file mode 100644
+index 0000000..3e31847
+--- /dev/null
++++ b/fs/unionfs/Makefile
+@@ -0,0 +1,17 @@
++UNIONFS_VERSION="2.5.9 (for 2.6.39-rc5)"
++
++EXTRA_CFLAGS += -DUNIONFS_VERSION=\"$(UNIONFS_VERSION)\"
++
++obj-$(CONFIG_UNION_FS) += unionfs.o
++
++unionfs-y := subr.o dentry.o file.o inode.o main.o super.o \
++ rdstate.o copyup.o dirhelper.o rename.o unlink.o \
++ lookup.o commonfops.o dirfops.o sioq.o mmap.o whiteout.o
++
++unionfs-$(CONFIG_UNION_FS_XATTR) += xattr.o
++
++unionfs-$(CONFIG_UNION_FS_DEBUG) += debug.o
++
++ifeq ($(CONFIG_UNION_FS_DEBUG),y)
++EXTRA_CFLAGS += -DDEBUG
++endif
+diff --git a/fs/unionfs/commonfops.c b/fs/unionfs/commonfops.c
+new file mode 100644
+index 0000000..9f63b1c
+--- /dev/null
++++ b/fs/unionfs/commonfops.c
+@@ -0,0 +1,898 @@
++/*
++ * Copyright (c) 2003-2011 Erez Zadok
++ * Copyright (c) 2003-2006 Charles P. Wright
++ * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
++ * Copyright (c) 2005-2006 Junjiro Okajima
++ * Copyright (c) 2005 Arun M. Krishnakumar
++ * Copyright (c) 2004-2006 David P. Quigley
++ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
++ * Copyright (c) 2003 Puja Gupta
++ * Copyright (c) 2003 Harikesavan Krishnan
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 The Research Foundation of SUNY
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "union.h"
++
++/*
++ * 1) Copyup the file
++ * 2) Rename the file to '.unionfs<original inode#><counter>' - obviously
++ * stolen from NFS's silly rename
++ */
++static int copyup_deleted_file(struct file *file, struct dentry *dentry,
++ struct dentry *parent, int bstart, int bindex)
++{
++ static unsigned int counter;
++ const int i_inosize = sizeof(dentry->d_inode->i_ino) * 2;
++ const int countersize = sizeof(counter) * 2;
++ const int nlen = sizeof(".unionfs") + i_inosize + countersize - 1;
++ char name[nlen + 1];
++ int err;
++ struct dentry *tmp_dentry = NULL;
++ struct dentry *lower_dentry;
++ struct dentry *lower_dir_dentry = NULL;
++
++ lower_dentry = unionfs_lower_dentry_idx(dentry, bstart);
++
++ sprintf(name, ".unionfs%*.*lx",
++ i_inosize, i_inosize, lower_dentry->d_inode->i_ino);
++
++ /*
++ * Loop, looking for an unused temp name to copyup to.
++ *
++ * It's somewhat silly that we look for a free temp tmp name in the
++ * source branch (bstart) instead of the dest branch (bindex), where
++ * the final name will be created. We _will_ catch it if somehow
++ * the name exists in the dest branch, but it'd be nice to catch it
++ * sooner than later.
++ */
++retry:
++ tmp_dentry = NULL;
++ do {
++ char *suffix = name + nlen - countersize;
++
++ dput(tmp_dentry);
++ counter++;
++ sprintf(suffix, "%*.*x", countersize, countersize, counter);
++
++ pr_debug("unionfs: trying to rename %s to %s\n",
++ dentry->d_name.name, name);
++
++ tmp_dentry = lookup_lck_len(name, lower_dentry->d_parent,
++ nlen);
++ if (IS_ERR(tmp_dentry)) {
++ err = PTR_ERR(tmp_dentry);
++ goto out;
++ }
++ } while (tmp_dentry->d_inode != NULL); /* need negative dentry */
++ dput(tmp_dentry);
++
++ err = copyup_named_file(parent->d_inode, file, name, bstart, bindex,
++ i_size_read(file->f_path.dentry->d_inode));
++ if (err) {
++ if (unlikely(err == -EEXIST))
++ goto retry;
++ goto out;
++ }
++
++ /* bring it to the same state as an unlinked file */
++ lower_dentry = unionfs_lower_dentry_idx(dentry, dbstart(dentry));
++ if (!unionfs_lower_inode_idx(dentry->d_inode, bindex)) {
++ atomic_inc(&lower_dentry->d_inode->i_count);
++ unionfs_set_lower_inode_idx(dentry->d_inode, bindex,
++ lower_dentry->d_inode);
++ }
++ lower_dir_dentry = lock_parent(lower_dentry);
++ err = vfs_unlink(lower_dir_dentry->d_inode, lower_dentry);
++ unlock_dir(lower_dir_dentry);
++
++out:
++ if (!err)
++ unionfs_check_dentry(dentry);
++ return err;
++}
++
++/*
++ * put all references held by upper struct file and free lower file pointer
++ * array
++ */
++static void cleanup_file(struct file *file)
++{
++ int bindex, bstart, bend;
++ struct file **lower_files;
++ struct file *lower_file;
++ struct super_block *sb = file->f_path.dentry->d_sb;
++
++ lower_files = UNIONFS_F(file)->lower_files;
++ bstart = fbstart(file);
++ bend = fbend(file);
++
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ int i; /* holds (possibly) updated branch index */
++ int old_bid;
++
++ lower_file = unionfs_lower_file_idx(file, bindex);
++ if (!lower_file)
++ continue;
++
++ /*
++ * Find new index of matching branch with an open
++ * file, since branches could have been added or
++ * deleted causing the one with open files to shift.
++ */
++ old_bid = UNIONFS_F(file)->saved_branch_ids[bindex];
++ i = branch_id_to_idx(sb, old_bid);
++ if (unlikely(i < 0)) {
++ printk(KERN_ERR "unionfs: no superblock for "
++ "file %p\n", file);
++ continue;
++ }
++
++ /* decrement count of open files */
++ branchput(sb, i);
++ /*
++ * fput will perform an mntput for us on the correct branch.
++ * Although we're using the file's old branch configuration,
++ * bindex, which is the old index, correctly points to the
++ * right branch in the file's branch list. In other words,
++ * we're going to mntput the correct branch even if branches
++ * have been added/removed.
++ */
++ fput(lower_file);
++ UNIONFS_F(file)->lower_files[bindex] = NULL;
++ UNIONFS_F(file)->saved_branch_ids[bindex] = -1;
++ }
++
++ UNIONFS_F(file)->lower_files = NULL;
++ kfree(lower_files);
++ kfree(UNIONFS_F(file)->saved_branch_ids);
++ /* set to NULL because caller needs to know if to kfree on error */
++ UNIONFS_F(file)->saved_branch_ids = NULL;
++}
++
++/* open all lower files for a given file */
++static int open_all_files(struct file *file)
++{
++ int bindex, bstart, bend, err = 0;
++ struct file *lower_file;
++ struct dentry *lower_dentry;
++ struct dentry *dentry = file->f_path.dentry;
++ struct super_block *sb = dentry->d_sb;
++
++ bstart = dbstart(dentry);
++ bend = dbend(dentry);
++
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
++ if (!lower_dentry)
++ continue;
++
++ dget(lower_dentry);
++ unionfs_mntget(dentry, bindex);
++ branchget(sb, bindex);
++
++ lower_file =
++ dentry_open(lower_dentry,
++ unionfs_lower_mnt_idx(dentry, bindex),
++ file->f_flags, current_cred());
++ if (IS_ERR(lower_file)) {
++ branchput(sb, bindex);
++ err = PTR_ERR(lower_file);
++ goto out;
++ } else {
++ unionfs_set_lower_file_idx(file, bindex, lower_file);
++ }
++ }
++out:
++ return err;
++}
++
++/* open the highest priority file for a given upper file */
++static int open_highest_file(struct file *file, bool willwrite)
++{
++ int bindex, bstart, bend, err = 0;
++ struct file *lower_file;
++ struct dentry *lower_dentry;
++ struct dentry *dentry = file->f_path.dentry;
++ struct dentry *parent = dget_parent(dentry);
++ struct inode *parent_inode = parent->d_inode;
++ struct super_block *sb = dentry->d_sb;
++
++ bstart = dbstart(dentry);
++ bend = dbend(dentry);
++
++ lower_dentry = unionfs_lower_dentry(dentry);
++ if (willwrite && IS_WRITE_FLAG(file->f_flags) && is_robranch(dentry)) {
++ for (bindex = bstart - 1; bindex >= 0; bindex--) {
++ err = copyup_file(parent_inode, file, bstart, bindex,
++ i_size_read(dentry->d_inode));
++ if (!err)
++ break;
++ }
++ atomic_set(&UNIONFS_F(file)->generation,
++ atomic_read(&UNIONFS_I(dentry->d_inode)->
++ generation));
++ goto out;
++ }
++
++ dget(lower_dentry);
++ unionfs_mntget(dentry, bstart);
++ lower_file = dentry_open(lower_dentry,
++ unionfs_lower_mnt_idx(dentry, bstart),
++ file->f_flags, current_cred());
++ if (IS_ERR(lower_file)) {
++ err = PTR_ERR(lower_file);
++ goto out;
++ }
++ branchget(sb, bstart);
++ unionfs_set_lower_file(file, lower_file);
++ /* Fix up the position. */
++ lower_file->f_pos = file->f_pos;
++
++ memcpy(&lower_file->f_ra, &file->f_ra, sizeof(struct file_ra_state));
++out:
++ dput(parent);
++ return err;
++}
++
++/* perform a delayed copyup of a read-write file on a read-only branch */
++static int do_delayed_copyup(struct file *file, struct dentry *parent)
++{
++ int bindex, bstart, bend, err = 0;
++ struct dentry *dentry = file->f_path.dentry;
++ struct inode *parent_inode = parent->d_inode;
++
++ bstart = fbstart(file);
++ bend = fbend(file);
++
++ BUG_ON(!S_ISREG(dentry->d_inode->i_mode));
++
++ unionfs_check_file(file);
++ for (bindex = bstart - 1; bindex >= 0; bindex--) {
++ if (!d_deleted(dentry))
++ err = copyup_file(parent_inode, file, bstart,
++ bindex,
++ i_size_read(dentry->d_inode));
++ else
++ err = copyup_deleted_file(file, dentry, parent,
++ bstart, bindex);
++ /* if succeeded, set lower open-file flags and break */
++ if (!err) {
++ struct file *lower_file;
++ lower_file = unionfs_lower_file_idx(file, bindex);
++ lower_file->f_flags = file->f_flags;
++ break;
++ }
++ }
++ if (err || (bstart <= fbstart(file)))
++ goto out;
++ bend = fbend(file);
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ if (unionfs_lower_file_idx(file, bindex)) {
++ branchput(dentry->d_sb, bindex);
++ fput(unionfs_lower_file_idx(file, bindex));
++ unionfs_set_lower_file_idx(file, bindex, NULL);
++ }
++ }
++ path_put_lowers(dentry, bstart, bend, false);
++ iput_lowers(dentry->d_inode, bstart, bend, false);
++ /* for reg file, we only open it "once" */
++ fbend(file) = fbstart(file);
++ dbend(dentry) = dbstart(dentry);
++ ibend(dentry->d_inode) = ibstart(dentry->d_inode);
++
++out:
++ unionfs_check_file(file);
++ return err;
++}
++
++/*
++ * Helper function for unionfs_file_revalidate/locked.
++ * Expects dentry/parent to be locked already, and revalidated.
++ */
++static int __unionfs_file_revalidate(struct file *file, struct dentry *dentry,
++ struct dentry *parent,
++ struct super_block *sb, int sbgen,
++ int dgen, bool willwrite)
++{
++ int fgen;
++ int bstart, bend, orig_brid;
++ int size;
++ int err = 0;
++
++ fgen = atomic_read(&UNIONFS_F(file)->generation);
++
++ /*
++ * There are two cases we are interested in. The first is if the
++ * generation is lower than the super-block. The second is if
++ * someone has copied up this file from underneath us, we also need
++ * to refresh things.
++ */
++ if ((d_deleted(dentry) && dbstart(dentry) >= fbstart(file)) ||
++ (sbgen <= fgen &&
++ dbstart(dentry) == fbstart(file) &&
++ unionfs_lower_file(file)))
++ goto out_may_copyup;
++
++ /* save orig branch ID */
++ orig_brid = UNIONFS_F(file)->saved_branch_ids[fbstart(file)];
++
++ /* First we throw out the existing files. */
++ cleanup_file(file);
++
++ /* Now we reopen the file(s) as in unionfs_open. */
++ bstart = fbstart(file) = dbstart(dentry);
++ bend = fbend(file) = dbend(dentry);
++
++ size = sizeof(struct file *) * sbmax(sb);
++ UNIONFS_F(file)->lower_files = kzalloc(size, GFP_KERNEL);
++ if (unlikely(!UNIONFS_F(file)->lower_files)) {
++ err = -ENOMEM;
++ goto out;
++ }
++ size = sizeof(int) * sbmax(sb);
++ UNIONFS_F(file)->saved_branch_ids = kzalloc(size, GFP_KERNEL);
++ if (unlikely(!UNIONFS_F(file)->saved_branch_ids)) {
++ err = -ENOMEM;
++ goto out;
++ }
++
++ if (S_ISDIR(dentry->d_inode->i_mode)) {
++ /* We need to open all the files. */
++ err = open_all_files(file);
++ if (err)
++ goto out;
++ } else {
++ int new_brid;
++ /* We only open the highest priority branch. */
++ err = open_highest_file(file, willwrite);
++ if (err)
++ goto out;
++ new_brid = UNIONFS_F(file)->saved_branch_ids[fbstart(file)];
++ if (unlikely(new_brid != orig_brid && sbgen > fgen)) {
++ /*
++ * If we re-opened the file on a different branch
++ * than the original one, and this was due to a new
++ * branch inserted, then update the mnt counts of
++ * the old and new branches accordingly.
++ */
++ unionfs_mntget(dentry, bstart);
++ unionfs_mntput(sb->s_root,
++ branch_id_to_idx(sb, orig_brid));
++ }
++ /* regular files have only one open lower file */
++ fbend(file) = fbstart(file);
++ }
++ atomic_set(&UNIONFS_F(file)->generation,
++ atomic_read(&UNIONFS_I(dentry->d_inode)->generation));
++
++out_may_copyup:
++ /* Copyup on the first write to a file on a readonly branch. */
++ if (willwrite && IS_WRITE_FLAG(file->f_flags) &&
++ !IS_WRITE_FLAG(unionfs_lower_file(file)->f_flags) &&
++ is_robranch(dentry)) {
++ pr_debug("unionfs: do delay copyup of \"%s\"\n",
++ dentry->d_name.name);
++ err = do_delayed_copyup(file, parent);
++ /* regular files have only one open lower file */
++ if (!err && !S_ISDIR(dentry->d_inode->i_mode))
++ fbend(file) = fbstart(file);
++ }
++
++out:
++ if (err) {
++ kfree(UNIONFS_F(file)->lower_files);
++ kfree(UNIONFS_F(file)->saved_branch_ids);
++ }
++ return err;
++}
++
++/*
++ * Revalidate the struct file
++ * @file: file to revalidate
++ * @parent: parent dentry (locked by caller)
++ * @willwrite: true if caller may cause changes to the file; false otherwise.
++ * Caller must lock/unlock dentry's branch configuration.
++ */
++int unionfs_file_revalidate(struct file *file, struct dentry *parent,
++ bool willwrite)
++{
++ struct super_block *sb;
++ struct dentry *dentry;
++ int sbgen, dgen;
++ int err = 0;
++
++ dentry = file->f_path.dentry;
++ sb = dentry->d_sb;
++ verify_locked(dentry);
++ verify_locked(parent);
++
++ /*
++ * First revalidate the dentry inside struct file,
++ * but not unhashed dentries.
++ */
++ if (!d_deleted(dentry) &&
++ !__unionfs_d_revalidate(dentry, parent, willwrite)) {
++ err = -ESTALE;
++ goto out;
++ }
++
++ sbgen = atomic_read(&UNIONFS_SB(sb)->generation);
++ dgen = atomic_read(&UNIONFS_D(dentry)->generation);
++
++ if (unlikely(sbgen > dgen)) { /* XXX: should never happen */
++ pr_debug("unionfs: failed to revalidate dentry (%s)\n",
++ dentry->d_name.name);
++ err = -ESTALE;
++ goto out;
++ }
++
++ err = __unionfs_file_revalidate(file, dentry, parent, sb,
++ sbgen, dgen, willwrite);
++out:
++ return err;
++}
++
++/* unionfs_open helper function: open a directory */
++static int __open_dir(struct inode *inode, struct file *file)
++{
++ struct dentry *lower_dentry;
++ struct file *lower_file;
++ int bindex, bstart, bend;
++ struct vfsmount *mnt;
++
++ bstart = fbstart(file) = dbstart(file->f_path.dentry);
++ bend = fbend(file) = dbend(file->f_path.dentry);
++
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ lower_dentry =
++ unionfs_lower_dentry_idx(file->f_path.dentry, bindex);
++ if (!lower_dentry)
++ continue;
++
++ dget(lower_dentry);
++ unionfs_mntget(file->f_path.dentry, bindex);
++ mnt = unionfs_lower_mnt_idx(file->f_path.dentry, bindex);
++ lower_file = dentry_open(lower_dentry, mnt, file->f_flags,
++ current_cred());
++ if (IS_ERR(lower_file))
++ return PTR_ERR(lower_file);
++
++ unionfs_set_lower_file_idx(file, bindex, lower_file);
++
++ /*
++ * The branchget goes after the open, because otherwise
++ * we would miss the reference on release.
++ */
++ branchget(inode->i_sb, bindex);
++ }
++
++ return 0;
++}
++
++/* unionfs_open helper function: open a file */
++static int __open_file(struct inode *inode, struct file *file,
++ struct dentry *parent)
++{
++ struct dentry *lower_dentry;
++ struct file *lower_file;
++ int lower_flags;
++ int bindex, bstart, bend;
++
++ lower_dentry = unionfs_lower_dentry(file->f_path.dentry);
++ lower_flags = file->f_flags;
++
++ bstart = fbstart(file) = dbstart(file->f_path.dentry);
++ bend = fbend(file) = dbend(file->f_path.dentry);
++
++ /*
++ * check for the permission for lower file. If the error is
++ * COPYUP_ERR, copyup the file.
++ */
++ if (lower_dentry->d_inode && is_robranch(file->f_path.dentry)) {
++ /*
++ * if the open will change the file, copy it up otherwise
++ * defer it.
++ */
++ if (lower_flags & O_TRUNC) {
++ int size = 0;
++ int err = -EROFS;
++
++ /* copyup the file */
++ for (bindex = bstart - 1; bindex >= 0; bindex--) {
++ err = copyup_file(parent->d_inode, file,
++ bstart, bindex, size);
++ if (!err) {
++ /* only one regular file open */
++ fbend(file) = fbstart(file);
++ break;
++ }
++ }
++ return err;
++ } else {
++ /*
++ * turn off writeable flags, to force delayed copyup
++ * by caller.
++ */
++ lower_flags &= ~(OPEN_WRITE_FLAGS);
++ }
++ }
++
++ dget(lower_dentry);
++
++ /*
++ * dentry_open will decrement mnt refcnt if err.
++ * otherwise fput() will do an mntput() for us upon file close.
++ */
++ unionfs_mntget(file->f_path.dentry, bstart);
++ lower_file =
++ dentry_open(lower_dentry,
++ unionfs_lower_mnt_idx(file->f_path.dentry, bstart),
++ lower_flags, current_cred());
++ if (IS_ERR(lower_file))
++ return PTR_ERR(lower_file);
++
++ unionfs_set_lower_file(file, lower_file);
++ branchget(inode->i_sb, bstart);
++
++ return 0;
++}
++
++int unionfs_open(struct inode *inode, struct file *file)
++{
++ int err = 0;
++ struct file *lower_file = NULL;
++ struct dentry *dentry = file->f_path.dentry;
++ struct dentry *parent;
++ int bindex = 0, bstart = 0, bend = 0;
++ int size;
++ int valid = 0;
++
++ unionfs_read_lock(inode->i_sb, UNIONFS_SMUTEX_PARENT);
++ parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ /* don't open unhashed/deleted files */
++ if (d_deleted(dentry)) {
++ err = -ENOENT;
++ goto out_nofree;
++ }
++
++ /* XXX: should I change 'false' below to the 'willwrite' flag? */
++ valid = __unionfs_d_revalidate(dentry, parent, false);
++ if (unlikely(!valid)) {
++ err = -ESTALE;
++ goto out_nofree;
++ }
++
++ file->private_data =
++ kzalloc(sizeof(struct unionfs_file_info), GFP_KERNEL);
++ if (unlikely(!UNIONFS_F(file))) {
++ err = -ENOMEM;
++ goto out_nofree;
++ }
++ fbstart(file) = -1;
++ fbend(file) = -1;
++ atomic_set(&UNIONFS_F(file)->generation,
++ atomic_read(&UNIONFS_I(inode)->generation));
++
++ size = sizeof(struct file *) * sbmax(inode->i_sb);
++ UNIONFS_F(file)->lower_files = kzalloc(size, GFP_KERNEL);
++ if (unlikely(!UNIONFS_F(file)->lower_files)) {
++ err = -ENOMEM;
++ goto out;
++ }
++ size = sizeof(int) * sbmax(inode->i_sb);
++ UNIONFS_F(file)->saved_branch_ids = kzalloc(size, GFP_KERNEL);
++ if (unlikely(!UNIONFS_F(file)->saved_branch_ids)) {
++ err = -ENOMEM;
++ goto out;
++ }
++
++ bstart = fbstart(file) = dbstart(dentry);
++ bend = fbend(file) = dbend(dentry);
++
++ /*
++ * open all directories and make the unionfs file struct point to
++ * these lower file structs
++ */
++ if (S_ISDIR(inode->i_mode))
++ err = __open_dir(inode, file); /* open a dir */
++ else
++ err = __open_file(inode, file, parent); /* open a file */
++
++ /* freeing the allocated resources, and fput the opened files */
++ if (err) {
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ lower_file = unionfs_lower_file_idx(file, bindex);
++ if (!lower_file)
++ continue;
++
++ branchput(dentry->d_sb, bindex);
++ /* fput calls dput for lower_dentry */
++ fput(lower_file);
++ }
++ }
++
++out:
++ if (err) {
++ kfree(UNIONFS_F(file)->lower_files);
++ kfree(UNIONFS_F(file)->saved_branch_ids);
++ kfree(UNIONFS_F(file));
++ }
++out_nofree:
++ if (!err) {
++ unionfs_postcopyup_setmnt(dentry);
++ unionfs_copy_attr_times(inode);
++ unionfs_check_file(file);
++ unionfs_check_inode(inode);
++ }
++ unionfs_unlock_dentry(dentry);
++ unionfs_unlock_parent(dentry, parent);
++ unionfs_read_unlock(inode->i_sb);
++ return err;
++}
++
++/*
++ * release all lower object references & free the file info structure
++ *
++ * No need to grab sb info's rwsem.
++ */
++int unionfs_file_release(struct inode *inode, struct file *file)
++{
++ struct file *lower_file = NULL;
++ struct unionfs_file_info *fileinfo;
++ struct unionfs_inode_info *inodeinfo;
++ struct super_block *sb = inode->i_sb;
++ struct dentry *dentry = file->f_path.dentry;
++ struct dentry *parent;
++ int bindex, bstart, bend;
++ int err = 0;
++
++ /*
++ * Since mm/memory.c:might_fault() (under PROVE_LOCKING) was
++ * modified in 2.6.29-rc1 to call might_lock_read on mmap_sem, this
++ * has been causing false positives in file system stacking layers.
++ * In particular, our ->mmap is called after sys_mmap2 already holds
++ * mmap_sem, then we lock our own mutexes; but earlier, it's
++ * possible for lockdep to have locked our mutexes first, and then
++ * we call a lower ->readdir which could call might_fault. The
++ * different ordering of the locks is what lockdep complains about
++ * -- unnecessarily. Therefore, we have no choice but to tell
++ * lockdep to temporarily turn off lockdep here. Note: the comments
++ * inside might_sleep also suggest that it would have been
++ * nicer to only annotate paths that needs that might_lock_read.
++ */
++ lockdep_off();
++ unionfs_read_lock(sb, UNIONFS_SMUTEX_PARENT);
++ parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ /*
++ * We try to revalidate, but the VFS ignores return return values
++ * from file->release, so we must always try to succeed here,
++ * including to do the kfree and dput below. So if revalidation
++ * failed, all we can do is print some message and keep going.
++ */
++ err = unionfs_file_revalidate(file, parent,
++ UNIONFS_F(file)->wrote_to_file);
++ if (!err)
++ unionfs_check_file(file);
++ fileinfo = UNIONFS_F(file);
++ BUG_ON(file->f_path.dentry->d_inode != inode);
++ inodeinfo = UNIONFS_I(inode);
++
++ /* fput all the lower files */
++ bstart = fbstart(file);
++ bend = fbend(file);
++
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ lower_file = unionfs_lower_file_idx(file, bindex);
++
++ if (lower_file) {
++ unionfs_set_lower_file_idx(file, bindex, NULL);
++ fput(lower_file);
++ branchput(sb, bindex);
++ }
++
++ /* if there are no more refs to the dentry, dput it */
++ if (d_deleted(dentry)) {
++ dput(unionfs_lower_dentry_idx(dentry, bindex));
++ unionfs_set_lower_dentry_idx(dentry, bindex, NULL);
++ }
++ }
++
++ kfree(fileinfo->lower_files);
++ kfree(fileinfo->saved_branch_ids);
++
++ if (fileinfo->rdstate) {
++ fileinfo->rdstate->access = jiffies;
++ spin_lock(&inodeinfo->rdlock);
++ inodeinfo->rdcount++;
++ list_add_tail(&fileinfo->rdstate->cache,
++ &inodeinfo->readdircache);
++ mark_inode_dirty(inode);
++ spin_unlock(&inodeinfo->rdlock);
++ fileinfo->rdstate = NULL;
++ }
++ kfree(fileinfo);
++
++ unionfs_unlock_dentry(dentry);
++ unionfs_unlock_parent(dentry, parent);
++ unionfs_read_unlock(sb);
++ lockdep_on();
++ return err;
++}
++
++/* pass the ioctl to the lower fs */
++static long do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++{
++ struct file *lower_file;
++ int err;
++
++ lower_file = unionfs_lower_file(file);
++
++ err = -ENOTTY;
++ if (!lower_file || !lower_file->f_op)
++ goto out;
++ if (lower_file->f_op->unlocked_ioctl) {
++ err = lower_file->f_op->unlocked_ioctl(lower_file, cmd, arg);
++#ifdef CONFIG_COMPAT
++ } else if (lower_file->f_op->ioctl) {
++ err = lower_file->f_op->compat_ioctl(
++ lower_file->f_path.dentry->d_inode,
++ lower_file, cmd, arg);
++#endif
++ }
++
++out:
++ return err;
++}
++
++/*
++ * return to user-space the branch indices containing the file in question
++ *
++ * We use fd_set and therefore we are limited to the number of the branches
++ * to FD_SETSIZE, which is currently 1024 - plenty for most people
++ */
++static int unionfs_ioctl_queryfile(struct file *file, struct dentry *parent,
++ unsigned int cmd, unsigned long arg)
++{
++ int err = 0;
++ fd_set branchlist;
++ int bstart = 0, bend = 0, bindex = 0;
++ int orig_bstart, orig_bend;
++ struct dentry *dentry, *lower_dentry;
++ struct vfsmount *mnt;
++
++ dentry = file->f_path.dentry;
++ orig_bstart = dbstart(dentry);
++ orig_bend = dbend(dentry);
++ err = unionfs_partial_lookup(dentry, parent);
++ if (err)
++ goto out;
++ bstart = dbstart(dentry);
++ bend = dbend(dentry);
++
++ FD_ZERO(&branchlist);
++
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
++ if (!lower_dentry)
++ continue;
++ if (likely(lower_dentry->d_inode))
++ FD_SET(bindex, &branchlist);
++ /* purge any lower objects after partial_lookup */
++ if (bindex < orig_bstart || bindex > orig_bend) {
++ dput(lower_dentry);
++ unionfs_set_lower_dentry_idx(dentry, bindex, NULL);
++ iput(unionfs_lower_inode_idx(dentry->d_inode, bindex));
++ unionfs_set_lower_inode_idx(dentry->d_inode, bindex,
++ NULL);
++ mnt = unionfs_lower_mnt_idx(dentry, bindex);
++ if (!mnt)
++ continue;
++ unionfs_mntput(dentry, bindex);
++ unionfs_set_lower_mnt_idx(dentry, bindex, NULL);
++ }
++ }
++ /* restore original dentry's offsets */
++ dbstart(dentry) = orig_bstart;
++ dbend(dentry) = orig_bend;
++ ibstart(dentry->d_inode) = orig_bstart;
++ ibend(dentry->d_inode) = orig_bend;
++
++ err = copy_to_user((void __user *)arg, &branchlist, sizeof(fd_set));
++ if (unlikely(err))
++ err = -EFAULT;
++
++out:
++ return err < 0 ? err : bend;
++}
++
++long unionfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++{
++ long err;
++ struct dentry *dentry = file->f_path.dentry;
++ struct dentry *parent;
++
++ unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_PARENT);
++ parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ err = unionfs_file_revalidate(file, parent, true);
++ if (unlikely(err))
++ goto out;
++
++ /* check if asked for local commands */
++ switch (cmd) {
++ case UNIONFS_IOCTL_INCGEN:
++ /* Increment the superblock generation count */
++ pr_info("unionfs: incgen ioctl deprecated; "
++ "use \"-o remount,incgen\"\n");
++ err = -ENOSYS;
++ break;
++
++ case UNIONFS_IOCTL_QUERYFILE:
++ /* Return list of branches containing the given file */
++ err = unionfs_ioctl_queryfile(file, parent, cmd, arg);
++ break;
++
++ default:
++ /* pass the ioctl down */
++ err = do_ioctl(file, cmd, arg);
++ break;
++ }
++
++out:
++ unionfs_check_file(file);
++ unionfs_unlock_dentry(dentry);
++ unionfs_unlock_parent(dentry, parent);
++ unionfs_read_unlock(dentry->d_sb);
++ return err;
++}
++
++int unionfs_flush(struct file *file, fl_owner_t id)
++{
++ int err = 0;
++ struct file *lower_file = NULL;
++ struct dentry *dentry = file->f_path.dentry;
++ struct dentry *parent;
++ int bindex, bstart, bend;
++
++ unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_PARENT);
++ parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ err = unionfs_file_revalidate(file, parent,
++ UNIONFS_F(file)->wrote_to_file);
++ if (unlikely(err))
++ goto out;
++ unionfs_check_file(file);
++
++ bstart = fbstart(file);
++ bend = fbend(file);
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ lower_file = unionfs_lower_file_idx(file, bindex);
++
++ if (lower_file && lower_file->f_op &&
++ lower_file->f_op->flush) {
++ err = lower_file->f_op->flush(lower_file, id);
++ if (err)
++ goto out;
++ }
++
++ }
++
++out:
++ if (!err)
++ unionfs_check_file(file);
++ unionfs_unlock_dentry(dentry);
++ unionfs_unlock_parent(dentry, parent);
++ unionfs_read_unlock(dentry->d_sb);
++ return err;
++}
+diff --git a/fs/unionfs/copyup.c b/fs/unionfs/copyup.c
+new file mode 100644
+index 0000000..37c2654
+--- /dev/null
++++ b/fs/unionfs/copyup.c
+@@ -0,0 +1,896 @@
++/*
++ * Copyright (c) 2003-2011 Erez Zadok
++ * Copyright (c) 2003-2006 Charles P. Wright
++ * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
++ * Copyright (c) 2005-2006 Junjiro Okajima
++ * Copyright (c) 2005 Arun M. Krishnakumar
++ * Copyright (c) 2004-2006 David P. Quigley
++ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
++ * Copyright (c) 2003 Puja Gupta
++ * Copyright (c) 2003 Harikesavan Krishnan
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 The Research Foundation of SUNY
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "union.h"
++
++/*
++ * For detailed explanation of copyup see:
++ * Documentation/filesystems/unionfs/concepts.txt
++ */
++
++#ifdef CONFIG_UNION_FS_XATTR
++/* copyup all extended attrs for a given dentry */
++static int copyup_xattrs(struct dentry *old_lower_dentry,
++ struct dentry *new_lower_dentry)
++{
++ int err = 0;
++ ssize_t list_size = -1;
++ char *name_list = NULL;
++ char *attr_value = NULL;
++ char *name_list_buf = NULL;
++
++ /* query the actual size of the xattr list */
++ list_size = vfs_listxattr(old_lower_dentry, NULL, 0);
++ if (list_size <= 0) {
++ err = list_size;
++ goto out;
++ }
++
++ /* allocate space for the actual list */
++ name_list = unionfs_xattr_alloc(list_size + 1, XATTR_LIST_MAX);
++ if (unlikely(!name_list || IS_ERR(name_list))) {
++ err = PTR_ERR(name_list);
++ goto out;
++ }
++
++ name_list_buf = name_list; /* save for kfree at end */
++
++ /* now get the actual xattr list of the source file */
++ list_size = vfs_listxattr(old_lower_dentry, name_list, list_size);
++ if (list_size <= 0) {
++ err = list_size;
++ goto out;
++ }
++
++ /* allocate space to hold each xattr's value */
++ attr_value = unionfs_xattr_alloc(XATTR_SIZE_MAX, XATTR_SIZE_MAX);
++ if (unlikely(!attr_value || IS_ERR(attr_value))) {
++ err = PTR_ERR(name_list);
++ goto out;
++ }
++
++ /* in a loop, get and set each xattr from src to dst file */
++ while (*name_list) {
++ ssize_t size;
++
++ /* Lock here since vfs_getxattr doesn't lock for us */
++ mutex_lock(&old_lower_dentry->d_inode->i_mutex);
++ size = vfs_getxattr(old_lower_dentry, name_list,
++ attr_value, XATTR_SIZE_MAX);
++ mutex_unlock(&old_lower_dentry->d_inode->i_mutex);
++ if (size < 0) {
++ err = size;
++ goto out;
++ }
++ if (size > XATTR_SIZE_MAX) {
++ err = -E2BIG;
++ goto out;
++ }
++ /* Don't lock here since vfs_setxattr does it for us. */
++ err = vfs_setxattr(new_lower_dentry, name_list, attr_value,
++ size, 0);
++ /*
++ * Selinux depends on "security.*" xattrs, so to maintain
++ * the security of copied-up files, if Selinux is active,
++ * then we must copy these xattrs as well. So we need to
++ * temporarily get FOWNER privileges.
++ * XXX: move entire copyup code to SIOQ.
++ */
++ if (err == -EPERM && !capable(CAP_FOWNER)) {
++ const struct cred *old_creds;
++ struct cred *new_creds;
++
++ new_creds = prepare_creds();
++ if (unlikely(!new_creds)) {
++ err = -ENOMEM;
++ goto out;
++ }
++ cap_raise(new_creds->cap_effective, CAP_FOWNER);
++ old_creds = override_creds(new_creds);
++ err = vfs_setxattr(new_lower_dentry, name_list,
++ attr_value, size, 0);
++ revert_creds(old_creds);
++ }
++ if (err < 0)
++ goto out;
++ name_list += strlen(name_list) + 1;
++ }
++out:
++ unionfs_xattr_kfree(name_list_buf);
++ unionfs_xattr_kfree(attr_value);
++ /* Ignore if xattr isn't supported */
++ if (err == -ENOTSUPP || err == -EOPNOTSUPP)
++ err = 0;
++ return err;
++}
++#endif /* CONFIG_UNION_FS_XATTR */
++
++/*
++ * Determine the mode based on the copyup flags, and the existing dentry.
++ *
++ * Handle file systems which may not support certain options. For example
++ * jffs2 doesn't allow one to chmod a symlink. So we ignore such harmless
++ * errors, rather than propagating them up, which results in copyup errors
++ * and errors returned back to users.
++ */
++static int copyup_permissions(struct super_block *sb,
++ struct dentry *old_lower_dentry,
++ struct dentry *new_lower_dentry)
++{
++ struct inode *i = old_lower_dentry->d_inode;
++ struct iattr newattrs;
++ int err;
++
++ newattrs.ia_atime = i->i_atime;
++ newattrs.ia_mtime = i->i_mtime;
++ newattrs.ia_ctime = i->i_ctime;
++ newattrs.ia_gid = i->i_gid;
++ newattrs.ia_uid = i->i_uid;
++ newattrs.ia_valid = ATTR_CTIME | ATTR_ATIME | ATTR_MTIME |
++ ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_FORCE |
++ ATTR_GID | ATTR_UID;
++ mutex_lock(&new_lower_dentry->d_inode->i_mutex);
++ err = notify_change(new_lower_dentry, &newattrs);
++ if (err)
++ goto out;
++
++ /* now try to change the mode and ignore EOPNOTSUPP on symlinks */
++ newattrs.ia_mode = i->i_mode;
++ newattrs.ia_valid = ATTR_MODE | ATTR_FORCE;
++ err = notify_change(new_lower_dentry, &newattrs);
++ if (err == -EOPNOTSUPP &&
++ S_ISLNK(new_lower_dentry->d_inode->i_mode)) {
++ printk(KERN_WARNING
++ "unionfs: changing \"%s\" symlink mode unsupported\n",
++ new_lower_dentry->d_name.name);
++ err = 0;
++ }
++
++out:
++ mutex_unlock(&new_lower_dentry->d_inode->i_mutex);
++ return err;
++}
++
++/*
++ * create the new device/file/directory - use copyup_permission to copyup
++ * times, and mode
++ *
++ * if the object being copied up is a regular file, the file is only created,
++ * the contents have to be copied up separately
++ */
++static int __copyup_ndentry(struct dentry *old_lower_dentry,
++ struct dentry *new_lower_dentry,
++ struct dentry *new_lower_parent_dentry,
++ char *symbuf)
++{
++ int err = 0;
++ umode_t old_mode = old_lower_dentry->d_inode->i_mode;
++ struct sioq_args args;
++
++ if (S_ISDIR(old_mode)) {
++ args.mkdir.parent = new_lower_parent_dentry->d_inode;
++ args.mkdir.dentry = new_lower_dentry;
++ args.mkdir.mode = old_mode;
++
++ run_sioq(__unionfs_mkdir, &args);
++ err = args.err;
++ } else if (S_ISLNK(old_mode)) {
++ args.symlink.parent = new_lower_parent_dentry->d_inode;
++ args.symlink.dentry = new_lower_dentry;
++ args.symlink.symbuf = symbuf;
++
++ run_sioq(__unionfs_symlink, &args);
++ err = args.err;
++ } else if (S_ISBLK(old_mode) || S_ISCHR(old_mode) ||
++ S_ISFIFO(old_mode) || S_ISSOCK(old_mode)) {
++ args.mknod.parent = new_lower_parent_dentry->d_inode;
++ args.mknod.dentry = new_lower_dentry;
++ args.mknod.mode = old_mode;
++ args.mknod.dev = old_lower_dentry->d_inode->i_rdev;
++
++ run_sioq(__unionfs_mknod, &args);
++ err = args.err;
++ } else if (S_ISREG(old_mode)) {
++ struct nameidata nd;
++ err = init_lower_nd(&nd, LOOKUP_CREATE);
++ if (unlikely(err < 0))
++ goto out;
++ args.create.nd = &nd;
++ args.create.parent = new_lower_parent_dentry->d_inode;
++ args.create.dentry = new_lower_dentry;
++ args.create.mode = old_mode;
++
++ run_sioq(__unionfs_create, &args);
++ err = args.err;
++ release_lower_nd(&nd, err);
++ } else {
++ printk(KERN_CRIT "unionfs: unknown inode type %d\n",
++ old_mode);
++ BUG();
++ }
++
++out:
++ return err;
++}
++
++static int __copyup_reg_data(struct dentry *dentry,
++ struct dentry *new_lower_dentry, int new_bindex,
++ struct dentry *old_lower_dentry, int old_bindex,
++ struct file **copyup_file, loff_t len)
++{
++ struct super_block *sb = dentry->d_sb;
++ struct file *input_file;
++ struct file *output_file;
++ struct vfsmount *output_mnt;
++ mm_segment_t old_fs;
++ char *buf = NULL;
++ ssize_t read_bytes, write_bytes;
++ loff_t size;
++ int err = 0;
++
++ /* open old file */
++ unionfs_mntget(dentry, old_bindex);
++ branchget(sb, old_bindex);
++ /* dentry_open calls dput and mntput if it returns an error */
++ input_file = dentry_open(old_lower_dentry,
++ unionfs_lower_mnt_idx(dentry, old_bindex),
++ O_RDONLY | O_LARGEFILE, current_cred());
++ if (IS_ERR(input_file)) {
++ dput(old_lower_dentry);
++ err = PTR_ERR(input_file);
++ goto out;
++ }
++ if (unlikely(!input_file->f_op || !input_file->f_op->read)) {
++ err = -EINVAL;
++ goto out_close_in;
++ }
++
++ /* open new file */
++ dget(new_lower_dentry);
++ output_mnt = unionfs_mntget(sb->s_root, new_bindex);
++ branchget(sb, new_bindex);
++ output_file = dentry_open(new_lower_dentry, output_mnt,
++ O_RDWR | O_LARGEFILE, current_cred());
++ if (IS_ERR(output_file)) {
++ err = PTR_ERR(output_file);
++ goto out_close_in2;
++ }
++ if (unlikely(!output_file->f_op || !output_file->f_op->write)) {
++ err = -EINVAL;
++ goto out_close_out;
++ }
++
++ /* allocating a buffer */
++ buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
++ if (unlikely(!buf)) {
++ err = -ENOMEM;
++ goto out_close_out;
++ }
++
++ input_file->f_pos = 0;
++ output_file->f_pos = 0;
++
++ old_fs = get_fs();
++ set_fs(KERNEL_DS);
++
++ size = len;
++ err = 0;
++ do {
++ if (len >= PAGE_SIZE)
++ size = PAGE_SIZE;
++ else if ((len < PAGE_SIZE) && (len > 0))
++ size = len;
++
++ len -= PAGE_SIZE;
++
++ read_bytes =
++ input_file->f_op->read(input_file,
++ (char __user *)buf, size,
++ &input_file->f_pos);
++ if (read_bytes <= 0) {
++ err = read_bytes;
++ break;
++ }
++
++ /* see Documentation/filesystems/unionfs/issues.txt */
++ lockdep_off();
++ write_bytes =
++ output_file->f_op->write(output_file,
++ (char __user *)buf,
++ read_bytes,
++ &output_file->f_pos);
++ lockdep_on();
++ if ((write_bytes < 0) || (write_bytes < read_bytes)) {
++ err = write_bytes;
++ break;
++ }
++ } while ((read_bytes > 0) && (len > 0));
++
++ set_fs(old_fs);
++
++ kfree(buf);
++
++ if (!err)
++ err = output_file->f_op->fsync(output_file, 0);
++
++ if (err)
++ goto out_close_out;
++
++ if (copyup_file) {
++ *copyup_file = output_file;
++ goto out_close_in;
++ }
++
++out_close_out:
++ fput(output_file);
++
++out_close_in2:
++ branchput(sb, new_bindex);
++
++out_close_in:
++ fput(input_file);
++
++out:
++ branchput(sb, old_bindex);
++
++ return err;
++}
++
++/*
++ * dput the lower references for old and new dentry & clear a lower dentry
++ * pointer
++ */
++static void __clear(struct dentry *dentry, struct dentry *old_lower_dentry,
++ int old_bstart, int old_bend,
++ struct dentry *new_lower_dentry, int new_bindex)
++{
++ /* get rid of the lower dentry and all its traces */
++ unionfs_set_lower_dentry_idx(dentry, new_bindex, NULL);
++ dbstart(dentry) = old_bstart;
++ dbend(dentry) = old_bend;
++
++ dput(new_lower_dentry);
++ dput(old_lower_dentry);
++}
++
++/*
++ * Copy up a dentry to a file of specified name.
++ *
++ * @dir: used to pull the ->i_sb to access other branches
++ * @dentry: the non-negative dentry whose lower_inode we should copy
++ * @bstart: the branch of the lower_inode to copy from
++ * @new_bindex: the branch to create the new file in
++ * @name: the name of the file to create
++ * @namelen: length of @name
++ * @copyup_file: the "struct file" to return (optional)
++ * @len: how many bytes to copy-up?
++ */
++int copyup_dentry(struct inode *dir, struct dentry *dentry, int bstart,
++ int new_bindex, const char *name, int namelen,
++ struct file **copyup_file, loff_t len)
++{
++ struct dentry *new_lower_dentry;
++ struct dentry *old_lower_dentry = NULL;
++ struct super_block *sb;
++ int err = 0;
++ int old_bindex;
++ int old_bstart;
++ int old_bend;
++ struct dentry *new_lower_parent_dentry = NULL;
++ mm_segment_t oldfs;
++ char *symbuf = NULL;
++
++ verify_locked(dentry);
++
++ old_bindex = bstart;
++ old_bstart = dbstart(dentry);
++ old_bend = dbend(dentry);
++
++ BUG_ON(new_bindex < 0);
++ BUG_ON(new_bindex >= old_bindex);
++
++ sb = dir->i_sb;
++
++ err = is_robranch_super(sb, new_bindex);
++ if (err)
++ goto out;
++
++ /* Create the directory structure above this dentry. */
++ new_lower_dentry = create_parents(dir, dentry, name, new_bindex);
++ if (IS_ERR(new_lower_dentry)) {
++ err = PTR_ERR(new_lower_dentry);
++ goto out;
++ }
++
++ old_lower_dentry = unionfs_lower_dentry_idx(dentry, old_bindex);
++ /* we conditionally dput this old_lower_dentry at end of function */
++ dget(old_lower_dentry);
++
++ /* For symlinks, we must read the link before we lock the directory. */
++ if (S_ISLNK(old_lower_dentry->d_inode->i_mode)) {
++
++ symbuf = kmalloc(PATH_MAX, GFP_KERNEL);
++ if (unlikely(!symbuf)) {
++ __clear(dentry, old_lower_dentry,
++ old_bstart, old_bend,
++ new_lower_dentry, new_bindex);
++ err = -ENOMEM;
++ goto out_free;
++ }
++
++ oldfs = get_fs();
++ set_fs(KERNEL_DS);
++ err = old_lower_dentry->d_inode->i_op->readlink(
++ old_lower_dentry,
++ (char __user *)symbuf,
++ PATH_MAX);
++ set_fs(oldfs);
++ if (err < 0) {
++ __clear(dentry, old_lower_dentry,
++ old_bstart, old_bend,
++ new_lower_dentry, new_bindex);
++ goto out_free;
++ }
++ symbuf[err] = '\0';
++ }
++
++ /* Now we lock the parent, and create the object in the new branch. */
++ new_lower_parent_dentry = lock_parent(new_lower_dentry);
++
++ /* create the new inode */
++ err = __copyup_ndentry(old_lower_dentry, new_lower_dentry,
++ new_lower_parent_dentry, symbuf);
++
++ if (err) {
++ __clear(dentry, old_lower_dentry,
++ old_bstart, old_bend,
++ new_lower_dentry, new_bindex);
++ goto out_unlock;
++ }
++
++ /* We actually copyup the file here. */
++ if (S_ISREG(old_lower_dentry->d_inode->i_mode))
++ err = __copyup_reg_data(dentry, new_lower_dentry, new_bindex,
++ old_lower_dentry, old_bindex,
++ copyup_file, len);
++ if (err)
++ goto out_unlink;
++
++ /* Set permissions. */
++ err = copyup_permissions(sb, old_lower_dentry, new_lower_dentry);
++ if (err)
++ goto out_unlink;
++
++#ifdef CONFIG_UNION_FS_XATTR
++ /* Selinux uses extended attributes for permissions. */
++ err = copyup_xattrs(old_lower_dentry, new_lower_dentry);
++ if (err)
++ goto out_unlink;
++#endif /* CONFIG_UNION_FS_XATTR */
++
++ /* do not allow files getting deleted to be re-interposed */
++ if (!d_deleted(dentry))
++ unionfs_reinterpose(dentry);
++
++ goto out_unlock;
++
++out_unlink:
++ /*
++ * copyup failed, because we possibly ran out of space or
++ * quota, or something else happened so let's unlink; we don't
++ * really care about the return value of vfs_unlink
++ */
++ vfs_unlink(new_lower_parent_dentry->d_inode, new_lower_dentry);
++
++ if (copyup_file) {
++ /* need to close the file */
++
++ fput(*copyup_file);
++ branchput(sb, new_bindex);
++ }
++
++ /*
++ * TODO: should we reset the error to something like -EIO?
++ *
++ * If we don't reset, the user may get some nonsensical errors, but
++ * on the other hand, if we reset to EIO, we guarantee that the user
++ * will get a "confusing" error message.
++ */
++
++out_unlock:
++ unlock_dir(new_lower_parent_dentry);
++
++out_free:
++ /*
++ * If old_lower_dentry was not a file, then we need to dput it. If
++ * it was a file, then it was already dput indirectly by other
++ * functions we call above which operate on regular files.
++ */
++ if (old_lower_dentry && old_lower_dentry->d_inode &&
++ !S_ISREG(old_lower_dentry->d_inode->i_mode))
++ dput(old_lower_dentry);
++ kfree(symbuf);
++
++ if (err) {
++ /*
++ * if directory creation succeeded, but inode copyup failed,
++ * then purge new dentries.
++ */
++ if (dbstart(dentry) < old_bstart &&
++ ibstart(dentry->d_inode) > dbstart(dentry))
++ __clear(dentry, NULL, old_bstart, old_bend,
++ unionfs_lower_dentry(dentry), dbstart(dentry));
++ goto out;
++ }
++ if (!S_ISDIR(dentry->d_inode->i_mode)) {
++ unionfs_postcopyup_release(dentry);
++ if (!unionfs_lower_inode(dentry->d_inode)) {
++ /*
++ * If we got here, then we copied up to an
++ * unlinked-open file, whose name is .unionfsXXXXX.
++ */
++ struct inode *inode = new_lower_dentry->d_inode;
++ atomic_inc(&inode->i_count);
++ unionfs_set_lower_inode_idx(dentry->d_inode,
++ ibstart(dentry->d_inode),
++ inode);
++ }
++ }
++ unionfs_postcopyup_setmnt(dentry);
++ /* sync inode times from copied-up inode to our inode */
++ unionfs_copy_attr_times(dentry->d_inode);
++ unionfs_check_inode(dir);
++ unionfs_check_dentry(dentry);
++out:
++ return err;
++}
++
++/*
++ * This function creates a copy of a file represented by 'file' which
++ * currently resides in branch 'bstart' to branch 'new_bindex.' The copy
++ * will be named "name".
++ */
++int copyup_named_file(struct inode *dir, struct file *file, char *name,
++ int bstart, int new_bindex, loff_t len)
++{
++ int err = 0;
++ struct file *output_file = NULL;
++
++ err = copyup_dentry(dir, file->f_path.dentry, bstart, new_bindex,
++ name, strlen(name), &output_file, len);
++ if (!err) {
++ fbstart(file) = new_bindex;
++ unionfs_set_lower_file_idx(file, new_bindex, output_file);
++ }
++
++ return err;
++}
++
++/*
++ * This function creates a copy of a file represented by 'file' which
++ * currently resides in branch 'bstart' to branch 'new_bindex'.
++ */
++int copyup_file(struct inode *dir, struct file *file, int bstart,
++ int new_bindex, loff_t len)
++{
++ int err = 0;
++ struct file *output_file = NULL;
++ struct dentry *dentry = file->f_path.dentry;
++
++ err = copyup_dentry(dir, dentry, bstart, new_bindex,
++ dentry->d_name.name, dentry->d_name.len,
++ &output_file, len);
++ if (!err) {
++ fbstart(file) = new_bindex;
++ unionfs_set_lower_file_idx(file, new_bindex, output_file);
++ }
++
++ return err;
++}
++
++/* purge a dentry's lower-branch states (dput/mntput, etc.) */
++static void __cleanup_dentry(struct dentry *dentry, int bindex,
++ int old_bstart, int old_bend)
++{
++ int loop_start;
++ int loop_end;
++ int new_bstart = -1;
++ int new_bend = -1;
++ int i;
++
++ loop_start = min(old_bstart, bindex);
++ loop_end = max(old_bend, bindex);
++
++ /*
++ * This loop sets the bstart and bend for the new dentry by
++ * traversing from left to right. It also dputs all negative
++ * dentries except bindex
++ */
++ for (i = loop_start; i <= loop_end; i++) {
++ if (!unionfs_lower_dentry_idx(dentry, i))
++ continue;
++
++ if (i == bindex) {
++ new_bend = i;
++ if (new_bstart < 0)
++ new_bstart = i;
++ continue;
++ }
++
++ if (!unionfs_lower_dentry_idx(dentry, i)->d_inode) {
++ dput(unionfs_lower_dentry_idx(dentry, i));
++ unionfs_set_lower_dentry_idx(dentry, i, NULL);
++
++ unionfs_mntput(dentry, i);
++ unionfs_set_lower_mnt_idx(dentry, i, NULL);
++ } else {
++ if (new_bstart < 0)
++ new_bstart = i;
++ new_bend = i;
++ }
++ }
++
++ if (new_bstart < 0)
++ new_bstart = bindex;
++ if (new_bend < 0)
++ new_bend = bindex;
++ dbstart(dentry) = new_bstart;
++ dbend(dentry) = new_bend;
++
++}
++
++/* set lower inode ptr and update bstart & bend if necessary */
++static void __set_inode(struct dentry *upper, struct dentry *lower,
++ int bindex)
++{
++ unionfs_set_lower_inode_idx(upper->d_inode, bindex,
++ igrab(lower->d_inode));
++ if (likely(ibstart(upper->d_inode) > bindex))
++ ibstart(upper->d_inode) = bindex;
++ if (likely(ibend(upper->d_inode) < bindex))
++ ibend(upper->d_inode) = bindex;
++
++}
++
++/* set lower dentry ptr and update bstart & bend if necessary */
++static void __set_dentry(struct dentry *upper, struct dentry *lower,
++ int bindex)
++{
++ unionfs_set_lower_dentry_idx(upper, bindex, lower);
++ if (likely(dbstart(upper) > bindex))
++ dbstart(upper) = bindex;
++ if (likely(dbend(upper) < bindex))
++ dbend(upper) = bindex;
++}
++
++/*
++ * This function replicates the directory structure up-to given dentry
++ * in the bindex branch.
++ */
++struct dentry *create_parents(struct inode *dir, struct dentry *dentry,
++ const char *name, int bindex)
++{
++ int err;
++ struct dentry *child_dentry;
++ struct dentry *parent_dentry;
++ struct dentry *lower_parent_dentry = NULL;
++ struct dentry *lower_dentry = NULL;
++ const char *childname;
++ unsigned int childnamelen;
++ int nr_dentry;
++ int count = 0;
++ int old_bstart;
++ int old_bend;
++ struct dentry **path = NULL;
++ struct super_block *sb;
++
++ verify_locked(dentry);
++
++ err = is_robranch_super(dir->i_sb, bindex);
++ if (err) {
++ lower_dentry = ERR_PTR(err);
++ goto out;
++ }
++
++ old_bstart = dbstart(dentry);
++ old_bend = dbend(dentry);
++
++ lower_dentry = ERR_PTR(-ENOMEM);
++
++ /* There is no sense allocating any less than the minimum. */
++ nr_dentry = 1;
++ path = kmalloc(nr_dentry * sizeof(struct dentry *), GFP_KERNEL);
++ if (unlikely(!path))
++ goto out;
++
++ /* assume the negative dentry of unionfs as the parent dentry */
++ parent_dentry = dentry;
++
++ /*
++ * This loop finds the first parent that exists in the given branch.
++ * We start building the directory structure from there. At the end
++ * of the loop, the following should hold:
++ * - child_dentry is the first nonexistent child
++ * - parent_dentry is the first existent parent
++ * - path[0] is the = deepest child
++ * - path[count] is the first child to create
++ */
++ do {
++ child_dentry = parent_dentry;
++
++ /* find the parent directory dentry in unionfs */
++ parent_dentry = dget_parent(child_dentry);
++
++ /* find out the lower_parent_dentry in the given branch */
++ lower_parent_dentry =
++ unionfs_lower_dentry_idx(parent_dentry, bindex);
++
++ /* grow path table */
++ if (count == nr_dentry) {
++ void *p;
++
++ nr_dentry *= 2;
++ p = krealloc(path, nr_dentry * sizeof(struct dentry *),
++ GFP_KERNEL);
++ if (unlikely(!p)) {
++ lower_dentry = ERR_PTR(-ENOMEM);
++ goto out;
++ }
++ path = p;
++ }
++
++ /* store the child dentry */
++ path[count++] = child_dentry;
++ } while (!lower_parent_dentry);
++ count--;
++
++ sb = dentry->d_sb;
++
++ /*
++ * This code goes between the begin/end labels and basically
++ * emulates a while(child_dentry != dentry), only cleaner and
++ * shorter than what would be a much longer while loop.
++ */
++begin:
++ /* get lower parent dir in the current branch */
++ lower_parent_dentry = unionfs_lower_dentry_idx(parent_dentry, bindex);
++ dput(parent_dentry);
++
++ /* init the values to lookup */
++ childname = child_dentry->d_name.name;
++ childnamelen = child_dentry->d_name.len;
++
++ if (child_dentry != dentry) {
++ /* lookup child in the underlying file system */
++ lower_dentry = lookup_lck_len(childname, lower_parent_dentry,
++ childnamelen);
++ if (IS_ERR(lower_dentry))
++ goto out;
++ } else {
++ /*
++ * Is the name a whiteout of the child name ? lookup the
++ * whiteout child in the underlying file system
++ */
++ lower_dentry = lookup_lck_len(name, lower_parent_dentry,
++ strlen(name));
++ if (IS_ERR(lower_dentry))
++ goto out;
++
++ /* Replace the current dentry (if any) with the new one */
++ dput(unionfs_lower_dentry_idx(dentry, bindex));
++ unionfs_set_lower_dentry_idx(dentry, bindex,
++ lower_dentry);
++
++ __cleanup_dentry(dentry, bindex, old_bstart, old_bend);
++ goto out;
++ }
++
++ if (lower_dentry->d_inode) {
++ /*
++ * since this already exists we dput to avoid
++ * multiple references on the same dentry
++ */
++ dput(lower_dentry);
++ } else {
++ struct sioq_args args;
++
++ /* it's a negative dentry, create a new dir */
++ lower_parent_dentry = lock_parent(lower_dentry);
++
++ args.mkdir.parent = lower_parent_dentry->d_inode;
++ args.mkdir.dentry = lower_dentry;
++ args.mkdir.mode = child_dentry->d_inode->i_mode;
++
++ run_sioq(__unionfs_mkdir, &args);
++ err = args.err;
++
++ if (!err)
++ err = copyup_permissions(dir->i_sb, child_dentry,
++ lower_dentry);
++ unlock_dir(lower_parent_dentry);
++ if (err) {
++ dput(lower_dentry);
++ lower_dentry = ERR_PTR(err);
++ goto out;
++ }
++
++ }
++
++ __set_inode(child_dentry, lower_dentry, bindex);
++ __set_dentry(child_dentry, lower_dentry, bindex);
++ /*
++ * update times of this dentry, but also the parent, because if
++ * we changed, the parent may have changed too.
++ */
++ fsstack_copy_attr_times(parent_dentry->d_inode,
++ lower_parent_dentry->d_inode);
++ unionfs_copy_attr_times(child_dentry->d_inode);
++
++ parent_dentry = child_dentry;
++ child_dentry = path[--count];
++ goto begin;
++out:
++ /* cleanup any leftover locks from the do/while loop above */
++ if (IS_ERR(lower_dentry))
++ while (count)
++ dput(path[count--]);
++ kfree(path);
++ return lower_dentry;
++}
++
++/*
++ * Post-copyup helper to ensure we have valid mnts: set lower mnt of
++ * dentry+parents to the first parent node that has an mnt.
++ */
++void unionfs_postcopyup_setmnt(struct dentry *dentry)
++{
++ struct dentry *parent, *hasone;
++ int bindex = dbstart(dentry);
++
++ if (unionfs_lower_mnt_idx(dentry, bindex))
++ return;
++ hasone = dentry->d_parent;
++ /* this loop should stop at root dentry */
++ while (!unionfs_lower_mnt_idx(hasone, bindex))
++ hasone = hasone->d_parent;
++ parent = dentry;
++ while (!unionfs_lower_mnt_idx(parent, bindex)) {
++ unionfs_set_lower_mnt_idx(parent, bindex,
++ unionfs_mntget(hasone, bindex));
++ parent = parent->d_parent;
++ }
++}
++
++/*
++ * Post-copyup helper to release all non-directory source objects of a
++ * copied-up file. Regular files should have only one lower object.
++ */
++void unionfs_postcopyup_release(struct dentry *dentry)
++{
++ int bstart, bend;
++
++ BUG_ON(S_ISDIR(dentry->d_inode->i_mode));
++ bstart = dbstart(dentry);
++ bend = dbend(dentry);
++
++ path_put_lowers(dentry, bstart + 1, bend, false);
++ iput_lowers(dentry->d_inode, bstart + 1, bend, false);
++
++ dbend(dentry) = bstart;
++ ibend(dentry->d_inode) = ibstart(dentry->d_inode) = bstart;
++}
+diff --git a/fs/unionfs/debug.c b/fs/unionfs/debug.c
+new file mode 100644
+index 0000000..6092e69
+--- /dev/null
++++ b/fs/unionfs/debug.c
+@@ -0,0 +1,548 @@
++/*
++ * Copyright (c) 2003-2011 Erez Zadok
++ * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 The Research Foundation of SUNY
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "union.h"
++
++/*
++ * Helper debugging functions for maintainers (and for users to report back
++ * useful information back to maintainers)
++ */
++
++/* it's always useful to know what part of the code called us */
++#define PRINT_CALLER(fname, fxn, line) \
++ do { \
++ if (!printed_caller) { \
++ pr_debug("PC:%s:%s:%d\n", (fname), (fxn), (line)); \
++ printed_caller = 1; \
++ } \
++ } while (0)
++
++/*
++ * __unionfs_check_{inode,dentry,file} perform exhaustive sanity checking on
++ * the fan-out of various Unionfs objects. We check that no lower objects
++ * exist outside the start/end branch range; that all objects within are
++ * non-NULL (with some allowed exceptions); that for every lower file
++ * there's a lower dentry+inode; that the start/end ranges match for all
++ * corresponding lower objects; that open files/symlinks have only one lower
++ * objects, but directories can have several; and more.
++ */
++void __unionfs_check_inode(const struct inode *inode,
++ const char *fname, const char *fxn, int line)
++{
++ int bindex;
++ int istart, iend;
++ struct inode *lower_inode;
++ struct super_block *sb;
++ int printed_caller = 0;
++ void *poison_ptr;
++
++ /* for inodes now */
++ BUG_ON(!inode);
++ sb = inode->i_sb;
++ istart = ibstart(inode);
++ iend = ibend(inode);
++ /* don't check inode if no lower branches */
++ if (istart < 0 && iend < 0)
++ return;
++ if (unlikely(istart > iend)) {
++ PRINT_CALLER(fname, fxn, line);
++ pr_debug(" Ci0: inode=%p istart/end=%d:%d\n",
++ inode, istart, iend);
++ }
++ if (unlikely((istart == -1 && iend != -1) ||
++ (istart != -1 && iend == -1))) {
++ PRINT_CALLER(fname, fxn, line);
++ pr_debug(" Ci1: inode=%p istart/end=%d:%d\n",
++ inode, istart, iend);
++ }
++ if (!S_ISDIR(inode->i_mode)) {
++ if (unlikely(iend != istart)) {
++ PRINT_CALLER(fname, fxn, line);
++ pr_debug(" Ci2: inode=%p istart=%d iend=%d\n",
++ inode, istart, iend);
++ }
++ }
++
++ for (bindex = sbstart(sb); bindex < sbmax(sb); bindex++) {
++ if (unlikely(!UNIONFS_I(inode))) {
++ PRINT_CALLER(fname, fxn, line);
++ pr_debug(" Ci3: no inode_info %p\n", inode);
++ return;
++ }
++ if (unlikely(!UNIONFS_I(inode)->lower_inodes)) {
++ PRINT_CALLER(fname, fxn, line);
++ pr_debug(" Ci4: no lower_inodes %p\n", inode);
++ return;
++ }
++ lower_inode = unionfs_lower_inode_idx(inode, bindex);
++ if (lower_inode) {
++ memset(&poison_ptr, POISON_INUSE, sizeof(void *));
++ if (unlikely(bindex < istart || bindex > iend)) {
++ PRINT_CALLER(fname, fxn, line);
++ pr_debug(" Ci5: inode/linode=%p:%p bindex=%d "
++ "istart/end=%d:%d\n", inode,
++ lower_inode, bindex, istart, iend);
++ } else if (unlikely(lower_inode == poison_ptr)) {
++ /* freed inode! */
++ PRINT_CALLER(fname, fxn, line);
++ pr_debug(" Ci6: inode/linode=%p:%p bindex=%d "
++ "istart/end=%d:%d\n", inode,
++ lower_inode, bindex, istart, iend);
++ }
++ continue;
++ }
++ /* if we get here, then lower_inode == NULL */
++ if (bindex < istart || bindex > iend)
++ continue;
++ /*
++ * directories can have NULL lower inodes in b/t start/end,
++ * but NOT if at the start/end range.
++ */
++ if (unlikely(S_ISDIR(inode->i_mode) &&
++ bindex > istart && bindex < iend))
++ continue;
++ PRINT_CALLER(fname, fxn, line);
++ pr_debug(" Ci7: inode/linode=%p:%p "
++ "bindex=%d istart/end=%d:%d\n",
++ inode, lower_inode, bindex, istart, iend);
++ }
++}
++
++void __unionfs_check_dentry(const struct dentry *dentry,
++ const char *fname, const char *fxn, int line)
++{
++ int bindex;
++ int dstart, dend, istart, iend;
++ struct dentry *lower_dentry;
++ struct inode *inode, *lower_inode;
++ struct super_block *sb;
++ struct vfsmount *lower_mnt;
++ int printed_caller = 0;
++ void *poison_ptr;
++
++ BUG_ON(!dentry);
++ sb = dentry->d_sb;
++ inode = dentry->d_inode;
++ dstart = dbstart(dentry);
++ dend = dbend(dentry);
++ /* don't check dentry/mnt if no lower branches */
++ if (dstart < 0 && dend < 0)
++ goto check_inode;
++ BUG_ON(dstart > dend);
++
++ if (unlikely((dstart == -1 && dend != -1) ||
++ (dstart != -1 && dend == -1))) {
++ PRINT_CALLER(fname, fxn, line);
++ pr_debug(" CD0: dentry=%p dstart/end=%d:%d\n",
++ dentry, dstart, dend);
++ }
++ /*
++ * check for NULL dentries inside the start/end range, or
++ * non-NULL dentries outside the start/end range.
++ */
++ for (bindex = sbstart(sb); bindex < sbmax(sb); bindex++) {
++ lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
++ if (lower_dentry) {
++ if (unlikely(bindex < dstart || bindex > dend)) {
++ PRINT_CALLER(fname, fxn, line);
++ pr_debug(" CD1: dentry/lower=%p:%p(%p) "
++ "bindex=%d dstart/end=%d:%d\n",
++ dentry, lower_dentry,
++ (lower_dentry ? lower_dentry->d_inode :
++ (void *) -1L),
++ bindex, dstart, dend);
++ }
++ } else { /* lower_dentry == NULL */
++ if (bindex < dstart || bindex > dend)
++ continue;
++ /*
++ * Directories can have NULL lower inodes in b/t
++ * start/end, but NOT if at the start/end range.
++ * Ignore this rule, however, if this is a NULL
++ * dentry or a deleted dentry.
++ */
++ if (unlikely(!d_deleted((struct dentry *) dentry) &&
++ inode &&
++ !(inode && S_ISDIR(inode->i_mode) &&
++ bindex > dstart && bindex < dend))) {
++ PRINT_CALLER(fname, fxn, line);
++ pr_debug(" CD2: dentry/lower=%p:%p(%p) "
++ "bindex=%d dstart/end=%d:%d\n",
++ dentry, lower_dentry,
++ (lower_dentry ?
++ lower_dentry->d_inode :
++ (void *) -1L),
++ bindex, dstart, dend);
++ }
++ }
++ }
++
++ /* check for vfsmounts same as for dentries */
++ for (bindex = sbstart(sb); bindex < sbmax(sb); bindex++) {
++ lower_mnt = unionfs_lower_mnt_idx(dentry, bindex);
++ if (lower_mnt) {
++ if (unlikely(bindex < dstart || bindex > dend)) {
++ PRINT_CALLER(fname, fxn, line);
++ pr_debug(" CM0: dentry/lmnt=%p:%p bindex=%d "
++ "dstart/end=%d:%d\n", dentry,
++ lower_mnt, bindex, dstart, dend);
++ }
++ } else { /* lower_mnt == NULL */
++ if (bindex < dstart || bindex > dend)
++ continue;
++ /*
++ * Directories can have NULL lower inodes in b/t
++ * start/end, but NOT if at the start/end range.
++ * Ignore this rule, however, if this is a NULL
++ * dentry.
++ */
++ if (unlikely(inode &&
++ !(inode && S_ISDIR(inode->i_mode) &&
++ bindex > dstart && bindex < dend))) {
++ PRINT_CALLER(fname, fxn, line);
++ pr_debug(" CM1: dentry/lmnt=%p:%p "
++ "bindex=%d dstart/end=%d:%d\n",
++ dentry, lower_mnt, bindex,
++ dstart, dend);
++ }
++ }
++ }
++
++check_inode:
++ /* for inodes now */
++ if (!inode)
++ return;
++ istart = ibstart(inode);
++ iend = ibend(inode);
++ /* don't check inode if no lower branches */
++ if (istart < 0 && iend < 0)
++ return;
++ BUG_ON(istart > iend);
++ if (unlikely((istart == -1 && iend != -1) ||
++ (istart != -1 && iend == -1))) {
++ PRINT_CALLER(fname, fxn, line);
++ pr_debug(" CI0: dentry/inode=%p:%p istart/end=%d:%d\n",
++ dentry, inode, istart, iend);
++ }
++ if (unlikely(istart != dstart)) {
++ PRINT_CALLER(fname, fxn, line);
++ pr_debug(" CI1: dentry/inode=%p:%p istart=%d dstart=%d\n",
++ dentry, inode, istart, dstart);
++ }
++ if (unlikely(iend != dend)) {
++ PRINT_CALLER(fname, fxn, line);
++ pr_debug(" CI2: dentry/inode=%p:%p iend=%d dend=%d\n",
++ dentry, inode, iend, dend);
++ }
++
++ if (!S_ISDIR(inode->i_mode)) {
++ if (unlikely(dend != dstart)) {
++ PRINT_CALLER(fname, fxn, line);
++ pr_debug(" CI3: dentry/inode=%p:%p dstart=%d dend=%d\n",
++ dentry, inode, dstart, dend);
++ }
++ if (unlikely(iend != istart)) {
++ PRINT_CALLER(fname, fxn, line);
++ pr_debug(" CI4: dentry/inode=%p:%p istart=%d iend=%d\n",
++ dentry, inode, istart, iend);
++ }
++ }
++
++ for (bindex = sbstart(sb); bindex < sbmax(sb); bindex++) {
++ lower_inode = unionfs_lower_inode_idx(inode, bindex);
++ if (lower_inode) {
++ memset(&poison_ptr, POISON_INUSE, sizeof(void *));
++ if (unlikely(bindex < istart || bindex > iend)) {
++ PRINT_CALLER(fname, fxn, line);
++ pr_debug(" CI5: dentry/linode=%p:%p bindex=%d "
++ "istart/end=%d:%d\n", dentry,
++ lower_inode, bindex, istart, iend);
++ } else if (unlikely(lower_inode == poison_ptr)) {
++ /* freed inode! */
++ PRINT_CALLER(fname, fxn, line);
++ pr_debug(" CI6: dentry/linode=%p:%p bindex=%d "
++ "istart/end=%d:%d\n", dentry,
++ lower_inode, bindex, istart, iend);
++ }
++ continue;
++ }
++ /* if we get here, then lower_inode == NULL */
++ if (bindex < istart || bindex > iend)
++ continue;
++ /*
++ * directories can have NULL lower inodes in b/t start/end,
++ * but NOT if at the start/end range.
++ */
++ if (unlikely(S_ISDIR(inode->i_mode) &&
++ bindex > istart && bindex < iend))
++ continue;
++ PRINT_CALLER(fname, fxn, line);
++ pr_debug(" CI7: dentry/linode=%p:%p "
++ "bindex=%d istart/end=%d:%d\n",
++ dentry, lower_inode, bindex, istart, iend);
++ }
++
++ /*
++ * If it's a directory, then intermediate objects b/t start/end can
++ * be NULL. But, check that all three are NULL: lower dentry, mnt,
++ * and inode.
++ */
++ if (dstart >= 0 && dend >= 0 && S_ISDIR(inode->i_mode))
++ for (bindex = dstart+1; bindex < dend; bindex++) {
++ lower_inode = unionfs_lower_inode_idx(inode, bindex);
++ lower_dentry = unionfs_lower_dentry_idx(dentry,
++ bindex);
++ lower_mnt = unionfs_lower_mnt_idx(dentry, bindex);
++ if (unlikely(!((lower_inode && lower_dentry &&
++ lower_mnt) ||
++ (!lower_inode &&
++ !lower_dentry && !lower_mnt)))) {
++ PRINT_CALLER(fname, fxn, line);
++ pr_debug(" Cx: lmnt/ldentry/linode=%p:%p:%p "
++ "bindex=%d dstart/end=%d:%d\n",
++ lower_mnt, lower_dentry, lower_inode,
++ bindex, dstart, dend);
++ }
++ }
++ /* check if lower inode is newer than upper one (it shouldn't) */
++ if (unlikely(is_newer_lower(dentry) && !is_negative_lower(dentry))) {
++ PRINT_CALLER(fname, fxn, line);
++ for (bindex = ibstart(inode); bindex <= ibend(inode);
++ bindex++) {
++ lower_inode = unionfs_lower_inode_idx(inode, bindex);
++ if (unlikely(!lower_inode))
++ continue;
++ pr_debug(" CI8: bindex=%d mtime/lmtime=%lu.%lu/%lu.%lu "
++ "ctime/lctime=%lu.%lu/%lu.%lu\n",
++ bindex,
++ inode->i_mtime.tv_sec,
++ inode->i_mtime.tv_nsec,
++ lower_inode->i_mtime.tv_sec,
++ lower_inode->i_mtime.tv_nsec,
++ inode->i_ctime.tv_sec,
++ inode->i_ctime.tv_nsec,
++ lower_inode->i_ctime.tv_sec,
++ lower_inode->i_ctime.tv_nsec);
++ }
++ }
++}
++
++void __unionfs_check_file(const struct file *file,
++ const char *fname, const char *fxn, int line)
++{
++ int bindex;
++ int dstart, dend, fstart, fend;
++ struct dentry *dentry;
++ struct file *lower_file;
++ struct inode *inode;
++ struct super_block *sb;
++ int printed_caller = 0;
++
++ BUG_ON(!file);
++ dentry = file->f_path.dentry;
++ sb = dentry->d_sb;
++ dstart = dbstart(dentry);
++ dend = dbend(dentry);
++ BUG_ON(dstart > dend);
++ fstart = fbstart(file);
++ fend = fbend(file);
++ BUG_ON(fstart > fend);
++
++ if (unlikely((fstart == -1 && fend != -1) ||
++ (fstart != -1 && fend == -1))) {
++ PRINT_CALLER(fname, fxn, line);
++ pr_debug(" CF0: file/dentry=%p:%p fstart/end=%d:%d\n",
++ file, dentry, fstart, fend);
++ }
++ if (unlikely(fstart != dstart)) {
++ PRINT_CALLER(fname, fxn, line);
++ pr_debug(" CF1: file/dentry=%p:%p fstart=%d dstart=%d\n",
++ file, dentry, fstart, dstart);
++ }
++ if (unlikely(fend != dend)) {
++ PRINT_CALLER(fname, fxn, line);
++ pr_debug(" CF2: file/dentry=%p:%p fend=%d dend=%d\n",
++ file, dentry, fend, dend);
++ }
++ inode = dentry->d_inode;
++ if (!S_ISDIR(inode->i_mode)) {
++ if (unlikely(fend != fstart)) {
++ PRINT_CALLER(fname, fxn, line);
++ pr_debug(" CF3: file/inode=%p:%p fstart=%d fend=%d\n",
++ file, inode, fstart, fend);
++ }
++ if (unlikely(dend != dstart)) {
++ PRINT_CALLER(fname, fxn, line);
++ pr_debug(" CF4: file/dentry=%p:%p dstart=%d dend=%d\n",
++ file, dentry, dstart, dend);
++ }
++ }
++
++ /*
++ * check for NULL dentries inside the start/end range, or
++ * non-NULL dentries outside the start/end range.
++ */
++ for (bindex = sbstart(sb); bindex < sbmax(sb); bindex++) {
++ lower_file = unionfs_lower_file_idx(file, bindex);
++ if (lower_file) {
++ if (unlikely(bindex < fstart || bindex > fend)) {
++ PRINT_CALLER(fname, fxn, line);
++ pr_debug(" CF5: file/lower=%p:%p bindex=%d "
++ "fstart/end=%d:%d\n", file,
++ lower_file, bindex, fstart, fend);
++ }
++ } else { /* lower_file == NULL */
++ if (bindex >= fstart && bindex <= fend) {
++ /*
++ * directories can have NULL lower inodes in
++ * b/t start/end, but NOT if at the
++ * start/end range.
++ */
++ if (unlikely(!(S_ISDIR(inode->i_mode) &&
++ bindex > fstart &&
++ bindex < fend))) {
++ PRINT_CALLER(fname, fxn, line);
++ pr_debug(" CF6: file/lower=%p:%p "
++ "bindex=%d fstart/end=%d:%d\n",
++ file, lower_file, bindex,
++ fstart, fend);
++ }
++ }
++ }
++ }
++
++ __unionfs_check_dentry(dentry, fname, fxn, line);
++}
++
++void __unionfs_check_nd(const struct nameidata *nd,
++ const char *fname, const char *fxn, int line)
++{
++ struct file *file;
++ int printed_caller = 0;
++
++ if (unlikely(!nd))
++ return;
++ if (nd->flags & LOOKUP_OPEN) {
++ file = nd->intent.open.file;
++ if (unlikely(file->f_path.dentry &&
++ strcmp(file->f_path.dentry->d_sb->s_type->name,
++ UNIONFS_NAME))) {
++ PRINT_CALLER(fname, fxn, line);
++ pr_debug(" CND1: lower_file of type %s\n",
++ file->f_path.dentry->d_sb->s_type->name);
++ }
++ }
++}
++
++static unsigned int __mnt_get_count(struct vfsmount *mnt)
++{
++#ifdef CONFIG_SMP
++ unsigned int count = 0;
++ int cpu;
++
++ for_each_possible_cpu(cpu) {
++ count += per_cpu_ptr(mnt->mnt_pcp, cpu)->mnt_count;
++ }
++
++ return count;
++#else
++ return mnt->mnt_count;
++#endif
++}
++
++/* useful to track vfsmount leaks that could cause EBUSY on unmount */
++void __show_branch_counts(const struct super_block *sb,
++ const char *file, const char *fxn, int line)
++{
++ int i;
++ struct vfsmount *mnt;
++
++ pr_debug("BC:");
++ for (i = 0; i < sbmax(sb); i++) {
++ if (likely(sb->s_root))
++ mnt = UNIONFS_D(sb->s_root)->lower_paths[i].mnt;
++ else
++ mnt = NULL;
++ printk(KERN_CONT "%d:",
++ (mnt ? __mnt_get_count(mnt) : -99));
++ }
++ printk(KERN_CONT "%s:%s:%d\n", file, fxn, line);
++}
++
++void __show_inode_times(const struct inode *inode,
++ const char *file, const char *fxn, int line)
++{
++ struct inode *lower_inode;
++ int bindex;
++
++ for (bindex = ibstart(inode); bindex <= ibend(inode); bindex++) {
++ lower_inode = unionfs_lower_inode_idx(inode, bindex);
++ if (unlikely(!lower_inode))
++ continue;
++ pr_debug("IT(%lu:%d): %s:%s:%d "
++ "um=%lu/%lu lm=%lu/%lu uc=%lu/%lu lc=%lu/%lu\n",
++ inode->i_ino, bindex,
++ file, fxn, line,
++ inode->i_mtime.tv_sec, inode->i_mtime.tv_nsec,
++ lower_inode->i_mtime.tv_sec,
++ lower_inode->i_mtime.tv_nsec,
++ inode->i_ctime.tv_sec, inode->i_ctime.tv_nsec,
++ lower_inode->i_ctime.tv_sec,
++ lower_inode->i_ctime.tv_nsec);
++ }
++}
++
++void __show_dinode_times(const struct dentry *dentry,
++ const char *file, const char *fxn, int line)
++{
++ struct inode *inode = dentry->d_inode;
++ struct inode *lower_inode;
++ int bindex;
++
++ for (bindex = ibstart(inode); bindex <= ibend(inode); bindex++) {
++ lower_inode = unionfs_lower_inode_idx(inode, bindex);
++ if (!lower_inode)
++ continue;
++ pr_debug("DT(%s:%lu:%d): %s:%s:%d "
++ "um=%lu/%lu lm=%lu/%lu uc=%lu/%lu lc=%lu/%lu\n",
++ dentry->d_name.name, inode->i_ino, bindex,
++ file, fxn, line,
++ inode->i_mtime.tv_sec, inode->i_mtime.tv_nsec,
++ lower_inode->i_mtime.tv_sec,
++ lower_inode->i_mtime.tv_nsec,
++ inode->i_ctime.tv_sec, inode->i_ctime.tv_nsec,
++ lower_inode->i_ctime.tv_sec,
++ lower_inode->i_ctime.tv_nsec);
++ }
++}
++
++void __show_inode_counts(const struct inode *inode,
++ const char *file, const char *fxn, int line)
++{
++ struct inode *lower_inode;
++ int bindex;
++
++ if (unlikely(!inode)) {
++ pr_debug("SiC: Null inode\n");
++ return;
++ }
++ for (bindex = sbstart(inode->i_sb); bindex <= sbend(inode->i_sb);
++ bindex++) {
++ lower_inode = unionfs_lower_inode_idx(inode, bindex);
++ if (unlikely(!lower_inode))
++ continue;
++ pr_debug("SIC(%lu:%d:%d): lc=%d %s:%s:%d\n",
++ inode->i_ino, bindex,
++ atomic_read(&(inode)->i_count),
++ atomic_read(&(lower_inode)->i_count),
++ file, fxn, line);
++ }
++}
+diff --git a/fs/unionfs/dentry.c b/fs/unionfs/dentry.c
+new file mode 100644
+index 0000000..c0205a4
+--- /dev/null
++++ b/fs/unionfs/dentry.c
+@@ -0,0 +1,406 @@
++/*
++ * Copyright (c) 2003-2011 Erez Zadok
++ * Copyright (c) 2003-2006 Charles P. Wright
++ * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
++ * Copyright (c) 2005-2006 Junjiro Okajima
++ * Copyright (c) 2005 Arun M. Krishnakumar
++ * Copyright (c) 2004-2006 David P. Quigley
++ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
++ * Copyright (c) 2003 Puja Gupta
++ * Copyright (c) 2003 Harikesavan Krishnan
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 The Research Foundation of SUNY
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "union.h"
++
++bool is_negative_lower(const struct dentry *dentry)
++{
++ int bindex;
++ struct dentry *lower_dentry;
++
++ BUG_ON(!dentry);
++ /* cache coherency: check if file was deleted on lower branch */
++ if (dbstart(dentry) < 0)
++ return true;
++ for (bindex = dbstart(dentry); bindex <= dbend(dentry); bindex++) {
++ lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
++ /* unhashed (i.e., unlinked) lower dentries don't count */
++ if (lower_dentry && lower_dentry->d_inode &&
++ !d_deleted(lower_dentry) &&
++ !(lower_dentry->d_flags & DCACHE_NFSFS_RENAMED))
++ return false;
++ }
++ return true;
++}
++
++static inline void __dput_lowers(struct dentry *dentry, int start, int end)
++{
++ struct dentry *lower_dentry;
++ int bindex;
++
++ if (start < 0)
++ return;
++ for (bindex = start; bindex <= end; bindex++) {
++ lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
++ if (!lower_dentry)
++ continue;
++ unionfs_set_lower_dentry_idx(dentry, bindex, NULL);
++ dput(lower_dentry);
++ }
++}
++
++/*
++ * Purge and invalidate as many data pages of a unionfs inode. This is
++ * called when the lower inode has changed, and we want to force processes
++ * to re-get the new data.
++ */
++static inline void purge_inode_data(struct inode *inode)
++{
++ /* remove all non-private mappings */
++ unmap_mapping_range(inode->i_mapping, 0, 0, 0);
++ /* invalidate as many pages as possible */
++ invalidate_mapping_pages(inode->i_mapping, 0, -1);
++ /*
++ * Don't try to truncate_inode_pages here, because this could lead
++ * to a deadlock between some of address_space ops and dentry
++ * revalidation: the address space op is invoked with a lock on our
++ * own page, and truncate_inode_pages will block on locked pages.
++ */
++}
++
++/*
++ * Revalidate a single file/symlink/special dentry. Assume that info nodes
++ * of the @dentry and its @parent are locked. Assume parent is valid,
++ * otherwise return false (and let's hope the VFS will try to re-lookup this
++ * dentry). Returns true if valid, false otherwise.
++ */
++bool __unionfs_d_revalidate(struct dentry *dentry, struct dentry *parent,
++ bool willwrite)
++{
++ bool valid = true; /* default is valid */
++ struct dentry *lower_dentry;
++ struct dentry *result;
++ int bindex, bstart, bend;
++ int sbgen, dgen, pdgen;
++ int positive = 0;
++ int interpose_flag;
++
++ verify_locked(dentry);
++ verify_locked(parent);
++
++ /* if the dentry is unhashed, do NOT revalidate */
++ if (d_deleted(dentry))
++ goto out;
++
++ dgen = atomic_read(&UNIONFS_D(dentry)->generation);
++
++ if (is_newer_lower(dentry)) {
++ /* root dentry is always valid */
++ if (IS_ROOT(dentry)) {
++ unionfs_copy_attr_times(dentry->d_inode);
++ } else {
++ /*
++ * reset generation number to zero, guaranteed to be
++ * "old"
++ */
++ dgen = 0;
++ atomic_set(&UNIONFS_D(dentry)->generation, dgen);
++ }
++ if (!willwrite)
++ purge_inode_data(dentry->d_inode);
++ }
++
++ sbgen = atomic_read(&UNIONFS_SB(dentry->d_sb)->generation);
++
++ BUG_ON(dbstart(dentry) == -1);
++ if (dentry->d_inode)
++ positive = 1;
++
++ /* if our dentry is valid, then validate all lower ones */
++ if (sbgen == dgen)
++ goto validate_lowers;
++
++ /* The root entry should always be valid */
++ BUG_ON(IS_ROOT(dentry));
++
++ /* We can't work correctly if our parent isn't valid. */
++ pdgen = atomic_read(&UNIONFS_D(parent)->generation);
++
++ /* Free the pointers for our inodes and this dentry. */
++ path_put_lowers_all(dentry, false);
++
++ interpose_flag = INTERPOSE_REVAL_NEG;
++ if (positive) {
++ interpose_flag = INTERPOSE_REVAL;
++ iput_lowers_all(dentry->d_inode, true);
++ }
++
++ if (realloc_dentry_private_data(dentry) != 0) {
++ valid = false;
++ goto out;
++ }
++
++ result = unionfs_lookup_full(dentry, parent, interpose_flag);
++ if (result) {
++ if (IS_ERR(result)) {
++ valid = false;
++ goto out;
++ }
++ /*
++ * current unionfs_lookup_backend() doesn't return
++ * a valid dentry
++ */
++ dput(dentry);
++ dentry = result;
++ }
++
++ if (unlikely(positive && is_negative_lower(dentry))) {
++ /* call make_bad_inode here ? */
++ d_drop(dentry);
++ valid = false;
++ goto out;
++ }
++
++ /*
++ * if we got here then we have revalidated our dentry and all lower
++ * ones, so we can return safely.
++ */
++ if (!valid) /* lower dentry revalidation failed */
++ goto out;
++
++ /*
++ * If the parent's gen no. matches the superblock's gen no., then
++ * we can update our denty's gen no. If they didn't match, then it
++ * was OK to revalidate this dentry with a stale parent, but we'll
++ * purposely not update our dentry's gen no. (so it can be redone);
++ * and, we'll mark our parent dentry as invalid so it'll force it
++ * (and our dentry) to be revalidated.
++ */
++ if (pdgen == sbgen)
++ atomic_set(&UNIONFS_D(dentry)->generation, sbgen);
++ goto out;
++
++validate_lowers:
++
++ /* The revalidation must occur across all branches */
++ bstart = dbstart(dentry);
++ bend = dbend(dentry);
++ BUG_ON(bstart == -1);
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ int err;
++ struct nameidata lower_nd;
++
++ lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
++ if (!lower_dentry || !lower_dentry->d_op
++ || !lower_dentry->d_op->d_revalidate)
++ continue;
++ /*
++ * Don't pass nameidata to lower file system, because we
++ * don't want an arbitrary lower file being opened or
++ * returned to us: it may be useless to us because of the
++ * fanout nature of unionfs (cf. file/directory open-file
++ * invariants). We will open lower files as and when needed
++ * later on.
++ */
++ err = init_lower_nd(&lower_nd, LOOKUP_OPEN);
++ if (unlikely(err < 0)) {
++ valid = false;
++ break;
++ }
++ if (!lower_dentry->d_op->d_revalidate(lower_dentry, &lower_nd))
++ valid = false;
++ release_lower_nd(&lower_nd, err);
++ }
++
++ if (!dentry->d_inode ||
++ ibstart(dentry->d_inode) < 0 ||
++ ibend(dentry->d_inode) < 0) {
++ valid = false;
++ goto out;
++ }
++
++ if (valid) {
++ /*
++ * If we get here, and we copy the meta-data from the lower
++ * inode to our inode, then it is vital that we have already
++ * purged all unionfs-level file data. We do that in the
++ * caller (__unionfs_d_revalidate) by calling
++ * purge_inode_data.
++ */
++ unionfs_copy_attr_all(dentry->d_inode,
++ unionfs_lower_inode(dentry->d_inode));
++ fsstack_copy_inode_size(dentry->d_inode,
++ unionfs_lower_inode(dentry->d_inode));
++ }
++
++out:
++ return valid;
++}
++
++/*
++ * Determine if the lower inode objects have changed from below the unionfs
++ * inode. Return true if changed, false otherwise.
++ *
++ * We check if the mtime or ctime have changed. However, the inode times
++ * can be changed by anyone without much protection, including
++ * asynchronously. This can sometimes cause unionfs to find that the lower
++ * file system doesn't change its inode times quick enough, resulting in a
++ * false positive indication (which is harmless, it just makes unionfs do
++ * extra work in re-validating the objects). To minimize the chances of
++ * these situations, we still consider such small time changes valid, but we
++ * don't print debugging messages unless the time changes are greater than
++ * UNIONFS_MIN_CC_TIME (which defaults to 3 seconds, as with NFS's acregmin)
++ * because significant changes are more likely due to users manually
++ * touching lower files.
++ */
++bool is_newer_lower(const struct dentry *dentry)
++{
++ int bindex;
++ struct inode *inode;
++ struct inode *lower_inode;
++
++ /* ignore if we're called on semi-initialized dentries/inodes */
++ if (!dentry || !UNIONFS_D(dentry))
++ return false;
++ inode = dentry->d_inode;
++ if (!inode || !UNIONFS_I(inode)->lower_inodes ||
++ ibstart(inode) < 0 || ibend(inode) < 0)
++ return false;
++
++ for (bindex = ibstart(inode); bindex <= ibend(inode); bindex++) {
++ lower_inode = unionfs_lower_inode_idx(inode, bindex);
++ if (!lower_inode)
++ continue;
++
++ /* check if mtime/ctime have changed */
++ if (unlikely(timespec_compare(&inode->i_mtime,
++ &lower_inode->i_mtime) < 0)) {
++ if ((lower_inode->i_mtime.tv_sec -
++ inode->i_mtime.tv_sec) > UNIONFS_MIN_CC_TIME) {
++ pr_info("unionfs: new lower inode mtime "
++ "(bindex=%d, name=%s)\n", bindex,
++ dentry->d_name.name);
++ show_dinode_times(dentry);
++ }
++ return true;
++ }
++ if (unlikely(timespec_compare(&inode->i_ctime,
++ &lower_inode->i_ctime) < 0)) {
++ if ((lower_inode->i_ctime.tv_sec -
++ inode->i_ctime.tv_sec) > UNIONFS_MIN_CC_TIME) {
++ pr_info("unionfs: new lower inode ctime "
++ "(bindex=%d, name=%s)\n", bindex,
++ dentry->d_name.name);
++ show_dinode_times(dentry);
++ }
++ return true;
++ }
++ }
++
++ /*
++ * Last check: if this is a positive dentry, but somehow all lower
++ * dentries are negative or unhashed, then this dentry needs to be
++ * revalidated, because someone probably deleted the objects from
++ * the lower branches directly.
++ */
++ if (is_negative_lower(dentry))
++ return true;
++
++ return false; /* default: lower is not newer */
++}
++
++static int unionfs_d_revalidate(struct dentry *dentry,
++ struct nameidata *nd_unused)
++{
++ bool valid = true;
++ int err = 1; /* 1 means valid for the VFS */
++ struct dentry *parent;
++
++ unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD);
++ parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ valid = __unionfs_d_revalidate(dentry, parent, false);
++ if (valid) {
++ unionfs_postcopyup_setmnt(dentry);
++ unionfs_check_dentry(dentry);
++ } else {
++ d_drop(dentry);
++ err = valid;
++ }
++ unionfs_unlock_dentry(dentry);
++ unionfs_unlock_parent(dentry, parent);
++ unionfs_read_unlock(dentry->d_sb);
++
++ return err;
++}
++
++static void unionfs_d_release(struct dentry *dentry)
++{
++ unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD);
++ if (unlikely(!UNIONFS_D(dentry)))
++ goto out; /* skip if no lower branches */
++ /* must lock our branch configuration here */
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ unionfs_check_dentry(dentry);
++ /* this could be a negative dentry, so check first */
++ if (dbstart(dentry) < 0) {
++ unionfs_unlock_dentry(dentry);
++ goto out; /* due to a (normal) failed lookup */
++ }
++
++ /* Release all the lower dentries */
++ path_put_lowers_all(dentry, true);
++
++ unionfs_unlock_dentry(dentry);
++
++out:
++ free_dentry_private_data(dentry);
++ unionfs_read_unlock(dentry->d_sb);
++ return;
++}
++
++/*
++ * Called when we're removing the last reference to our dentry. So we
++ * should drop all lower references too.
++ */
++static void unionfs_d_iput(struct dentry *dentry, struct inode *inode)
++{
++ int rc;
++
++ BUG_ON(!dentry);
++ unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD);
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ if (!UNIONFS_D(dentry) || dbstart(dentry) < 0)
++ goto drop_lower_inodes;
++ path_put_lowers_all(dentry, false);
++
++drop_lower_inodes:
++ rc = atomic_read(&inode->i_count);
++ if (rc == 1 && inode->i_nlink == 1 && ibstart(inode) >= 0) {
++ /* see Documentation/filesystems/unionfs/issues.txt */
++ lockdep_off();
++ iput(unionfs_lower_inode(inode));
++ lockdep_on();
++ unionfs_set_lower_inode(inode, NULL);
++ /* XXX: may need to set start/end to -1? */
++ }
++
++ iput(inode);
++
++ unionfs_unlock_dentry(dentry);
++ unionfs_read_unlock(dentry->d_sb);
++}
++
++struct dentry_operations unionfs_dops = {
++ .d_revalidate = unionfs_d_revalidate,
++ .d_release = unionfs_d_release,
++ .d_iput = unionfs_d_iput,
++};
+diff --git a/fs/unionfs/dirfops.c b/fs/unionfs/dirfops.c
+new file mode 100644
+index 0000000..72a9c1a
+--- /dev/null
++++ b/fs/unionfs/dirfops.c
+@@ -0,0 +1,302 @@
++/*
++ * Copyright (c) 2003-2011 Erez Zadok
++ * Copyright (c) 2003-2006 Charles P. Wright
++ * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
++ * Copyright (c) 2005-2006 Junjiro Okajima
++ * Copyright (c) 2005 Arun M. Krishnakumar
++ * Copyright (c) 2004-2006 David P. Quigley
++ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
++ * Copyright (c) 2003 Puja Gupta
++ * Copyright (c) 2003 Harikesavan Krishnan
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 The Research Foundation of SUNY
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "union.h"
++
++/* Make sure our rdstate is playing by the rules. */
++static void verify_rdstate_offset(struct unionfs_dir_state *rdstate)
++{
++ BUG_ON(rdstate->offset >= DIREOF);
++ BUG_ON(rdstate->cookie >= MAXRDCOOKIE);
++}
++
++struct unionfs_getdents_callback {
++ struct unionfs_dir_state *rdstate;
++ void *dirent;
++ int entries_written;
++ int filldir_called;
++ int filldir_error;
++ filldir_t filldir;
++ struct super_block *sb;
++};
++
++/* based on generic filldir in fs/readir.c */
++static int unionfs_filldir(void *dirent, const char *oname, int namelen,
++ loff_t offset, u64 ino, unsigned int d_type)
++{
++ struct unionfs_getdents_callback *buf = dirent;
++ struct filldir_node *found = NULL;
++ int err = 0;
++ int is_whiteout;
++ char *name = (char *) oname;
++
++ buf->filldir_called++;
++
++ is_whiteout = is_whiteout_name(&name, &namelen);
++
++ found = find_filldir_node(buf->rdstate, name, namelen, is_whiteout);
++
++ if (found) {
++ /*
++ * If we had non-whiteout entry in dir cache, then mark it
++ * as a whiteout and but leave it in the dir cache.
++ */
++ if (is_whiteout && !found->whiteout)
++ found->whiteout = is_whiteout;
++ goto out;
++ }
++
++ /* if 'name' isn't a whiteout, filldir it. */
++ if (!is_whiteout) {
++ off_t pos = rdstate2offset(buf->rdstate);
++ u64 unionfs_ino = ino;
++
++ err = buf->filldir(buf->dirent, name, namelen, pos,
++ unionfs_ino, d_type);
++ buf->rdstate->offset++;
++ verify_rdstate_offset(buf->rdstate);
++ }
++ /*
++ * If we did fill it, stuff it in our hash, otherwise return an
++ * error.
++ */
++ if (err) {
++ buf->filldir_error = err;
++ goto out;
++ }
++ buf->entries_written++;
++ err = add_filldir_node(buf->rdstate, name, namelen,
++ buf->rdstate->bindex, is_whiteout);
++ if (err)
++ buf->filldir_error = err;
++
++out:
++ return err;
++}
++
++static int unionfs_readdir(struct file *file, void *dirent, filldir_t filldir)
++{
++ int err = 0;
++ struct file *lower_file = NULL;
++ struct dentry *dentry = file->f_path.dentry;
++ struct dentry *parent;
++ struct inode *inode = NULL;
++ struct unionfs_getdents_callback buf;
++ struct unionfs_dir_state *uds;
++ int bend;
++ loff_t offset;
++
++ unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_PARENT);
++ parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ err = unionfs_file_revalidate(file, parent, false);
++ if (unlikely(err))
++ goto out;
++
++ inode = dentry->d_inode;
++
++ uds = UNIONFS_F(file)->rdstate;
++ if (!uds) {
++ if (file->f_pos == DIREOF) {
++ goto out;
++ } else if (file->f_pos > 0) {
++ uds = find_rdstate(inode, file->f_pos);
++ if (unlikely(!uds)) {
++ err = -ESTALE;
++ goto out;
++ }
++ UNIONFS_F(file)->rdstate = uds;
++ } else {
++ init_rdstate(file);
++ uds = UNIONFS_F(file)->rdstate;
++ }
++ }
++ bend = fbend(file);
++
++ while (uds->bindex <= bend) {
++ lower_file = unionfs_lower_file_idx(file, uds->bindex);
++ if (!lower_file) {
++ uds->bindex++;
++ uds->dirpos = 0;
++ continue;
++ }
++
++ /* prepare callback buffer */
++ buf.filldir_called = 0;
++ buf.filldir_error = 0;
++ buf.entries_written = 0;
++ buf.dirent = dirent;
++ buf.filldir = filldir;
++ buf.rdstate = uds;
++ buf.sb = inode->i_sb;
++
++ /* Read starting from where we last left off. */
++ offset = vfs_llseek(lower_file, uds->dirpos, SEEK_SET);
++ if (offset < 0) {
++ err = offset;
++ goto out;
++ }
++ err = vfs_readdir(lower_file, unionfs_filldir, &buf);
++
++ /* Save the position for when we continue. */
++ offset = vfs_llseek(lower_file, 0, SEEK_CUR);
++ if (offset < 0) {
++ err = offset;
++ goto out;
++ }
++ uds->dirpos = offset;
++
++ /* Copy the atime. */
++ fsstack_copy_attr_atime(inode,
++ lower_file->f_path.dentry->d_inode);
++
++ if (err < 0)
++ goto out;
++
++ if (buf.filldir_error)
++ break;
++
++ if (!buf.entries_written) {
++ uds->bindex++;
++ uds->dirpos = 0;
++ }
++ }
++
++ if (!buf.filldir_error && uds->bindex >= bend) {
++ /* Save the number of hash entries for next time. */
++ UNIONFS_I(inode)->hashsize = uds->hashentries;
++ free_rdstate(uds);
++ UNIONFS_F(file)->rdstate = NULL;
++ file->f_pos = DIREOF;
++ } else {
++ file->f_pos = rdstate2offset(uds);
++ }
++
++out:
++ if (!err)
++ unionfs_check_file(file);
++ unionfs_unlock_dentry(dentry);
++ unionfs_unlock_parent(dentry, parent);
++ unionfs_read_unlock(dentry->d_sb);
++ return err;
++}
++
++/*
++ * This is not meant to be a generic repositioning function. If you do
++ * things that aren't supported, then we return EINVAL.
++ *
++ * What is allowed:
++ * (1) seeking to the same position that you are currently at
++ * This really has no effect, but returns where you are.
++ * (2) seeking to the beginning of the file
++ * This throws out all state, and lets you begin again.
++ */
++static loff_t unionfs_dir_llseek(struct file *file, loff_t offset, int origin)
++{
++ struct unionfs_dir_state *rdstate;
++ struct dentry *dentry = file->f_path.dentry;
++ struct dentry *parent;
++ loff_t err;
++
++ unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_PARENT);
++ parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ err = unionfs_file_revalidate(file, parent, false);
++ if (unlikely(err))
++ goto out;
++
++ rdstate = UNIONFS_F(file)->rdstate;
++
++ /*
++ * we let users seek to their current position, but not anywhere
++ * else.
++ */
++ if (!offset) {
++ switch (origin) {
++ case SEEK_SET:
++ if (rdstate) {
++ free_rdstate(rdstate);
++ UNIONFS_F(file)->rdstate = NULL;
++ }
++ init_rdstate(file);
++ err = 0;
++ break;
++ case SEEK_CUR:
++ err = file->f_pos;
++ break;
++ case SEEK_END:
++ /* Unsupported, because we would break everything. */
++ err = -EINVAL;
++ break;
++ }
++ } else {
++ switch (origin) {
++ case SEEK_SET:
++ if (rdstate) {
++ if (offset == rdstate2offset(rdstate))
++ err = offset;
++ else if (file->f_pos == DIREOF)
++ err = DIREOF;
++ else
++ err = -EINVAL;
++ } else {
++ struct inode *inode;
++ inode = dentry->d_inode;
++ rdstate = find_rdstate(inode, offset);
++ if (rdstate) {
++ UNIONFS_F(file)->rdstate = rdstate;
++ err = rdstate->offset;
++ } else {
++ err = -EINVAL;
++ }
++ }
++ break;
++ case SEEK_CUR:
++ case SEEK_END:
++ /* Unsupported, because we would break everything. */
++ err = -EINVAL;
++ break;
++ }
++ }
++
++out:
++ if (!err)
++ unionfs_check_file(file);
++ unionfs_unlock_dentry(dentry);
++ unionfs_unlock_parent(dentry, parent);
++ unionfs_read_unlock(dentry->d_sb);
++ return err;
++}
++
++/*
++ * Trimmed directory options, we shouldn't pass everything down since
++ * we don't want to operate on partial directories.
++ */
++struct file_operations unionfs_dir_fops = {
++ .llseek = unionfs_dir_llseek,
++ .read = generic_read_dir,
++ .readdir = unionfs_readdir,
++ .unlocked_ioctl = unionfs_ioctl,
++ .open = unionfs_open,
++ .release = unionfs_file_release,
++ .flush = unionfs_flush,
++ .fsync = unionfs_fsync,
++ .fasync = unionfs_fasync,
++};
+diff --git a/fs/unionfs/dirhelper.c b/fs/unionfs/dirhelper.c
+new file mode 100644
+index 0000000..62ec9af
+--- /dev/null
++++ b/fs/unionfs/dirhelper.c
+@@ -0,0 +1,158 @@
++/*
++ * Copyright (c) 2003-2011 Erez Zadok
++ * Copyright (c) 2003-2006 Charles P. Wright
++ * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
++ * Copyright (c) 2005-2006 Junjiro Okajima
++ * Copyright (c) 2005 Arun M. Krishnakumar
++ * Copyright (c) 2004-2006 David P. Quigley
++ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
++ * Copyright (c) 2003 Puja Gupta
++ * Copyright (c) 2003 Harikesavan Krishnan
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 The Research Foundation of SUNY
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "union.h"
++
++#define RD_NONE 0
++#define RD_CHECK_EMPTY 1
++/* The callback structure for check_empty. */
++struct unionfs_rdutil_callback {
++ int err;
++ int filldir_called;
++ struct unionfs_dir_state *rdstate;
++ int mode;
++};
++
++/* This filldir function makes sure only whiteouts exist within a directory. */
++static int readdir_util_callback(void *dirent, const char *oname, int namelen,
++ loff_t offset, u64 ino, unsigned int d_type)
++{
++ int err = 0;
++ struct unionfs_rdutil_callback *buf = dirent;
++ int is_whiteout;
++ struct filldir_node *found;
++ char *name = (char *) oname;
++
++ buf->filldir_called = 1;
++
++ if (name[0] == '.' && (namelen == 1 ||
++ (name[1] == '.' && namelen == 2)))
++ goto out;
++
++ is_whiteout = is_whiteout_name(&name, &namelen);
++
++ found = find_filldir_node(buf->rdstate, name, namelen, is_whiteout);
++ /* If it was found in the table there was a previous whiteout. */
++ if (found)
++ goto out;
++
++ /*
++ * if it wasn't found and isn't a whiteout, the directory isn't
++ * empty.
++ */
++ err = -ENOTEMPTY;
++ if ((buf->mode == RD_CHECK_EMPTY) && !is_whiteout)
++ goto out;
++
++ err = add_filldir_node(buf->rdstate, name, namelen,
++ buf->rdstate->bindex, is_whiteout);
++
++out:
++ buf->err = err;
++ return err;
++}
++
++/* Is a directory logically empty? */
++int check_empty(struct dentry *dentry, struct dentry *parent,
++ struct unionfs_dir_state **namelist)
++{
++ int err = 0;
++ struct dentry *lower_dentry = NULL;
++ struct vfsmount *mnt;
++ struct super_block *sb;
++ struct file *lower_file;
++ struct unionfs_rdutil_callback *buf = NULL;
++ int bindex, bstart, bend, bopaque;
++
++ sb = dentry->d_sb;
++
++
++ BUG_ON(!S_ISDIR(dentry->d_inode->i_mode));
++
++ err = unionfs_partial_lookup(dentry, parent);
++ if (err)
++ goto out;
++
++ bstart = dbstart(dentry);
++ bend = dbend(dentry);
++ bopaque = dbopaque(dentry);
++ if (0 <= bopaque && bopaque < bend)
++ bend = bopaque;
++
++ buf = kmalloc(sizeof(struct unionfs_rdutil_callback), GFP_KERNEL);
++ if (unlikely(!buf)) {
++ err = -ENOMEM;
++ goto out;
++ }
++ buf->err = 0;
++ buf->mode = RD_CHECK_EMPTY;
++ buf->rdstate = alloc_rdstate(dentry->d_inode, bstart);
++ if (unlikely(!buf->rdstate)) {
++ err = -ENOMEM;
++ goto out;
++ }
++
++ /* Process the lower directories with rdutil_callback as a filldir. */
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
++ if (!lower_dentry)
++ continue;
++ if (!lower_dentry->d_inode)
++ continue;
++ if (!S_ISDIR(lower_dentry->d_inode->i_mode))
++ continue;
++
++ dget(lower_dentry);
++ mnt = unionfs_mntget(dentry, bindex);
++ branchget(sb, bindex);
++ lower_file = dentry_open(lower_dentry, mnt, O_RDONLY, current_cred());
++ if (IS_ERR(lower_file)) {
++ err = PTR_ERR(lower_file);
++ branchput(sb, bindex);
++ goto out;
++ }
++
++ do {
++ buf->filldir_called = 0;
++ buf->rdstate->bindex = bindex;
++ err = vfs_readdir(lower_file,
++ readdir_util_callback, buf);
++ if (buf->err)
++ err = buf->err;
++ } while ((err >= 0) && buf->filldir_called);
++
++ /* fput calls dput for lower_dentry */
++ fput(lower_file);
++ branchput(sb, bindex);
++
++ if (err < 0)
++ goto out;
++ }
++
++out:
++ if (buf) {
++ if (namelist && !err)
++ *namelist = buf->rdstate;
++ else if (buf->rdstate)
++ free_rdstate(buf->rdstate);
++ kfree(buf);
++ }
++
++
++ return err;
++}
+diff --git a/fs/unionfs/fanout.h b/fs/unionfs/fanout.h
+new file mode 100644
+index 0000000..ae1b86a
+--- /dev/null
++++ b/fs/unionfs/fanout.h
+@@ -0,0 +1,407 @@
++/*
++ * Copyright (c) 2003-2011 Erez Zadok
++ * Copyright (c) 2003-2006 Charles P. Wright
++ * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
++ * Copyright (c) 2005 Arun M. Krishnakumar
++ * Copyright (c) 2004-2006 David P. Quigley
++ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
++ * Copyright (c) 2003 Puja Gupta
++ * Copyright (c) 2003 Harikesavan Krishnan
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 The Research Foundation of SUNY
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#ifndef _FANOUT_H_
++#define _FANOUT_H_
++
++/*
++ * Inode to private data
++ *
++ * Since we use containers and the struct inode is _inside_ the
++ * unionfs_inode_info structure, UNIONFS_I will always (given a non-NULL
++ * inode pointer), return a valid non-NULL pointer.
++ */
++static inline struct unionfs_inode_info *UNIONFS_I(const struct inode *inode)
++{
++ return container_of(inode, struct unionfs_inode_info, vfs_inode);
++}
++
++#define ibstart(ino) (UNIONFS_I(ino)->bstart)
++#define ibend(ino) (UNIONFS_I(ino)->bend)
++
++/* Dentry to private data */
++#define UNIONFS_D(dent) ((struct unionfs_dentry_info *)(dent)->d_fsdata)
++#define dbstart(dent) (UNIONFS_D(dent)->bstart)
++#define dbend(dent) (UNIONFS_D(dent)->bend)
++#define dbopaque(dent) (UNIONFS_D(dent)->bopaque)
++
++/* Superblock to private data */
++#define UNIONFS_SB(super) ((struct unionfs_sb_info *)(super)->s_fs_info)
++#define sbstart(sb) 0
++#define sbend(sb) (UNIONFS_SB(sb)->bend)
++#define sbmax(sb) (UNIONFS_SB(sb)->bend + 1)
++#define sbhbid(sb) (UNIONFS_SB(sb)->high_branch_id)
++
++/* File to private Data */
++#define UNIONFS_F(file) ((struct unionfs_file_info *)((file)->private_data))
++#define fbstart(file) (UNIONFS_F(file)->bstart)
++#define fbend(file) (UNIONFS_F(file)->bend)
++
++/* macros to manipulate branch IDs in stored in our superblock */
++static inline int branch_id(struct super_block *sb, int index)
++{
++ BUG_ON(!sb || index < 0);
++ return UNIONFS_SB(sb)->data[index].branch_id;
++}
++
++static inline void set_branch_id(struct super_block *sb, int index, int val)
++{
++ BUG_ON(!sb || index < 0);
++ UNIONFS_SB(sb)->data[index].branch_id = val;
++}
++
++static inline void new_branch_id(struct super_block *sb, int index)
++{
++ BUG_ON(!sb || index < 0);
++ set_branch_id(sb, index, ++UNIONFS_SB(sb)->high_branch_id);
++}
++
++/*
++ * Find new index of matching branch with an existing superblock of a known
++ * (possibly old) id. This is needed because branches could have been
++ * added/deleted causing the branches of any open files to shift.
++ *
++ * @sb: the new superblock which may have new/different branch IDs
++ * @id: the old/existing id we're looking for
++ * Returns index of newly found branch (0 or greater), -1 otherwise.
++ */
++static inline int branch_id_to_idx(struct super_block *sb, int id)
++{
++ int i;
++ for (i = 0; i < sbmax(sb); i++) {
++ if (branch_id(sb, i) == id)
++ return i;
++ }
++ /* in the non-ODF code, this should really never happen */
++ printk(KERN_WARNING "unionfs: cannot find branch with id %d\n", id);
++ return -1;
++}
++
++/* File to lower file. */
++static inline struct file *unionfs_lower_file(const struct file *f)
++{
++ BUG_ON(!f);
++ return UNIONFS_F(f)->lower_files[fbstart(f)];
++}
++
++static inline struct file *unionfs_lower_file_idx(const struct file *f,
++ int index)
++{
++ BUG_ON(!f || index < 0);
++ return UNIONFS_F(f)->lower_files[index];
++}
++
++static inline void unionfs_set_lower_file_idx(struct file *f, int index,
++ struct file *val)
++{
++ BUG_ON(!f || index < 0);
++ UNIONFS_F(f)->lower_files[index] = val;
++ /* save branch ID (may be redundant?) */
++ UNIONFS_F(f)->saved_branch_ids[index] =
++ branch_id((f)->f_path.dentry->d_sb, index);
++}
++
++static inline void unionfs_set_lower_file(struct file *f, struct file *val)
++{
++ BUG_ON(!f);
++ unionfs_set_lower_file_idx((f), fbstart(f), (val));
++}
++
++/* Inode to lower inode. */
++static inline struct inode *unionfs_lower_inode(const struct inode *i)
++{
++ BUG_ON(!i);
++ return UNIONFS_I(i)->lower_inodes[ibstart(i)];
++}
++
++static inline struct inode *unionfs_lower_inode_idx(const struct inode *i,
++ int index)
++{
++ BUG_ON(!i || index < 0);
++ return UNIONFS_I(i)->lower_inodes[index];
++}
++
++static inline void unionfs_set_lower_inode_idx(struct inode *i, int index,
++ struct inode *val)
++{
++ BUG_ON(!i || index < 0);
++ UNIONFS_I(i)->lower_inodes[index] = val;
++}
++
++static inline void unionfs_set_lower_inode(struct inode *i, struct inode *val)
++{
++ BUG_ON(!i);
++ UNIONFS_I(i)->lower_inodes[ibstart(i)] = val;
++}
++
++/* Superblock to lower superblock. */
++static inline struct super_block *unionfs_lower_super(
++ const struct super_block *sb)
++{
++ BUG_ON(!sb);
++ return UNIONFS_SB(sb)->data[sbstart(sb)].sb;
++}
++
++static inline struct super_block *unionfs_lower_super_idx(
++ const struct super_block *sb,
++ int index)
++{
++ BUG_ON(!sb || index < 0);
++ return UNIONFS_SB(sb)->data[index].sb;
++}
++
++static inline void unionfs_set_lower_super_idx(struct super_block *sb,
++ int index,
++ struct super_block *val)
++{
++ BUG_ON(!sb || index < 0);
++ UNIONFS_SB(sb)->data[index].sb = val;
++}
++
++static inline void unionfs_set_lower_super(struct super_block *sb,
++ struct super_block *val)
++{
++ BUG_ON(!sb);
++ UNIONFS_SB(sb)->data[sbstart(sb)].sb = val;
++}
++
++/* Branch count macros. */
++static inline int branch_count(const struct super_block *sb, int index)
++{
++ BUG_ON(!sb || index < 0);
++ return atomic_read(&UNIONFS_SB(sb)->data[index].open_files);
++}
++
++static inline void set_branch_count(struct super_block *sb, int index, int val)
++{
++ BUG_ON(!sb || index < 0);
++ atomic_set(&UNIONFS_SB(sb)->data[index].open_files, val);
++}
++
++static inline void branchget(struct super_block *sb, int index)
++{
++ BUG_ON(!sb || index < 0);
++ atomic_inc(&UNIONFS_SB(sb)->data[index].open_files);
++}
++
++static inline void branchput(struct super_block *sb, int index)
++{
++ BUG_ON(!sb || index < 0);
++ atomic_dec(&UNIONFS_SB(sb)->data[index].open_files);
++}
++
++/* Dentry macros */
++static inline void unionfs_set_lower_dentry_idx(struct dentry *dent, int index,
++ struct dentry *val)
++{
++ BUG_ON(!dent || index < 0);
++ UNIONFS_D(dent)->lower_paths[index].dentry = val;
++}
++
++static inline struct dentry *unionfs_lower_dentry_idx(
++ const struct dentry *dent,
++ int index)
++{
++ BUG_ON(!dent || index < 0);
++ return UNIONFS_D(dent)->lower_paths[index].dentry;
++}
++
++static inline struct dentry *unionfs_lower_dentry(const struct dentry *dent)
++{
++ BUG_ON(!dent);
++ return unionfs_lower_dentry_idx(dent, dbstart(dent));
++}
++
++static inline void unionfs_set_lower_mnt_idx(struct dentry *dent, int index,
++ struct vfsmount *mnt)
++{
++ BUG_ON(!dent || index < 0);
++ UNIONFS_D(dent)->lower_paths[index].mnt = mnt;
++}
++
++static inline struct vfsmount *unionfs_lower_mnt_idx(
++ const struct dentry *dent,
++ int index)
++{
++ BUG_ON(!dent || index < 0);
++ return UNIONFS_D(dent)->lower_paths[index].mnt;
++}
++
++static inline struct vfsmount *unionfs_lower_mnt(const struct dentry *dent)
++{
++ BUG_ON(!dent);
++ return unionfs_lower_mnt_idx(dent, dbstart(dent));
++}
++
++/* Macros for locking a dentry. */
++enum unionfs_dentry_lock_class {
++ UNIONFS_DMUTEX_NORMAL,
++ UNIONFS_DMUTEX_ROOT,
++ UNIONFS_DMUTEX_PARENT,
++ UNIONFS_DMUTEX_CHILD,
++ UNIONFS_DMUTEX_WHITEOUT,
++ UNIONFS_DMUTEX_REVAL_PARENT, /* for file/dentry revalidate */
++ UNIONFS_DMUTEX_REVAL_CHILD, /* for file/dentry revalidate */
++};
++
++static inline void unionfs_lock_dentry(struct dentry *d,
++ unsigned int subclass)
++{
++ BUG_ON(!d);
++ mutex_lock_nested(&UNIONFS_D(d)->lock, subclass);
++}
++
++static inline void unionfs_unlock_dentry(struct dentry *d)
++{
++ BUG_ON(!d);
++ mutex_unlock(&UNIONFS_D(d)->lock);
++}
++
++static inline struct dentry *unionfs_lock_parent(struct dentry *d,
++ unsigned int subclass)
++{
++ struct dentry *p;
++
++ BUG_ON(!d);
++ p = dget_parent(d);
++ if (p != d)
++ mutex_lock_nested(&UNIONFS_D(p)->lock, subclass);
++ return p;
++}
++
++static inline void unionfs_unlock_parent(struct dentry *d, struct dentry *p)
++{
++ BUG_ON(!d);
++ BUG_ON(!p);
++ if (p != d) {
++ BUG_ON(!mutex_is_locked(&UNIONFS_D(p)->lock));
++ mutex_unlock(&UNIONFS_D(p)->lock);
++ }
++ dput(p);
++}
++
++static inline void verify_locked(struct dentry *d)
++{
++ BUG_ON(!d);
++ BUG_ON(!mutex_is_locked(&UNIONFS_D(d)->lock));
++}
++
++/* macros to put lower objects */
++
++/*
++ * iput lower inodes of an unionfs dentry, from bstart to bend. If
++ * @free_lower is true, then also kfree the memory used to hold the lower
++ * object pointers.
++ */
++static inline void iput_lowers(struct inode *inode,
++ int bstart, int bend, bool free_lower)
++{
++ struct inode *lower_inode;
++ int bindex;
++
++ BUG_ON(!inode);
++ BUG_ON(!UNIONFS_I(inode));
++ BUG_ON(bstart < 0);
++
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ lower_inode = unionfs_lower_inode_idx(inode, bindex);
++ if (lower_inode) {
++ unionfs_set_lower_inode_idx(inode, bindex, NULL);
++ /* see Documentation/filesystems/unionfs/issues.txt */
++ lockdep_off();
++ iput(lower_inode);
++ lockdep_on();
++ }
++ }
++
++ if (free_lower) {
++ kfree(UNIONFS_I(inode)->lower_inodes);
++ UNIONFS_I(inode)->lower_inodes = NULL;
++ }
++}
++
++/* iput all lower inodes, and reset start/end branch indices to -1 */
++static inline void iput_lowers_all(struct inode *inode, bool free_lower)
++{
++ int bstart, bend;
++
++ BUG_ON(!inode);
++ BUG_ON(!UNIONFS_I(inode));
++ bstart = ibstart(inode);
++ bend = ibend(inode);
++ BUG_ON(bstart < 0);
++
++ iput_lowers(inode, bstart, bend, free_lower);
++ ibstart(inode) = ibend(inode) = -1;
++}
++
++/*
++ * dput/mntput all lower dentries and vfsmounts of an unionfs dentry, from
++ * bstart to bend. If @free_lower is true, then also kfree the memory used
++ * to hold the lower object pointers.
++ *
++ * XXX: implement using path_put VFS macros
++ */
++static inline void path_put_lowers(struct dentry *dentry,
++ int bstart, int bend, bool free_lower)
++{
++ struct dentry *lower_dentry;
++ struct vfsmount *lower_mnt;
++ int bindex;
++
++ BUG_ON(!dentry);
++ BUG_ON(!UNIONFS_D(dentry));
++ BUG_ON(bstart < 0);
++
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
++ if (lower_dentry) {
++ unionfs_set_lower_dentry_idx(dentry, bindex, NULL);
++ dput(lower_dentry);
++ }
++ lower_mnt = unionfs_lower_mnt_idx(dentry, bindex);
++ if (lower_mnt) {
++ unionfs_set_lower_mnt_idx(dentry, bindex, NULL);
++ mntput(lower_mnt);
++ }
++ }
++
++ if (free_lower) {
++ kfree(UNIONFS_D(dentry)->lower_paths);
++ UNIONFS_D(dentry)->lower_paths = NULL;
++ }
++}
++
++/*
++ * dput/mntput all lower dentries and vfsmounts, and reset start/end branch
++ * indices to -1.
++ */
++static inline void path_put_lowers_all(struct dentry *dentry, bool free_lower)
++{
++ int bstart, bend;
++
++ BUG_ON(!dentry);
++ BUG_ON(!UNIONFS_D(dentry));
++ bstart = dbstart(dentry);
++ bend = dbend(dentry);
++ BUG_ON(bstart < 0);
++
++ path_put_lowers(dentry, bstart, bend, free_lower);
++ dbstart(dentry) = dbend(dentry) = -1;
++}
++
++#endif /* not _FANOUT_H */
+diff --git a/fs/unionfs/file.c b/fs/unionfs/file.c
+new file mode 100644
+index 0000000..416c52f
+--- /dev/null
++++ b/fs/unionfs/file.c
+@@ -0,0 +1,382 @@
++/*
++ * Copyright (c) 2003-2011 Erez Zadok
++ * Copyright (c) 2003-2006 Charles P. Wright
++ * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
++ * Copyright (c) 2005-2006 Junjiro Okajima
++ * Copyright (c) 2005 Arun M. Krishnakumar
++ * Copyright (c) 2004-2006 David P. Quigley
++ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
++ * Copyright (c) 2003 Puja Gupta
++ * Copyright (c) 2003 Harikesavan Krishnan
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 The Research Foundation of SUNY
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "union.h"
++
++static ssize_t unionfs_read(struct file *file, char __user *buf,
++ size_t count, loff_t *ppos)
++{
++ int err;
++ struct file *lower_file;
++ struct dentry *dentry = file->f_path.dentry;
++ struct dentry *parent;
++
++ unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_PARENT);
++ parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ err = unionfs_file_revalidate(file, parent, false);
++ if (unlikely(err))
++ goto out;
++
++ lower_file = unionfs_lower_file(file);
++ err = vfs_read(lower_file, buf, count, ppos);
++ /* update our inode atime upon a successful lower read */
++ if (err >= 0) {
++ fsstack_copy_attr_atime(dentry->d_inode,
++ lower_file->f_path.dentry->d_inode);
++ unionfs_check_file(file);
++ }
++
++out:
++ unionfs_unlock_dentry(dentry);
++ unionfs_unlock_parent(dentry, parent);
++ unionfs_read_unlock(dentry->d_sb);
++ return err;
++}
++
++static ssize_t unionfs_write(struct file *file, const char __user *buf,
++ size_t count, loff_t *ppos)
++{
++ int err = 0;
++ struct file *lower_file;
++ struct dentry *dentry = file->f_path.dentry;
++ struct dentry *parent;
++
++ unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_PARENT);
++ parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ err = unionfs_file_revalidate(file, parent, true);
++ if (unlikely(err))
++ goto out;
++
++ lower_file = unionfs_lower_file(file);
++ err = vfs_write(lower_file, buf, count, ppos);
++ /* update our inode times+sizes upon a successful lower write */
++ if (err >= 0) {
++ fsstack_copy_inode_size(dentry->d_inode,
++ lower_file->f_path.dentry->d_inode);
++ fsstack_copy_attr_times(dentry->d_inode,
++ lower_file->f_path.dentry->d_inode);
++ UNIONFS_F(file)->wrote_to_file = true; /* for delayed copyup */
++ unionfs_check_file(file);
++ }
++
++out:
++ unionfs_unlock_dentry(dentry);
++ unionfs_unlock_parent(dentry, parent);
++ unionfs_read_unlock(dentry->d_sb);
++ return err;
++}
++
++static int unionfs_file_readdir(struct file *file, void *dirent,
++ filldir_t filldir)
++{
++ return -ENOTDIR;
++}
++
++static int unionfs_mmap(struct file *file, struct vm_area_struct *vma)
++{
++ int err = 0;
++ bool willwrite;
++ struct file *lower_file;
++ struct dentry *dentry = file->f_path.dentry;
++ struct dentry *parent;
++ const struct vm_operations_struct *saved_vm_ops = NULL;
++
++ /*
++ * Since mm/memory.c:might_fault() (under PROVE_LOCKING) was
++ * modified in 2.6.29-rc1 to call might_lock_read on mmap_sem, this
++ * has been causing false positives in file system stacking layers.
++ * In particular, our ->mmap is called after sys_mmap2 already holds
++ * mmap_sem, then we lock our own mutexes; but earlier, it's
++ * possible for lockdep to have locked our mutexes first, and then
++ * we call a lower ->readdir which could call might_fault. The
++ * different ordering of the locks is what lockdep complains about
++ * -- unnecessarily. Therefore, we have no choice but to tell
++ * lockdep to temporarily turn off lockdep here. Note: the comments
++ * inside might_sleep also suggest that it would have been
++ * nicer to only annotate paths that needs that might_lock_read.
++ */
++ lockdep_off();
++ unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_PARENT);
++ parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ /* This might be deferred to mmap's writepage */
++ willwrite = ((vma->vm_flags | VM_SHARED | VM_WRITE) == vma->vm_flags);
++ err = unionfs_file_revalidate(file, parent, willwrite);
++ if (unlikely(err))
++ goto out;
++ unionfs_check_file(file);
++
++ /*
++ * File systems which do not implement ->writepage may use
++ * generic_file_readonly_mmap as their ->mmap op. If you call
++ * generic_file_readonly_mmap with VM_WRITE, you'd get an -EINVAL.
++ * But we cannot call the lower ->mmap op, so we can't tell that
++ * writeable mappings won't work. Therefore, our only choice is to
++ * check if the lower file system supports the ->writepage, and if
++ * not, return EINVAL (the same error that
++ * generic_file_readonly_mmap returns in that case).
++ */
++ lower_file = unionfs_lower_file(file);
++ if (willwrite && !lower_file->f_mapping->a_ops->writepage) {
++ err = -EINVAL;
++ printk(KERN_ERR "unionfs: branch %d file system does not "
++ "support writeable mmap\n", fbstart(file));
++ goto out;
++ }
++
++ /*
++ * find and save lower vm_ops.
++ *
++ * XXX: the VFS should have a cleaner way of finding the lower vm_ops
++ */
++ if (!UNIONFS_F(file)->lower_vm_ops) {
++ err = lower_file->f_op->mmap(lower_file, vma);
++ if (err) {
++ printk(KERN_ERR "unionfs: lower mmap failed %d\n", err);
++ goto out;
++ }
++ saved_vm_ops = vma->vm_ops;
++ err = do_munmap(current->mm, vma->vm_start,
++ vma->vm_end - vma->vm_start);
++ if (err) {
++ printk(KERN_ERR "unionfs: do_munmap failed %d\n", err);
++ goto out;
++ }
++ }
++
++ file->f_mapping->a_ops = &unionfs_dummy_aops;
++ err = generic_file_mmap(file, vma);
++ file->f_mapping->a_ops = &unionfs_aops;
++ if (err) {
++ printk(KERN_ERR "unionfs: generic_file_mmap failed %d\n", err);
++ goto out;
++ }
++ vma->vm_ops = &unionfs_vm_ops;
++ if (!UNIONFS_F(file)->lower_vm_ops)
++ UNIONFS_F(file)->lower_vm_ops = saved_vm_ops;
++
++out:
++ if (!err) {
++ /* copyup could cause parent dir times to change */
++ unionfs_copy_attr_times(parent->d_inode);
++ unionfs_check_file(file);
++ }
++ unionfs_unlock_dentry(dentry);
++ unionfs_unlock_parent(dentry, parent);
++ unionfs_read_unlock(dentry->d_sb);
++ lockdep_on();
++ return err;
++}
++
++int unionfs_fsync(struct file *file, int datasync)
++{
++ int bindex, bstart, bend;
++ struct file *lower_file;
++ struct dentry *dentry = file->f_path.dentry;
++ struct dentry *lower_dentry;
++ struct dentry *parent;
++ struct inode *lower_inode, *inode;
++ int err = -EINVAL;
++
++ unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_PARENT);
++ parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ err = unionfs_file_revalidate(file, parent, true);
++ if (unlikely(err))
++ goto out;
++ unionfs_check_file(file);
++
++ bstart = fbstart(file);
++ bend = fbend(file);
++ if (bstart < 0 || bend < 0)
++ goto out;
++
++ inode = dentry->d_inode;
++ if (unlikely(!inode)) {
++ printk(KERN_ERR
++ "unionfs: null lower inode in unionfs_fsync\n");
++ goto out;
++ }
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ lower_inode = unionfs_lower_inode_idx(inode, bindex);
++ if (!lower_inode || !lower_inode->i_fop->fsync)
++ continue;
++ lower_file = unionfs_lower_file_idx(file, bindex);
++ lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
++ mutex_lock(&lower_inode->i_mutex);
++ err = lower_inode->i_fop->fsync(lower_file, datasync);
++ if (!err && bindex == bstart)
++ fsstack_copy_attr_times(inode, lower_inode);
++ mutex_unlock(&lower_inode->i_mutex);
++ if (err)
++ goto out;
++ }
++
++out:
++ if (!err)
++ unionfs_check_file(file);
++ unionfs_unlock_dentry(dentry);
++ unionfs_unlock_parent(dentry, parent);
++ unionfs_read_unlock(dentry->d_sb);
++ return err;
++}
++
++int unionfs_fasync(int fd, struct file *file, int flag)
++{
++ int bindex, bstart, bend;
++ struct file *lower_file;
++ struct dentry *dentry = file->f_path.dentry;
++ struct dentry *parent;
++ struct inode *lower_inode, *inode;
++ int err = 0;
++
++ unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_PARENT);
++ parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ err = unionfs_file_revalidate(file, parent, true);
++ if (unlikely(err))
++ goto out;
++ unionfs_check_file(file);
++
++ bstart = fbstart(file);
++ bend = fbend(file);
++ if (bstart < 0 || bend < 0)
++ goto out;
++
++ inode = dentry->d_inode;
++ if (unlikely(!inode)) {
++ printk(KERN_ERR
++ "unionfs: null lower inode in unionfs_fasync\n");
++ goto out;
++ }
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ lower_inode = unionfs_lower_inode_idx(inode, bindex);
++ if (!lower_inode || !lower_inode->i_fop->fasync)
++ continue;
++ lower_file = unionfs_lower_file_idx(file, bindex);
++ mutex_lock(&lower_inode->i_mutex);
++ err = lower_inode->i_fop->fasync(fd, lower_file, flag);
++ if (!err && bindex == bstart)
++ fsstack_copy_attr_times(inode, lower_inode);
++ mutex_unlock(&lower_inode->i_mutex);
++ if (err)
++ goto out;
++ }
++
++out:
++ if (!err)
++ unionfs_check_file(file);
++ unionfs_unlock_dentry(dentry);
++ unionfs_unlock_parent(dentry, parent);
++ unionfs_read_unlock(dentry->d_sb);
++ return err;
++}
++
++static ssize_t unionfs_splice_read(struct file *file, loff_t *ppos,
++ struct pipe_inode_info *pipe, size_t len,
++ unsigned int flags)
++{
++ ssize_t err;
++ struct file *lower_file;
++ struct dentry *dentry = file->f_path.dentry;
++ struct dentry *parent;
++
++ unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_PARENT);
++ parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ err = unionfs_file_revalidate(file, parent, false);
++ if (unlikely(err))
++ goto out;
++
++ lower_file = unionfs_lower_file(file);
++ err = vfs_splice_to(lower_file, ppos, pipe, len, flags);
++ /* update our inode atime upon a successful lower splice-read */
++ if (err >= 0) {
++ fsstack_copy_attr_atime(dentry->d_inode,
++ lower_file->f_path.dentry->d_inode);
++ unionfs_check_file(file);
++ }
++
++out:
++ unionfs_unlock_dentry(dentry);
++ unionfs_unlock_parent(dentry, parent);
++ unionfs_read_unlock(dentry->d_sb);
++ return err;
++}
++
++static ssize_t unionfs_splice_write(struct pipe_inode_info *pipe,
++ struct file *file, loff_t *ppos,
++ size_t len, unsigned int flags)
++{
++ ssize_t err = 0;
++ struct file *lower_file;
++ struct dentry *dentry = file->f_path.dentry;
++ struct dentry *parent;
++
++ unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_PARENT);
++ parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ err = unionfs_file_revalidate(file, parent, true);
++ if (unlikely(err))
++ goto out;
++
++ lower_file = unionfs_lower_file(file);
++ err = vfs_splice_from(pipe, lower_file, ppos, len, flags);
++ /* update our inode times+sizes upon a successful lower write */
++ if (err >= 0) {
++ fsstack_copy_inode_size(dentry->d_inode,
++ lower_file->f_path.dentry->d_inode);
++ fsstack_copy_attr_times(dentry->d_inode,
++ lower_file->f_path.dentry->d_inode);
++ unionfs_check_file(file);
++ }
++
++out:
++ unionfs_unlock_dentry(dentry);
++ unionfs_unlock_parent(dentry, parent);
++ unionfs_read_unlock(dentry->d_sb);
++ return err;
++}
++
++struct file_operations unionfs_main_fops = {
++ .llseek = generic_file_llseek,
++ .read = unionfs_read,
++ .write = unionfs_write,
++ .readdir = unionfs_file_readdir,
++ .unlocked_ioctl = unionfs_ioctl,
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = unionfs_ioctl,
++#endif
++ .mmap = unionfs_mmap,
++ .open = unionfs_open,
++ .flush = unionfs_flush,
++ .release = unionfs_file_release,
++ .fsync = unionfs_fsync,
++ .fasync = unionfs_fasync,
++ .splice_read = unionfs_splice_read,
++ .splice_write = unionfs_splice_write,
++};
+diff --git a/fs/unionfs/inode.c b/fs/unionfs/inode.c
+new file mode 100644
+index 0000000..b207c13
+--- /dev/null
++++ b/fs/unionfs/inode.c
+@@ -0,0 +1,1099 @@
++/*
++ * Copyright (c) 2003-2011 Erez Zadok
++ * Copyright (c) 2003-2006 Charles P. Wright
++ * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
++ * Copyright (c) 2005-2006 Junjiro Okajima
++ * Copyright (c) 2005 Arun M. Krishnakumar
++ * Copyright (c) 2004-2006 David P. Quigley
++ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
++ * Copyright (c) 2003 Puja Gupta
++ * Copyright (c) 2003 Harikesavan Krishnan
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 The Research Foundation of SUNY
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "union.h"
++
++/*
++ * Find a writeable branch to create new object in. Checks all writeble
++ * branches of the parent inode, from istart to iend order; if none are
++ * suitable, also tries branch 0 (which may require a copyup).
++ *
++ * Return a lower_dentry we can use to create object in, or ERR_PTR.
++ */
++static struct dentry *find_writeable_branch(struct inode *parent,
++ struct dentry *dentry)
++{
++ int err = -EINVAL;
++ int bindex, istart, iend;
++ struct dentry *lower_dentry = NULL;
++
++ istart = ibstart(parent);
++ iend = ibend(parent);
++ if (istart < 0)
++ goto out;
++
++begin:
++ for (bindex = istart; bindex <= iend; bindex++) {
++ /* skip non-writeable branches */
++ err = is_robranch_super(dentry->d_sb, bindex);
++ if (err) {
++ err = -EROFS;
++ continue;
++ }
++ lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
++ if (!lower_dentry)
++ continue;
++ /*
++ * check for whiteouts in writeable branch, and remove them
++ * if necessary.
++ */
++ err = check_unlink_whiteout(dentry, lower_dentry, bindex);
++ if (err > 0) /* ignore if whiteout found and removed */
++ err = 0;
++ if (err)
++ continue;
++ /* if get here, we can write to the branch */
++ break;
++ }
++ /*
++ * If istart wasn't already branch 0, and we got any error, then try
++ * branch 0 (which may require copyup)
++ */
++ if (err && istart > 0) {
++ istart = iend = 0;
++ goto begin;
++ }
++
++ /*
++ * If we tried even branch 0, and still got an error, abort. But if
++ * the error was an EROFS, then we should try to copyup.
++ */
++ if (err && err != -EROFS)
++ goto out;
++
++ /*
++ * If we get here, then check if copyup needed. If lower_dentry is
++ * NULL, create the entire dentry directory structure in branch 0.
++ */
++ if (!lower_dentry) {
++ bindex = 0;
++ lower_dentry = create_parents(parent, dentry,
++ dentry->d_name.name, bindex);
++ if (IS_ERR(lower_dentry)) {
++ err = PTR_ERR(lower_dentry);
++ goto out;
++ }
++ }
++ err = 0; /* all's well */
++out:
++ if (err)
++ return ERR_PTR(err);
++ return lower_dentry;
++}
++
++static int unionfs_create(struct inode *dir, struct dentry *dentry,
++ int mode, struct nameidata *nd_unused)
++{
++ int err = 0;
++ struct dentry *lower_dentry = NULL;
++ struct dentry *lower_parent_dentry = NULL;
++ struct dentry *parent;
++ int valid = 0;
++ struct nameidata lower_nd;
++
++ unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD);
++ parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ valid = __unionfs_d_revalidate(dentry, parent, false);
++ if (unlikely(!valid)) {
++ err = -ESTALE; /* same as what real_lookup does */
++ goto out;
++ }
++
++ lower_dentry = find_writeable_branch(dir, dentry);
++ if (IS_ERR(lower_dentry)) {
++ err = PTR_ERR(lower_dentry);
++ goto out;
++ }
++
++ lower_parent_dentry = lock_parent(lower_dentry);
++ if (IS_ERR(lower_parent_dentry)) {
++ err = PTR_ERR(lower_parent_dentry);
++ goto out_unlock;
++ }
++
++ err = init_lower_nd(&lower_nd, LOOKUP_CREATE);
++ if (unlikely(err < 0))
++ goto out_unlock;
++ err = vfs_create(lower_parent_dentry->d_inode, lower_dentry, mode,
++ &lower_nd);
++ release_lower_nd(&lower_nd, err);
++
++ if (!err) {
++ err = PTR_ERR(unionfs_interpose(dentry, dir->i_sb, 0));
++ if (!err) {
++ unionfs_copy_attr_times(dir);
++ fsstack_copy_inode_size(dir,
++ lower_parent_dentry->d_inode);
++ /* update no. of links on parent directory */
++ dir->i_nlink = unionfs_get_nlinks(dir);
++ }
++ }
++
++out_unlock:
++ unlock_dir(lower_parent_dentry);
++out:
++ if (!err) {
++ unionfs_postcopyup_setmnt(dentry);
++ unionfs_check_inode(dir);
++ unionfs_check_dentry(dentry);
++ }
++ unionfs_unlock_dentry(dentry);
++ unionfs_unlock_parent(dentry, parent);
++ unionfs_read_unlock(dentry->d_sb);
++ return err;
++}
++
++/*
++ * unionfs_lookup is the only special function which takes a dentry, yet we
++ * do NOT want to call __unionfs_d_revalidate_chain because by definition,
++ * we don't have a valid dentry here yet.
++ */
++static struct dentry *unionfs_lookup(struct inode *dir,
++ struct dentry *dentry,
++ struct nameidata *nd_unused)
++{
++ struct dentry *ret, *parent;
++ int err = 0;
++
++ unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD);
++ parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
++
++ /*
++ * As long as we lock/dget the parent, then can skip validating the
++ * parent now; we may have to rebuild this dentry on the next
++ * ->d_revalidate, however.
++ */
++
++ /* allocate dentry private data. We free it in ->d_release */
++ err = new_dentry_private_data(dentry, UNIONFS_DMUTEX_CHILD);
++ if (unlikely(err)) {
++ ret = ERR_PTR(err);
++ goto out;
++ }
++
++ ret = unionfs_lookup_full(dentry, parent, INTERPOSE_LOOKUP);
++
++ if (!IS_ERR(ret)) {
++ if (ret)
++ dentry = ret;
++ /* lookup_full can return multiple positive dentries */
++ if (dentry->d_inode && !S_ISDIR(dentry->d_inode->i_mode)) {
++ BUG_ON(dbstart(dentry) < 0);
++ unionfs_postcopyup_release(dentry);
++ }
++ unionfs_copy_attr_times(dentry->d_inode);
++ }
++
++ unionfs_check_inode(dir);
++ if (!IS_ERR(ret))
++ unionfs_check_dentry(dentry);
++ unionfs_check_dentry(parent);
++ unionfs_unlock_dentry(dentry); /* locked in new_dentry_private data */
++
++out:
++ unionfs_unlock_parent(dentry, parent);
++ unionfs_read_unlock(dentry->d_sb);
++
++ return ret;
++}
++
++static int unionfs_link(struct dentry *old_dentry, struct inode *dir,
++ struct dentry *new_dentry)
++{
++ int err = 0;
++ struct dentry *lower_old_dentry = NULL;
++ struct dentry *lower_new_dentry = NULL;
++ struct dentry *lower_dir_dentry = NULL;
++ struct dentry *old_parent, *new_parent;
++ char *name = NULL;
++ bool valid;
++
++ unionfs_read_lock(old_dentry->d_sb, UNIONFS_SMUTEX_CHILD);
++ old_parent = dget_parent(old_dentry);
++ new_parent = dget_parent(new_dentry);
++ unionfs_double_lock_parents(old_parent, new_parent);
++ unionfs_double_lock_dentry(old_dentry, new_dentry);
++
++ valid = __unionfs_d_revalidate(old_dentry, old_parent, false);
++ if (unlikely(!valid)) {
++ err = -ESTALE;
++ goto out;
++ }
++ if (new_dentry->d_inode) {
++ valid = __unionfs_d_revalidate(new_dentry, new_parent, false);
++ if (unlikely(!valid)) {
++ err = -ESTALE;
++ goto out;
++ }
++ }
++
++ lower_new_dentry = unionfs_lower_dentry(new_dentry);
++
++ /* check for a whiteout in new dentry branch, and delete it */
++ err = check_unlink_whiteout(new_dentry, lower_new_dentry,
++ dbstart(new_dentry));
++ if (err > 0) { /* whiteout found and removed successfully */
++ lower_dir_dentry = dget_parent(lower_new_dentry);
++ fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
++ dput(lower_dir_dentry);
++ dir->i_nlink = unionfs_get_nlinks(dir);
++ err = 0;
++ }
++ if (err)
++ goto out;
++
++ /* check if parent hierachy is needed, then link in same branch */
++ if (dbstart(old_dentry) != dbstart(new_dentry)) {
++ lower_new_dentry = create_parents(dir, new_dentry,
++ new_dentry->d_name.name,
++ dbstart(old_dentry));
++ err = PTR_ERR(lower_new_dentry);
++ if (IS_COPYUP_ERR(err))
++ goto docopyup;
++ if (!lower_new_dentry || IS_ERR(lower_new_dentry))
++ goto out;
++ }
++ lower_new_dentry = unionfs_lower_dentry(new_dentry);
++ lower_old_dentry = unionfs_lower_dentry(old_dentry);
++
++ BUG_ON(dbstart(old_dentry) != dbstart(new_dentry));
++ lower_dir_dentry = lock_parent(lower_new_dentry);
++ err = is_robranch(old_dentry);
++ if (!err) {
++ /* see Documentation/filesystems/unionfs/issues.txt */
++ lockdep_off();
++ err = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode,
++ lower_new_dentry);
++ lockdep_on();
++ }
++ unlock_dir(lower_dir_dentry);
++
++docopyup:
++ if (IS_COPYUP_ERR(err)) {
++ int old_bstart = dbstart(old_dentry);
++ int bindex;
++
++ for (bindex = old_bstart - 1; bindex >= 0; bindex--) {
++ err = copyup_dentry(old_parent->d_inode,
++ old_dentry, old_bstart,
++ bindex, old_dentry->d_name.name,
++ old_dentry->d_name.len, NULL,
++ i_size_read(old_dentry->d_inode));
++ if (err)
++ continue;
++ lower_new_dentry =
++ create_parents(dir, new_dentry,
++ new_dentry->d_name.name,
++ bindex);
++ lower_old_dentry = unionfs_lower_dentry(old_dentry);
++ lower_dir_dentry = lock_parent(lower_new_dentry);
++ /* see Documentation/filesystems/unionfs/issues.txt */
++ lockdep_off();
++ /* do vfs_link */
++ err = vfs_link(lower_old_dentry,
++ lower_dir_dentry->d_inode,
++ lower_new_dentry);
++ lockdep_on();
++ unlock_dir(lower_dir_dentry);
++ goto check_link;
++ }
++ goto out;
++ }
++
++check_link:
++ if (err || !lower_new_dentry->d_inode)
++ goto out;
++
++ /* Its a hard link, so use the same inode */
++ new_dentry->d_inode = igrab(old_dentry->d_inode);
++ d_add(new_dentry, new_dentry->d_inode);
++ unionfs_copy_attr_all(dir, lower_new_dentry->d_parent->d_inode);
++ fsstack_copy_inode_size(dir, lower_new_dentry->d_parent->d_inode);
++
++ /* propagate number of hard-links */
++ old_dentry->d_inode->i_nlink = unionfs_get_nlinks(old_dentry->d_inode);
++ /* new dentry's ctime may have changed due to hard-link counts */
++ unionfs_copy_attr_times(new_dentry->d_inode);
++
++out:
++ if (!new_dentry->d_inode)
++ d_drop(new_dentry);
++
++ kfree(name);
++ if (!err)
++ unionfs_postcopyup_setmnt(new_dentry);
++
++ unionfs_check_inode(dir);
++ unionfs_check_dentry(new_dentry);
++ unionfs_check_dentry(old_dentry);
++
++ unionfs_double_unlock_dentry(old_dentry, new_dentry);
++ unionfs_double_unlock_parents(old_parent, new_parent);
++ dput(new_parent);
++ dput(old_parent);
++ unionfs_read_unlock(old_dentry->d_sb);
++
++ return err;
++}
++
++static int unionfs_symlink(struct inode *dir, struct dentry *dentry,
++ const char *symname)
++{
++ int err = 0;
++ struct dentry *lower_dentry = NULL;
++ struct dentry *wh_dentry = NULL;
++ struct dentry *lower_parent_dentry = NULL;
++ struct dentry *parent;
++ char *name = NULL;
++ int valid = 0;
++ umode_t mode;
++
++ unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD);
++ parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ valid = __unionfs_d_revalidate(dentry, parent, false);
++ if (unlikely(!valid)) {
++ err = -ESTALE;
++ goto out;
++ }
++
++ /*
++ * It's only a bug if this dentry was not negative and couldn't be
++ * revalidated (shouldn't happen).
++ */
++ BUG_ON(!valid && dentry->d_inode);
++
++ lower_dentry = find_writeable_branch(dir, dentry);
++ if (IS_ERR(lower_dentry)) {
++ err = PTR_ERR(lower_dentry);
++ goto out;
++ }
++
++ lower_parent_dentry = lock_parent(lower_dentry);
++ if (IS_ERR(lower_parent_dentry)) {
++ err = PTR_ERR(lower_parent_dentry);
++ goto out_unlock;
++ }
++
++ mode = S_IALLUGO;
++ err = vfs_symlink(lower_parent_dentry->d_inode, lower_dentry, symname);
++ if (!err) {
++ err = PTR_ERR(unionfs_interpose(dentry, dir->i_sb, 0));
++ if (!err) {
++ unionfs_copy_attr_times(dir);
++ fsstack_copy_inode_size(dir,
++ lower_parent_dentry->d_inode);
++ /* update no. of links on parent directory */
++ dir->i_nlink = unionfs_get_nlinks(dir);
++ }
++ }
++
++out_unlock:
++ unlock_dir(lower_parent_dentry);
++out:
++ dput(wh_dentry);
++ kfree(name);
++
++ if (!err) {
++ unionfs_postcopyup_setmnt(dentry);
++ unionfs_check_inode(dir);
++ unionfs_check_dentry(dentry);
++ }
++ unionfs_unlock_dentry(dentry);
++ unionfs_unlock_parent(dentry, parent);
++ unionfs_read_unlock(dentry->d_sb);
++ return err;
++}
++
++static int unionfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
++{
++ int err = 0;
++ struct dentry *lower_dentry = NULL;
++ struct dentry *lower_parent_dentry = NULL;
++ struct dentry *parent;
++ int bindex = 0, bstart;
++ char *name = NULL;
++ int valid;
++
++ unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD);
++ parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ valid = __unionfs_d_revalidate(dentry, parent, false);
++ if (unlikely(!valid)) {
++ err = -ESTALE; /* same as what real_lookup does */
++ goto out;
++ }
++
++ bstart = dbstart(dentry);
++
++ lower_dentry = unionfs_lower_dentry(dentry);
++
++ /* check for a whiteout in new dentry branch, and delete it */
++ err = check_unlink_whiteout(dentry, lower_dentry, bstart);
++ if (err > 0) /* whiteout found and removed successfully */
++ err = 0;
++ if (err) {
++ /* exit if the error returned was NOT -EROFS */
++ if (!IS_COPYUP_ERR(err))
++ goto out;
++ bstart--;
++ }
++
++ /* check if copyup's needed, and mkdir */
++ for (bindex = bstart; bindex >= 0; bindex--) {
++ int i;
++ int bend = dbend(dentry);
++
++ if (is_robranch_super(dentry->d_sb, bindex))
++ continue;
++
++ lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
++ if (!lower_dentry) {
++ lower_dentry = create_parents(dir, dentry,
++ dentry->d_name.name,
++ bindex);
++ if (!lower_dentry || IS_ERR(lower_dentry)) {
++ printk(KERN_ERR "unionfs: lower dentry "
++ " NULL for bindex = %d\n", bindex);
++ continue;
++ }
++ }
++
++ lower_parent_dentry = lock_parent(lower_dentry);
++
++ if (IS_ERR(lower_parent_dentry)) {
++ err = PTR_ERR(lower_parent_dentry);
++ goto out;
++ }
++
++ err = vfs_mkdir(lower_parent_dentry->d_inode, lower_dentry,
++ mode);
++
++ unlock_dir(lower_parent_dentry);
++
++ /* did the mkdir succeed? */
++ if (err)
++ break;
++
++ for (i = bindex + 1; i <= bend; i++) {
++ /* XXX: use path_put_lowers? */
++ if (unionfs_lower_dentry_idx(dentry, i)) {
++ dput(unionfs_lower_dentry_idx(dentry, i));
++ unionfs_set_lower_dentry_idx(dentry, i, NULL);
++ }
++ }
++ dbend(dentry) = bindex;
++
++ /*
++ * Only INTERPOSE_LOOKUP can return a value other than 0 on
++ * err.
++ */
++ err = PTR_ERR(unionfs_interpose(dentry, dir->i_sb, 0));
++ if (!err) {
++ unionfs_copy_attr_times(dir);
++ fsstack_copy_inode_size(dir,
++ lower_parent_dentry->d_inode);
++
++ /* update number of links on parent directory */
++ dir->i_nlink = unionfs_get_nlinks(dir);
++ }
++
++ err = make_dir_opaque(dentry, dbstart(dentry));
++ if (err) {
++ printk(KERN_ERR "unionfs: mkdir: error creating "
++ ".wh.__dir_opaque: %d\n", err);
++ goto out;
++ }
++
++ /* we are done! */
++ break;
++ }
++
++out:
++ if (!dentry->d_inode)
++ d_drop(dentry);
++
++ kfree(name);
++
++ if (!err) {
++ unionfs_copy_attr_times(dentry->d_inode);
++ unionfs_postcopyup_setmnt(dentry);
++ }
++ unionfs_check_inode(dir);
++ unionfs_check_dentry(dentry);
++ unionfs_unlock_dentry(dentry);
++ unionfs_unlock_parent(dentry, parent);
++ unionfs_read_unlock(dentry->d_sb);
++
++ return err;
++}
++
++static int unionfs_mknod(struct inode *dir, struct dentry *dentry, int mode,
++ dev_t dev)
++{
++ int err = 0;
++ struct dentry *lower_dentry = NULL;
++ struct dentry *wh_dentry = NULL;
++ struct dentry *lower_parent_dentry = NULL;
++ struct dentry *parent;
++ char *name = NULL;
++ int valid = 0;
++
++ unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD);
++ parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ valid = __unionfs_d_revalidate(dentry, parent, false);
++ if (unlikely(!valid)) {
++ err = -ESTALE;
++ goto out;
++ }
++
++ /*
++ * It's only a bug if this dentry was not negative and couldn't be
++ * revalidated (shouldn't happen).
++ */
++ BUG_ON(!valid && dentry->d_inode);
++
++ lower_dentry = find_writeable_branch(dir, dentry);
++ if (IS_ERR(lower_dentry)) {
++ err = PTR_ERR(lower_dentry);
++ goto out;
++ }
++
++ lower_parent_dentry = lock_parent(lower_dentry);
++ if (IS_ERR(lower_parent_dentry)) {
++ err = PTR_ERR(lower_parent_dentry);
++ goto out_unlock;
++ }
++
++ err = vfs_mknod(lower_parent_dentry->d_inode, lower_dentry, mode, dev);
++ if (!err) {
++ err = PTR_ERR(unionfs_interpose(dentry, dir->i_sb, 0));
++ if (!err) {
++ unionfs_copy_attr_times(dir);
++ fsstack_copy_inode_size(dir,
++ lower_parent_dentry->d_inode);
++ /* update no. of links on parent directory */
++ dir->i_nlink = unionfs_get_nlinks(dir);
++ }
++ }
++
++out_unlock:
++ unlock_dir(lower_parent_dentry);
++out:
++ dput(wh_dentry);
++ kfree(name);
++
++ if (!err) {
++ unionfs_postcopyup_setmnt(dentry);
++ unionfs_check_inode(dir);
++ unionfs_check_dentry(dentry);
++ }
++ unionfs_unlock_dentry(dentry);
++ unionfs_unlock_parent(dentry, parent);
++ unionfs_read_unlock(dentry->d_sb);
++ return err;
++}
++
++/* requires sb, dentry, and parent to already be locked */
++static int __unionfs_readlink(struct dentry *dentry, char __user *buf,
++ int bufsiz)
++{
++ int err;
++ struct dentry *lower_dentry;
++
++ lower_dentry = unionfs_lower_dentry(dentry);
++
++ if (!lower_dentry->d_inode->i_op ||
++ !lower_dentry->d_inode->i_op->readlink) {
++ err = -EINVAL;
++ goto out;
++ }
++
++ err = lower_dentry->d_inode->i_op->readlink(lower_dentry,
++ buf, bufsiz);
++ if (err >= 0)
++ fsstack_copy_attr_atime(dentry->d_inode,
++ lower_dentry->d_inode);
++
++out:
++ return err;
++}
++
++static int unionfs_readlink(struct dentry *dentry, char __user *buf,
++ int bufsiz)
++{
++ int err;
++ struct dentry *parent;
++
++ unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD);
++ parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ if (unlikely(!__unionfs_d_revalidate(dentry, parent, false))) {
++ err = -ESTALE;
++ goto out;
++ }
++
++ err = __unionfs_readlink(dentry, buf, bufsiz);
++
++out:
++ unionfs_check_dentry(dentry);
++ unionfs_unlock_dentry(dentry);
++ unionfs_unlock_parent(dentry, parent);
++ unionfs_read_unlock(dentry->d_sb);
++
++ return err;
++}
++
++static void *unionfs_follow_link(struct dentry *dentry, struct nameidata *nd)
++{
++ char *buf;
++ int len = PAGE_SIZE, err;
++ mm_segment_t old_fs;
++ struct dentry *parent;
++
++ unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD);
++ parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ /* This is freed by the put_link method assuming a successful call. */
++ buf = kmalloc(len, GFP_KERNEL);
++ if (unlikely(!buf)) {
++ err = -ENOMEM;
++ goto out;
++ }
++
++ /* read the symlink, and then we will follow it */
++ old_fs = get_fs();
++ set_fs(KERNEL_DS);
++ err = __unionfs_readlink(dentry, buf, len);
++ set_fs(old_fs);
++ if (err < 0) {
++ kfree(buf);
++ buf = NULL;
++ goto out;
++ }
++ buf[err] = 0;
++ nd_set_link(nd, buf);
++ err = 0;
++
++out:
++ if (err >= 0) {
++ unionfs_check_nd(nd);
++ unionfs_check_dentry(dentry);
++ }
++
++ unionfs_unlock_dentry(dentry);
++ unionfs_unlock_parent(dentry, parent);
++ unionfs_read_unlock(dentry->d_sb);
++
++ return ERR_PTR(err);
++}
++
++/* this @nd *IS* still used */
++static void unionfs_put_link(struct dentry *dentry, struct nameidata *nd,
++ void *cookie)
++{
++ struct dentry *parent;
++ char *buf;
++
++ unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD);
++ parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ if (unlikely(!__unionfs_d_revalidate(dentry, parent, false)))
++ printk(KERN_ERR
++ "unionfs: put_link failed to revalidate dentry\n");
++
++ unionfs_check_dentry(dentry);
++#if 0
++ /* XXX: can't run this check b/c this fxn can receive a poisoned 'nd' PTR */
++ unionfs_check_nd(nd);
++#endif
++ buf = nd_get_link(nd);
++ if (!IS_ERR(buf))
++ kfree(buf);
++ unionfs_unlock_dentry(dentry);
++ unionfs_unlock_parent(dentry, parent);
++ unionfs_read_unlock(dentry->d_sb);
++}
++
++/*
++ * This is a variant of fs/namei.c:permission() or inode_permission() which
++ * skips over EROFS tests (because we perform copyup on EROFS).
++ */
++static int __inode_permission(struct inode *inode, int mask, unsigned int flags)
++{
++ int retval;
++
++ /* nobody gets write access to an immutable file */
++ if ((mask & MAY_WRITE) && IS_IMMUTABLE(inode))
++ return -EACCES;
++
++ /* Ordinary permission routines do not understand MAY_APPEND. */
++ if (inode->i_op && inode->i_op->permission) {
++ retval = inode->i_op->permission(inode, mask, flags);
++ if (!retval) {
++ /*
++ * Exec permission on a regular file is denied if none
++ * of the execute bits are set.
++ *
++ * This check should be done by the ->permission()
++ * method.
++ */
++ if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode) &&
++ !(inode->i_mode & S_IXUGO))
++ return -EACCES;
++ }
++ } else {
++ retval = generic_permission(inode, mask, flags, NULL);
++ }
++ if (retval)
++ return retval;
++
++ return security_inode_permission(inode,
++ mask & (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND));
++}
++
++/*
++ * Don't grab the superblock read-lock in unionfs_permission, which prevents
++ * a deadlock with the branch-management "add branch" code (which grabbed
++ * the write lock). It is safe to not grab the read lock here, because even
++ * with branch management taking place, there is no chance that
++ * unionfs_permission, or anything it calls, will use stale branch
++ * information.
++ */
++static int unionfs_permission(struct inode *inode, int mask, unsigned int flags)
++{
++ struct inode *lower_inode = NULL;
++ int err = 0;
++ int bindex, bstart, bend;
++ int is_file;
++ const int write_mask = (mask & MAY_WRITE) && !(mask & MAY_READ);
++ struct inode *inode_grabbed;
++ struct dentry *dentry;
++
++ if (flags & IPERM_FLAG_RCU) {
++ err = -ECHILD;
++ goto out_nograb;
++ }
++
++ dentry = d_find_alias(inode);
++ if (dentry)
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ inode_grabbed = igrab(inode);
++ is_file = !S_ISDIR(inode->i_mode);
++
++ if (!UNIONFS_I(inode)->lower_inodes) {
++ if (is_file) /* dirs can be unlinked but chdir'ed to */
++ err = -ESTALE; /* force revalidate */
++ goto out;
++ }
++ bstart = ibstart(inode);
++ bend = ibend(inode);
++ if (unlikely(bstart < 0 || bend < 0)) {
++ /*
++ * With branch-management, we can get a stale inode here.
++ * If so, we return ESTALE back to link_path_walk, which
++ * would discard the dcache entry and re-lookup the
++ * dentry+inode. This should be equivalent to issuing
++ * __unionfs_d_revalidate_chain on nd.dentry here.
++ */
++ if (is_file) /* dirs can be unlinked but chdir'ed to */
++ err = -ESTALE; /* force revalidate */
++ goto out;
++ }
++
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ lower_inode = unionfs_lower_inode_idx(inode, bindex);
++ if (!lower_inode)
++ continue;
++
++ /*
++ * check the condition for D-F-D underlying files/directories,
++ * we don't have to check for files, if we are checking for
++ * directories.
++ */
++ if (!is_file && !S_ISDIR(lower_inode->i_mode))
++ continue;
++
++ /*
++ * We check basic permissions, but we ignore any conditions
++ * such as readonly file systems or branches marked as
++ * readonly, because those conditions should lead to a
++ * copyup taking place later on. However, if user never had
++ * access to the file, then no copyup could ever take place.
++ */
++ err = __inode_permission(lower_inode, mask, flags);
++ if (err && err != -EACCES && err != EPERM && bindex > 0) {
++ umode_t mode = lower_inode->i_mode;
++ if ((is_robranch_super(inode->i_sb, bindex) ||
++ __is_rdonly(lower_inode)) &&
++ (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
++ err = 0;
++ if (IS_COPYUP_ERR(err))
++ err = 0;
++ }
++
++ /*
++ * NFS HACK: NFSv2/3 return EACCES on readonly-exported,
++ * locally readonly-mounted file systems, instead of EROFS
++ * like other file systems do. So we have no choice here
++ * but to intercept this and ignore it for NFS branches
++ * marked readonly. Specifically, we avoid using NFS's own
++ * "broken" ->permission method, and rely on
++ * generic_permission() to do basic checking for us.
++ */
++ if (err && err == -EACCES &&
++ is_robranch_super(inode->i_sb, bindex) &&
++ lower_inode->i_sb->s_magic == NFS_SUPER_MAGIC)
++ err = generic_permission(lower_inode, mask, flags, NULL);
++
++ /*
++ * The permissions are an intersection of the overall directory
++ * permissions, so we fail if one fails.
++ */
++ if (err)
++ goto out;
++
++ /* only the leftmost file matters. */
++ if (is_file || write_mask) {
++ if (is_file && write_mask) {
++ err = get_write_access(lower_inode);
++ if (!err)
++ put_write_access(lower_inode);
++ }
++ break;
++ }
++ }
++ /* sync times which may have changed (asynchronously) below */
++ unionfs_copy_attr_times(inode);
++
++out:
++ unionfs_check_inode(inode);
++ if (dentry) {
++ unionfs_unlock_dentry(dentry);
++ dput(dentry);
++ }
++ iput(inode_grabbed);
++out_nograb:
++ return err;
++}
++
++static int unionfs_setattr(struct dentry *dentry, struct iattr *ia)
++{
++ int err = 0;
++ struct dentry *lower_dentry;
++ struct dentry *parent;
++ struct inode *inode;
++ struct inode *lower_inode;
++ int bstart, bend, bindex;
++ loff_t size;
++ struct iattr lower_ia;
++
++ /* check if user has permission to change inode */
++ err = inode_change_ok(dentry->d_inode, ia);
++ if (err)
++ goto out_err;
++
++ unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD);
++ parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ if (unlikely(!__unionfs_d_revalidate(dentry, parent, false))) {
++ err = -ESTALE;
++ goto out;
++ }
++
++ bstart = dbstart(dentry);
++ bend = dbend(dentry);
++ inode = dentry->d_inode;
++
++ /*
++ * mode change is for clearing setuid/setgid. Allow lower filesystem
++ * to reinterpret it in its own way.
++ */
++ if (ia->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID))
++ ia->ia_valid &= ~ATTR_MODE;
++
++ lower_dentry = unionfs_lower_dentry(dentry);
++ if (!lower_dentry) { /* should never happen after above revalidate */
++ err = -EINVAL;
++ goto out;
++ }
++
++ /*
++ * Get the lower inode directly from lower dentry, in case ibstart
++ * is -1 (which happens when the file is open but unlinked.
++ */
++ lower_inode = lower_dentry->d_inode;
++
++ /* check if user has permission to change lower inode */
++ err = inode_change_ok(lower_inode, ia);
++ if (err)
++ goto out;
++
++ /* copyup if the file is on a read only branch */
++ if (is_robranch_super(dentry->d_sb, bstart)
++ || __is_rdonly(lower_inode)) {
++ /* check if we have a branch to copy up to */
++ if (bstart <= 0) {
++ err = -EACCES;
++ goto out;
++ }
++
++ if (ia->ia_valid & ATTR_SIZE)
++ size = ia->ia_size;
++ else
++ size = i_size_read(inode);
++ /* copyup to next available branch */
++ for (bindex = bstart - 1; bindex >= 0; bindex--) {
++ err = copyup_dentry(parent->d_inode,
++ dentry, bstart, bindex,
++ dentry->d_name.name,
++ dentry->d_name.len,
++ NULL, size);
++ if (!err)
++ break;
++ }
++ if (err)
++ goto out;
++ /* get updated lower_dentry/inode after copyup */
++ lower_dentry = unionfs_lower_dentry(dentry);
++ lower_inode = unionfs_lower_inode(inode);
++ /*
++ * check for whiteouts in writeable branch, and remove them
++ * if necessary.
++ */
++ if (lower_dentry) {
++ err = check_unlink_whiteout(dentry, lower_dentry,
++ bindex);
++ if (err > 0) /* ignore if whiteout found and removed */
++ err = 0;
++ }
++ }
++
++ /*
++ * If shrinking, first truncate upper level to cancel writing dirty
++ * pages beyond the new eof; and also if its' maxbytes is more
++ * limiting (fail with -EFBIG before making any change to the lower
++ * level). There is no need to vmtruncate the upper level
++ * afterwards in the other cases: we fsstack_copy_inode_size from
++ * the lower level.
++ */
++ if (ia->ia_valid & ATTR_SIZE) {
++ size = i_size_read(inode);
++ if (ia->ia_size < size || (ia->ia_size > size &&
++ inode->i_sb->s_maxbytes < lower_inode->i_sb->s_maxbytes)) {
++ err = vmtruncate(inode, ia->ia_size);
++ if (err)
++ goto out;
++ }
++ }
++
++ /* notify the (possibly copied-up) lower inode */
++ /*
++ * Note: we use lower_dentry->d_inode, because lower_inode may be
++ * unlinked (no inode->i_sb and i_ino==0. This happens if someone
++ * tries to open(), unlink(), then ftruncate() a file.
++ */
++ /* prepare our own lower struct iattr (with our own lower file) */
++ memcpy(&lower_ia, ia, sizeof(lower_ia));
++ if (ia->ia_valid & ATTR_FILE) {
++ lower_ia.ia_file = unionfs_lower_file(ia->ia_file);
++ BUG_ON(!lower_ia.ia_file); // XXX?
++ }
++
++ mutex_lock(&lower_dentry->d_inode->i_mutex);
++ err = notify_change(lower_dentry, &lower_ia);
++ mutex_unlock(&lower_dentry->d_inode->i_mutex);
++ if (err)
++ goto out;
++
++ /* get attributes from the first lower inode */
++ if (ibstart(inode) >= 0)
++ unionfs_copy_attr_all(inode, lower_inode);
++ /*
++ * unionfs_copy_attr_all will copy the lower times to our inode if
++ * the lower ones are newer (useful for cache coherency). However,
++ * ->setattr is the only place in which we may have to copy the
++ * lower inode times absolutely, to support utimes(2).
++ */
++ if (ia->ia_valid & ATTR_MTIME_SET)
++ inode->i_mtime = lower_inode->i_mtime;
++ if (ia->ia_valid & ATTR_CTIME)
++ inode->i_ctime = lower_inode->i_ctime;
++ if (ia->ia_valid & ATTR_ATIME_SET)
++ inode->i_atime = lower_inode->i_atime;
++ fsstack_copy_inode_size(inode, lower_inode);
++
++out:
++ if (!err)
++ unionfs_check_dentry(dentry);
++ unionfs_unlock_dentry(dentry);
++ unionfs_unlock_parent(dentry, parent);
++ unionfs_read_unlock(dentry->d_sb);
++out_err:
++ return err;
++}
++
++struct inode_operations unionfs_symlink_iops = {
++ .readlink = unionfs_readlink,
++ .permission = unionfs_permission,
++ .follow_link = unionfs_follow_link,
++ .setattr = unionfs_setattr,
++ .put_link = unionfs_put_link,
++};
++
++struct inode_operations unionfs_dir_iops = {
++ .create = unionfs_create,
++ .lookup = unionfs_lookup,
++ .link = unionfs_link,
++ .unlink = unionfs_unlink,
++ .symlink = unionfs_symlink,
++ .mkdir = unionfs_mkdir,
++ .rmdir = unionfs_rmdir,
++ .mknod = unionfs_mknod,
++ .rename = unionfs_rename,
++ .permission = unionfs_permission,
++ .setattr = unionfs_setattr,
++#ifdef CONFIG_UNION_FS_XATTR
++ .setxattr = unionfs_setxattr,
++ .getxattr = unionfs_getxattr,
++ .removexattr = unionfs_removexattr,
++ .listxattr = unionfs_listxattr,
++#endif /* CONFIG_UNION_FS_XATTR */
++};
++
++struct inode_operations unionfs_main_iops = {
++ .permission = unionfs_permission,
++ .setattr = unionfs_setattr,
++#ifdef CONFIG_UNION_FS_XATTR
++ .setxattr = unionfs_setxattr,
++ .getxattr = unionfs_getxattr,
++ .removexattr = unionfs_removexattr,
++ .listxattr = unionfs_listxattr,
++#endif /* CONFIG_UNION_FS_XATTR */
++};
+diff --git a/fs/unionfs/lookup.c b/fs/unionfs/lookup.c
+new file mode 100644
+index 0000000..3cbde56
+--- /dev/null
++++ b/fs/unionfs/lookup.c
+@@ -0,0 +1,569 @@
++/*
++ * Copyright (c) 2003-2011 Erez Zadok
++ * Copyright (c) 2003-2006 Charles P. Wright
++ * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
++ * Copyright (c) 2005-2006 Junjiro Okajima
++ * Copyright (c) 2005 Arun M. Krishnakumar
++ * Copyright (c) 2004-2006 David P. Quigley
++ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
++ * Copyright (c) 2003 Puja Gupta
++ * Copyright (c) 2003 Harikesavan Krishnan
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 The Research Foundation of SUNY
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "union.h"
++
++/*
++ * Lookup one path component @name relative to a <base,mnt> path pair.
++ * Behaves nearly the same as lookup_one_len (i.e., return negative dentry
++ * on ENOENT), but uses the @mnt passed, so it can cross bind mounts and
++ * other lower mounts properly. If @new_mnt is non-null, will fill in the
++ * new mnt there. Caller is responsible to dput/mntput/path_put returned
++ * @dentry and @new_mnt.
++ */
++struct dentry *__lookup_one(struct dentry *base, struct vfsmount *mnt,
++ const char *name, struct vfsmount **new_mnt)
++{
++ struct dentry *dentry = NULL;
++ struct nameidata lower_nd;
++ int err;
++
++ /* we use flags=0 to get basic lookup */
++ err = vfs_path_lookup(base, mnt, name, 0, &lower_nd);
++
++ switch (err) {
++ case 0: /* no error */
++ dentry = lower_nd.path.dentry;
++ if (new_mnt)
++ *new_mnt = lower_nd.path.mnt; /* rc already inc'ed */
++ break;
++ case -ENOENT:
++ /*
++ * We don't consider ENOENT an error, and we want to return
++ * a negative dentry (ala lookup_one_len). As we know
++ * there was no inode for this name before (-ENOENT), then
++ * it's safe to call lookup_one_len (which doesn't take a
++ * vfsmount).
++ */
++ dentry = lookup_lck_len(name, base, strlen(name));
++ if (new_mnt)
++ *new_mnt = mntget(lower_nd.path.mnt);
++ break;
++ default: /* all other real errors */
++ dentry = ERR_PTR(err);
++ break;
++ }
++
++ return dentry;
++}
++
++/*
++ * This is a utility function that fills in a unionfs dentry.
++ * Caller must lock this dentry with unionfs_lock_dentry.
++ *
++ * Returns: 0 (ok), or -ERRNO if an error occurred.
++ * XXX: get rid of _partial_lookup and make callers call _lookup_full directly
++ */
++int unionfs_partial_lookup(struct dentry *dentry, struct dentry *parent)
++{
++ struct dentry *tmp;
++ int err = -ENOSYS;
++
++ tmp = unionfs_lookup_full(dentry, parent, INTERPOSE_PARTIAL);
++
++ if (!tmp) {
++ err = 0;
++ goto out;
++ }
++ if (IS_ERR(tmp)) {
++ err = PTR_ERR(tmp);
++ goto out;
++ }
++ /* XXX: need to change the interface */
++ BUG_ON(tmp != dentry);
++out:
++ return err;
++}
++
++/* The dentry cache is just so we have properly sized dentries. */
++static struct kmem_cache *unionfs_dentry_cachep;
++int unionfs_init_dentry_cache(void)
++{
++ unionfs_dentry_cachep =
++ kmem_cache_create("unionfs_dentry",
++ sizeof(struct unionfs_dentry_info),
++ 0, SLAB_RECLAIM_ACCOUNT, NULL);
++
++ return (unionfs_dentry_cachep ? 0 : -ENOMEM);
++}
++
++void unionfs_destroy_dentry_cache(void)
++{
++ if (unionfs_dentry_cachep)
++ kmem_cache_destroy(unionfs_dentry_cachep);
++}
++
++void free_dentry_private_data(struct dentry *dentry)
++{
++ if (!dentry || !dentry->d_fsdata)
++ return;
++ kfree(UNIONFS_D(dentry)->lower_paths);
++ UNIONFS_D(dentry)->lower_paths = NULL;
++ kmem_cache_free(unionfs_dentry_cachep, dentry->d_fsdata);
++ dentry->d_fsdata = NULL;
++}
++
++static inline int __realloc_dentry_private_data(struct dentry *dentry)
++{
++ struct unionfs_dentry_info *info = UNIONFS_D(dentry);
++ void *p;
++ int size;
++
++ BUG_ON(!info);
++
++ size = sizeof(struct path) * sbmax(dentry->d_sb);
++ p = krealloc(info->lower_paths, size, GFP_ATOMIC);
++ if (unlikely(!p))
++ return -ENOMEM;
++
++ info->lower_paths = p;
++
++ info->bstart = -1;
++ info->bend = -1;
++ info->bopaque = -1;
++ info->bcount = sbmax(dentry->d_sb);
++ atomic_set(&info->generation,
++ atomic_read(&UNIONFS_SB(dentry->d_sb)->generation));
++
++ memset(info->lower_paths, 0, size);
++
++ return 0;
++}
++
++/* UNIONFS_D(dentry)->lock must be locked */
++int realloc_dentry_private_data(struct dentry *dentry)
++{
++ if (!__realloc_dentry_private_data(dentry))
++ return 0;
++
++ kfree(UNIONFS_D(dentry)->lower_paths);
++ free_dentry_private_data(dentry);
++ return -ENOMEM;
++}
++
++/* allocate new dentry private data */
++int new_dentry_private_data(struct dentry *dentry, int subclass)
++{
++ struct unionfs_dentry_info *info = UNIONFS_D(dentry);
++
++ BUG_ON(info);
++
++ info = kmem_cache_alloc(unionfs_dentry_cachep, GFP_ATOMIC);
++ if (unlikely(!info))
++ return -ENOMEM;
++
++ mutex_init(&info->lock);
++ mutex_lock_nested(&info->lock, subclass);
++
++ info->lower_paths = NULL;
++
++ dentry->d_fsdata = info;
++
++ if (!__realloc_dentry_private_data(dentry))
++ return 0;
++
++ mutex_unlock(&info->lock);
++ free_dentry_private_data(dentry);
++ return -ENOMEM;
++}
++
++/*
++ * scan through the lower dentry objects, and set bstart to reflect the
++ * starting branch
++ */
++void update_bstart(struct dentry *dentry)
++{
++ int bindex;
++ int bstart = dbstart(dentry);
++ int bend = dbend(dentry);
++ struct dentry *lower_dentry;
++
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
++ if (!lower_dentry)
++ continue;
++ if (lower_dentry->d_inode) {
++ dbstart(dentry) = bindex;
++ break;
++ }
++ dput(lower_dentry);
++ unionfs_set_lower_dentry_idx(dentry, bindex, NULL);
++ }
++}
++
++
++/*
++ * Initialize a nameidata structure (the intent part) we can pass to a lower
++ * file system. Returns 0 on success or -error (only -ENOMEM possible).
++ * Inside that nd structure, this function may also return an allocated
++ * struct file (for open intents). The caller, when done with this nd, must
++ * kfree the intent file (using release_lower_nd).
++ *
++ * XXX: this code, and the callers of this code, should be redone using
++ * vfs_path_lookup() when (1) the nameidata structure is refactored into a
++ * separate intent-structure, and (2) open_namei() is broken into a VFS-only
++ * function and a method that other file systems can call.
++ */
++int init_lower_nd(struct nameidata *nd, unsigned int flags)
++{
++ int err = 0;
++#ifdef ALLOC_LOWER_ND_FILE
++ /*
++ * XXX: one day we may need to have the lower return an open file
++ * for us. It is not needed in 2.6.23-rc1 for nfs2/nfs3, but may
++ * very well be needed for nfs4.
++ */
++ struct file *file;
++#endif /* ALLOC_LOWER_ND_FILE */
++
++ memset(nd, 0, sizeof(struct nameidata));
++ if (!flags)
++ return err;
++
++ switch (flags) {
++ case LOOKUP_CREATE:
++ nd->intent.open.flags |= O_CREAT;
++ /* fall through: shared code for create/open cases */
++ case LOOKUP_OPEN:
++ nd->flags = flags;
++ nd->intent.open.flags |= (FMODE_READ | FMODE_WRITE);
++#ifdef ALLOC_LOWER_ND_FILE
++ file = kzalloc(sizeof(struct file), GFP_KERNEL);
++ if (unlikely(!file)) {
++ err = -ENOMEM;
++ break; /* exit switch statement and thus return */
++ }
++ nd->intent.open.file = file;
++#endif /* ALLOC_LOWER_ND_FILE */
++ break;
++ default:
++ /*
++ * We should never get here, for now.
++ * We can add new cases here later on.
++ */
++ pr_debug("unionfs: unknown nameidata flag 0x%x\n", flags);
++ BUG();
++ break;
++ }
++
++ return err;
++}
++
++void release_lower_nd(struct nameidata *nd, int err)
++{
++ if (!nd->intent.open.file)
++ return;
++ else if (!err)
++ release_open_intent(nd);
++#ifdef ALLOC_LOWER_ND_FILE
++ kfree(nd->intent.open.file);
++#endif /* ALLOC_LOWER_ND_FILE */
++}
++
++/*
++ * Main (and complex) driver function for Unionfs's lookup
++ *
++ * Returns: NULL (ok), ERR_PTR if an error occurred, or a non-null non-error
++ * PTR if d_splice returned a different dentry.
++ *
++ * If lookupmode is INTERPOSE_PARTIAL/REVAL/REVAL_NEG, the passed dentry's
++ * inode info must be locked. If lookupmode is INTERPOSE_LOOKUP (i.e., a
++ * newly looked-up dentry), then unionfs_lookup_backend will return a locked
++ * dentry's info, which the caller must unlock.
++ */
++struct dentry *unionfs_lookup_full(struct dentry *dentry,
++ struct dentry *parent, int lookupmode)
++{
++ int err = 0;
++ struct dentry *lower_dentry = NULL;
++ struct vfsmount *lower_mnt;
++ struct vfsmount *lower_dir_mnt;
++ struct dentry *wh_lower_dentry = NULL;
++ struct dentry *lower_dir_dentry = NULL;
++ struct dentry *d_interposed = NULL;
++ int bindex, bstart, bend, bopaque;
++ int opaque, num_positive = 0;
++ const char *name;
++ int namelen;
++ int pos_start, pos_end;
++
++ /*
++ * We should already have a lock on this dentry in the case of a
++ * partial lookup, or a revalidation. Otherwise it is returned from
++ * new_dentry_private_data already locked.
++ */
++ verify_locked(dentry);
++ verify_locked(parent);
++
++ /* must initialize dentry operations */
++ dentry->d_op = &unionfs_dops;
++
++ /* We never partial lookup the root directory. */
++ if (IS_ROOT(dentry))
++ goto out;
++
++ name = dentry->d_name.name;
++ namelen = dentry->d_name.len;
++
++ /* No dentries should get created for possible whiteout names. */
++ if (!is_validname(name)) {
++ err = -EPERM;
++ goto out_free;
++ }
++
++ /* Now start the actual lookup procedure. */
++ bstart = dbstart(parent);
++ bend = dbend(parent);
++ bopaque = dbopaque(parent);
++ BUG_ON(bstart < 0);
++
++ /* adjust bend to bopaque if needed */
++ if ((bopaque >= 0) && (bopaque < bend))
++ bend = bopaque;
++
++ /* lookup all possible dentries */
++ for (bindex = bstart; bindex <= bend; bindex++) {
++
++ lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
++ lower_mnt = unionfs_lower_mnt_idx(dentry, bindex);
++
++ /* skip if we already have a positive lower dentry */
++ if (lower_dentry) {
++ if (dbstart(dentry) < 0)
++ dbstart(dentry) = bindex;
++ if (bindex > dbend(dentry))
++ dbend(dentry) = bindex;
++ if (lower_dentry->d_inode)
++ num_positive++;
++ continue;
++ }
++
++ lower_dir_dentry =
++ unionfs_lower_dentry_idx(parent, bindex);
++ /* if the lower dentry's parent does not exist, skip this */
++ if (!lower_dir_dentry || !lower_dir_dentry->d_inode)
++ continue;
++
++ /* also skip it if the parent isn't a directory. */
++ if (!S_ISDIR(lower_dir_dentry->d_inode->i_mode))
++ continue; /* XXX: should be BUG_ON */
++
++ /* check for whiteouts: stop lookup if found */
++ wh_lower_dentry = lookup_whiteout(name, lower_dir_dentry);
++ if (IS_ERR(wh_lower_dentry)) {
++ err = PTR_ERR(wh_lower_dentry);
++ goto out_free;
++ }
++ if (wh_lower_dentry->d_inode) {
++ dbend(dentry) = dbopaque(dentry) = bindex;
++ if (dbstart(dentry) < 0)
++ dbstart(dentry) = bindex;
++ dput(wh_lower_dentry);
++ break;
++ }
++ dput(wh_lower_dentry);
++
++ /* Now do regular lookup; lookup @name */
++ lower_dir_mnt = unionfs_lower_mnt_idx(parent, bindex);
++ lower_mnt = NULL; /* XXX: needed? */
++
++ lower_dentry = __lookup_one(lower_dir_dentry, lower_dir_mnt,
++ name, &lower_mnt);
++
++ if (IS_ERR(lower_dentry)) {
++ err = PTR_ERR(lower_dentry);
++ goto out_free;
++ }
++ unionfs_set_lower_dentry_idx(dentry, bindex, lower_dentry);
++ if (!lower_mnt)
++ lower_mnt = unionfs_mntget(dentry->d_sb->s_root,
++ bindex);
++ unionfs_set_lower_mnt_idx(dentry, bindex, lower_mnt);
++
++ /* adjust dbstart/end */
++ if (dbstart(dentry) < 0)
++ dbstart(dentry) = bindex;
++ if (bindex > dbend(dentry))
++ dbend(dentry) = bindex;
++ /*
++ * We always store the lower dentries above, and update
++ * dbstart/dbend, even if the whole unionfs dentry is
++ * negative (i.e., no lower inodes).
++ */
++ if (!lower_dentry->d_inode)
++ continue;
++ num_positive++;
++
++ /*
++ * check if we just found an opaque directory, if so, stop
++ * lookups here.
++ */
++ if (!S_ISDIR(lower_dentry->d_inode->i_mode))
++ continue;
++ opaque = is_opaque_dir(dentry, bindex);
++ if (opaque < 0) {
++ err = opaque;
++ goto out_free;
++ } else if (opaque) {
++ dbend(dentry) = dbopaque(dentry) = bindex;
++ break;
++ }
++ dbend(dentry) = bindex;
++
++ /* update parent directory's atime with the bindex */
++ fsstack_copy_attr_atime(parent->d_inode,
++ lower_dir_dentry->d_inode);
++ }
++
++ /* sanity checks, then decide if to process a negative dentry */
++ BUG_ON(dbstart(dentry) < 0 && dbend(dentry) >= 0);
++ BUG_ON(dbstart(dentry) >= 0 && dbend(dentry) < 0);
++
++ if (num_positive > 0)
++ goto out_positive;
++
++ /*** handle NEGATIVE dentries ***/
++
++ /*
++ * If negative, keep only first lower negative dentry, to save on
++ * memory.
++ */
++ if (dbstart(dentry) < dbend(dentry)) {
++ path_put_lowers(dentry, dbstart(dentry) + 1,
++ dbend(dentry), false);
++ dbend(dentry) = dbstart(dentry);
++ }
++ if (lookupmode == INTERPOSE_PARTIAL)
++ goto out;
++ if (lookupmode == INTERPOSE_LOOKUP) {
++ /*
++ * If all we found was a whiteout in the first available
++ * branch, then create a negative dentry for a possibly new
++ * file to be created.
++ */
++ if (dbopaque(dentry) < 0)
++ goto out;
++ /* XXX: need to get mnt here */
++ bindex = dbstart(dentry);
++ if (unionfs_lower_dentry_idx(dentry, bindex))
++ goto out;
++ lower_dir_dentry =
++ unionfs_lower_dentry_idx(parent, bindex);
++ if (!lower_dir_dentry || !lower_dir_dentry->d_inode)
++ goto out;
++ if (!S_ISDIR(lower_dir_dentry->d_inode->i_mode))
++ goto out; /* XXX: should be BUG_ON */
++ /* XXX: do we need to cross bind mounts here? */
++ lower_dentry = lookup_lck_len(name, lower_dir_dentry, namelen);
++ if (IS_ERR(lower_dentry)) {
++ err = PTR_ERR(lower_dentry);
++ goto out;
++ }
++ /* XXX: need to mntget/mntput as needed too! */
++ unionfs_set_lower_dentry_idx(dentry, bindex, lower_dentry);
++ /* XXX: wrong mnt for crossing bind mounts! */
++ lower_mnt = unionfs_mntget(dentry->d_sb->s_root, bindex);
++ unionfs_set_lower_mnt_idx(dentry, bindex, lower_mnt);
++
++ goto out;
++ }
++
++ /* if we're revalidating a positive dentry, don't make it negative */
++ if (lookupmode != INTERPOSE_REVAL)
++ d_add(dentry, NULL);
++
++ goto out;
++
++out_positive:
++ /*** handle POSITIVE dentries ***/
++
++ /*
++ * This unionfs dentry is positive (at least one lower inode
++ * exists), so scan entire dentry from beginning to end, and remove
++ * any negative lower dentries, if any. Then, update dbstart/dbend
++ * to reflect the start/end of positive dentries.
++ */
++ pos_start = pos_end = -1;
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ lower_dentry = unionfs_lower_dentry_idx(dentry,
++ bindex);
++ if (lower_dentry && lower_dentry->d_inode) {
++ if (pos_start < 0)
++ pos_start = bindex;
++ if (bindex > pos_end)
++ pos_end = bindex;
++ continue;
++ }
++ path_put_lowers(dentry, bindex, bindex, false);
++ }
++ if (pos_start >= 0)
++ dbstart(dentry) = pos_start;
++ if (pos_end >= 0)
++ dbend(dentry) = pos_end;
++
++ /* Partial lookups need to re-interpose, or throw away older negs. */
++ if (lookupmode == INTERPOSE_PARTIAL) {
++ if (dentry->d_inode) {
++ unionfs_reinterpose(dentry);
++ goto out;
++ }
++
++ /*
++ * This dentry was positive, so it is as if we had a
++ * negative revalidation.
++ */
++ lookupmode = INTERPOSE_REVAL_NEG;
++ update_bstart(dentry);
++ }
++
++ /*
++ * Interpose can return a dentry if d_splice returned a different
++ * dentry.
++ */
++ d_interposed = unionfs_interpose(dentry, dentry->d_sb, lookupmode);
++ if (IS_ERR(d_interposed))
++ err = PTR_ERR(d_interposed);
++ else if (d_interposed)
++ dentry = d_interposed;
++
++ if (!err)
++ goto out;
++ d_drop(dentry);
++
++out_free:
++ /* should dput/mntput all the underlying dentries on error condition */
++ if (dbstart(dentry) >= 0)
++ path_put_lowers_all(dentry, false);
++ /* free lower_paths unconditionally */
++ kfree(UNIONFS_D(dentry)->lower_paths);
++ UNIONFS_D(dentry)->lower_paths = NULL;
++
++out:
++ if (dentry && UNIONFS_D(dentry)) {
++ BUG_ON(dbstart(dentry) < 0 && dbend(dentry) >= 0);
++ BUG_ON(dbstart(dentry) >= 0 && dbend(dentry) < 0);
++ }
++ if (d_interposed && UNIONFS_D(d_interposed)) {
++ BUG_ON(dbstart(d_interposed) < 0 && dbend(d_interposed) >= 0);
++ BUG_ON(dbstart(d_interposed) >= 0 && dbend(d_interposed) < 0);
++ }
++
++ if (!err && d_interposed)
++ return d_interposed;
++ return ERR_PTR(err);
++}
+diff --git a/fs/unionfs/main.c b/fs/unionfs/main.c
+new file mode 100644
+index 0000000..fa52f61
+--- /dev/null
++++ b/fs/unionfs/main.c
+@@ -0,0 +1,763 @@
++/*
++ * Copyright (c) 2003-2011 Erez Zadok
++ * Copyright (c) 2003-2006 Charles P. Wright
++ * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
++ * Copyright (c) 2005-2006 Junjiro Okajima
++ * Copyright (c) 2005 Arun M. Krishnakumar
++ * Copyright (c) 2004-2006 David P. Quigley
++ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
++ * Copyright (c) 2003 Puja Gupta
++ * Copyright (c) 2003 Harikesavan Krishnan
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 The Research Foundation of SUNY
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "union.h"
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++
++static void unionfs_fill_inode(struct dentry *dentry,
++ struct inode *inode)
++{
++ struct inode *lower_inode;
++ struct dentry *lower_dentry;
++ int bindex, bstart, bend;
++
++ bstart = dbstart(dentry);
++ bend = dbend(dentry);
++
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
++ if (!lower_dentry) {
++ unionfs_set_lower_inode_idx(inode, bindex, NULL);
++ continue;
++ }
++
++ /* Initialize the lower inode to the new lower inode. */
++ if (!lower_dentry->d_inode)
++ continue;
++
++ unionfs_set_lower_inode_idx(inode, bindex,
++ igrab(lower_dentry->d_inode));
++ }
++
++ ibstart(inode) = dbstart(dentry);
++ ibend(inode) = dbend(dentry);
++
++ /* Use attributes from the first branch. */
++ lower_inode = unionfs_lower_inode(inode);
++
++ /* Use different set of inode ops for symlinks & directories */
++ if (S_ISLNK(lower_inode->i_mode))
++ inode->i_op = &unionfs_symlink_iops;
++ else if (S_ISDIR(lower_inode->i_mode))
++ inode->i_op = &unionfs_dir_iops;
++
++ /* Use different set of file ops for directories */
++ if (S_ISDIR(lower_inode->i_mode))
++ inode->i_fop = &unionfs_dir_fops;
++
++ /* properly initialize special inodes */
++ if (S_ISBLK(lower_inode->i_mode) || S_ISCHR(lower_inode->i_mode) ||
++ S_ISFIFO(lower_inode->i_mode) || S_ISSOCK(lower_inode->i_mode))
++ init_special_inode(inode, lower_inode->i_mode,
++ lower_inode->i_rdev);
++
++ /* all well, copy inode attributes */
++ unionfs_copy_attr_all(inode, lower_inode);
++ fsstack_copy_inode_size(inode, lower_inode);
++}
++
++/*
++ * Connect a unionfs inode dentry/inode with several lower ones. This is
++ * the classic stackable file system "vnode interposition" action.
++ *
++ * @sb: unionfs's super_block
++ */
++struct dentry *unionfs_interpose(struct dentry *dentry, struct super_block *sb,
++ int flag)
++{
++ int err = 0;
++ struct inode *inode;
++ int need_fill_inode = 1;
++ struct dentry *spliced = NULL;
++
++ verify_locked(dentry);
++
++ /*
++ * We allocate our new inode below by calling unionfs_iget,
++ * which will initialize some of the new inode's fields
++ */
++
++ /*
++ * On revalidate we've already got our own inode and just need
++ * to fix it up.
++ */
++ if (flag == INTERPOSE_REVAL) {
++ inode = dentry->d_inode;
++ UNIONFS_I(inode)->bstart = -1;
++ UNIONFS_I(inode)->bend = -1;
++ atomic_set(&UNIONFS_I(inode)->generation,
++ atomic_read(&UNIONFS_SB(sb)->generation));
++
++ UNIONFS_I(inode)->lower_inodes =
++ kcalloc(sbmax(sb), sizeof(struct inode *), GFP_KERNEL);
++ if (unlikely(!UNIONFS_I(inode)->lower_inodes)) {
++ err = -ENOMEM;
++ goto out;
++ }
++ } else {
++ /* get unique inode number for unionfs */
++ inode = unionfs_iget(sb, iunique(sb, UNIONFS_ROOT_INO));
++ if (IS_ERR(inode)) {
++ err = PTR_ERR(inode);
++ goto out;
++ }
++ if (atomic_read(&inode->i_count) > 1)
++ goto skip;
++ }
++
++ need_fill_inode = 0;
++ unionfs_fill_inode(dentry, inode);
++
++skip:
++ /* only (our) lookup wants to do a d_add */
++ switch (flag) {
++ case INTERPOSE_DEFAULT:
++ /* for operations which create new inodes */
++ d_add(dentry, inode);
++ break;
++ case INTERPOSE_REVAL_NEG:
++ d_instantiate(dentry, inode);
++ break;
++ case INTERPOSE_LOOKUP:
++ spliced = d_splice_alias(inode, dentry);
++ if (spliced && spliced != dentry) {
++ /*
++ * d_splice can return a dentry if it was
++ * disconnected and had to be moved. We must ensure
++ * that the private data of the new dentry is
++ * correct and that the inode info was filled
++ * properly. Finally we must return this new
++ * dentry.
++ */
++ spliced->d_op = &unionfs_dops;
++ spliced->d_fsdata = dentry->d_fsdata;
++ dentry->d_fsdata = NULL;
++ dentry = spliced;
++ if (need_fill_inode) {
++ need_fill_inode = 0;
++ unionfs_fill_inode(dentry, inode);
++ }
++ goto out_spliced;
++ } else if (!spliced) {
++ if (need_fill_inode) {
++ need_fill_inode = 0;
++ unionfs_fill_inode(dentry, inode);
++ goto out_spliced;
++ }
++ }
++ break;
++ case INTERPOSE_REVAL:
++ /* Do nothing. */
++ break;
++ default:
++ printk(KERN_CRIT "unionfs: invalid interpose flag passed!\n");
++ BUG();
++ }
++ goto out;
++
++out_spliced:
++ if (!err)
++ return spliced;
++out:
++ return ERR_PTR(err);
++}
++
++/* like interpose above, but for an already existing dentry */
++void unionfs_reinterpose(struct dentry *dentry)
++{
++ struct dentry *lower_dentry;
++ struct inode *inode;
++ int bindex, bstart, bend;
++
++ verify_locked(dentry);
++
++ /* This is pre-allocated inode */
++ inode = dentry->d_inode;
++
++ bstart = dbstart(dentry);
++ bend = dbend(dentry);
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
++ if (!lower_dentry)
++ continue;
++
++ if (!lower_dentry->d_inode)
++ continue;
++ if (unionfs_lower_inode_idx(inode, bindex))
++ continue;
++ unionfs_set_lower_inode_idx(inode, bindex,
++ igrab(lower_dentry->d_inode));
++ }
++ ibstart(inode) = dbstart(dentry);
++ ibend(inode) = dbend(dentry);
++}
++
++/*
++ * make sure the branch we just looked up (nd) makes sense:
++ *
++ * 1) we're not trying to stack unionfs on top of unionfs
++ * 2) it exists
++ * 3) is a directory
++ */
++int check_branch(const struct path *path)
++{
++ /* XXX: remove in ODF code -- stacking unions allowed there */
++ if (!strcmp(path->dentry->d_sb->s_type->name, UNIONFS_NAME))
++ return -EINVAL;
++ if (!path->dentry->d_inode)
++ return -ENOENT;
++ if (!S_ISDIR(path->dentry->d_inode->i_mode))
++ return -ENOTDIR;
++ return 0;
++}
++
++/* checks if two lower_dentries have overlapping branches */
++static int is_branch_overlap(struct dentry *dent1, struct dentry *dent2)
++{
++ struct dentry *dent = NULL;
++
++ dent = dent1;
++ while ((dent != dent2) && (dent->d_parent != dent))
++ dent = dent->d_parent;
++
++ if (dent == dent2)
++ return 1;
++
++ dent = dent2;
++ while ((dent != dent1) && (dent->d_parent != dent))
++ dent = dent->d_parent;
++
++ return (dent == dent1);
++}
++
++/*
++ * Parse "ro" or "rw" options, but default to "rw" if no mode options was
++ * specified. Fill the mode bits in @perms. If encounter an unknown
++ * string, return -EINVAL. Otherwise return 0.
++ */
++int parse_branch_mode(const char *name, int *perms)
++{
++ if (!name || !strcmp(name, "rw")) {
++ *perms = MAY_READ | MAY_WRITE;
++ return 0;
++ }
++ if (!strcmp(name, "ro")) {
++ *perms = MAY_READ;
++ return 0;
++ }
++ return -EINVAL;
++}
++
++/*
++ * parse the dirs= mount argument
++ *
++ * We don't need to lock the superblock private data's rwsem, as we get
++ * called only by unionfs_read_super - it is still a long time before anyone
++ * can even get a reference to us.
++ */
++static int parse_dirs_option(struct super_block *sb, struct unionfs_dentry_info
++ *lower_root_info, char *options)
++{
++ struct path path;
++ char *name;
++ int err = 0;
++ int branches = 1;
++ int bindex = 0;
++ int i = 0;
++ int j = 0;
++ struct dentry *dent1;
++ struct dentry *dent2;
++
++ if (options[0] == '\0') {
++ printk(KERN_ERR "unionfs: no branches specified\n");
++ err = -EINVAL;
++ goto out_return;
++ }
++
++ /*
++ * Each colon means we have a separator, this is really just a rough
++ * guess, since strsep will handle empty fields for us.
++ */
++ for (i = 0; options[i]; i++)
++ if (options[i] == ':')
++ branches++;
++
++ /* allocate space for underlying pointers to lower dentry */
++ UNIONFS_SB(sb)->data =
++ kcalloc(branches, sizeof(struct unionfs_data), GFP_KERNEL);
++ if (unlikely(!UNIONFS_SB(sb)->data)) {
++ err = -ENOMEM;
++ goto out_return;
++ }
++
++ lower_root_info->lower_paths =
++ kcalloc(branches, sizeof(struct path), GFP_KERNEL);
++ if (unlikely(!lower_root_info->lower_paths)) {
++ err = -ENOMEM;
++ /* free the underlying pointer array */
++ kfree(UNIONFS_SB(sb)->data);
++ UNIONFS_SB(sb)->data = NULL;
++ goto out_return;
++ }
++
++ /* now parsing a string such as "b1:b2=rw:b3=ro:b4" */
++ branches = 0;
++ while ((name = strsep(&options, ":")) != NULL) {
++ int perms;
++ char *mode = strchr(name, '=');
++
++ if (!name)
++ continue;
++ if (!*name) { /* bad use of ':' (extra colons) */
++ err = -EINVAL;
++ goto out;
++ }
++
++ branches++;
++
++ /* strip off '=' if any */
++ if (mode)
++ *mode++ = '\0';
++
++ err = parse_branch_mode(mode, &perms);
++ if (err) {
++ printk(KERN_ERR "unionfs: invalid mode \"%s\" for "
++ "branch %d\n", mode, bindex);
++ goto out;
++ }
++ /* ensure that leftmost branch is writeable */
++ if (!bindex && !(perms & MAY_WRITE)) {
++ printk(KERN_ERR "unionfs: leftmost branch cannot be "
++ "read-only (use \"-o ro\" to create a "
++ "read-only union)\n");
++ err = -EINVAL;
++ goto out;
++ }
++
++ err = kern_path(name, LOOKUP_FOLLOW, &path);
++ if (err) {
++ printk(KERN_ERR "unionfs: error accessing "
++ "lower directory '%s' (error %d)\n",
++ name, err);
++ goto out;
++ }
++
++ err = check_branch(&path);
++ if (err) {
++ printk(KERN_ERR "unionfs: lower directory "
++ "'%s' is not a valid branch\n", name);
++ path_put(&path);
++ goto out;
++ }
++
++ lower_root_info->lower_paths[bindex].dentry = path.dentry;
++ lower_root_info->lower_paths[bindex].mnt = path.mnt;
++
++ set_branchperms(sb, bindex, perms);
++ set_branch_count(sb, bindex, 0);
++ new_branch_id(sb, bindex);
++
++ if (lower_root_info->bstart < 0)
++ lower_root_info->bstart = bindex;
++ lower_root_info->bend = bindex;
++ bindex++;
++ }
++
++ if (branches == 0) {
++ printk(KERN_ERR "unionfs: no branches specified\n");
++ err = -EINVAL;
++ goto out;
++ }
++
++ BUG_ON(branches != (lower_root_info->bend + 1));
++
++ /*
++ * Ensure that no overlaps exist in the branches.
++ *
++ * This test is required because the Linux kernel has no support
++ * currently for ensuring coherency between stackable layers and
++ * branches. If we were to allow overlapping branches, it would be
++ * possible, for example, to delete a file via one branch, which
++ * would not be reflected in another branch. Such incoherency could
++ * lead to inconsistencies and even kernel oopses. Rather than
++ * implement hacks to work around some of these cache-coherency
++ * problems, we prevent branch overlapping, for now. A complete
++ * solution will involve proper kernel/VFS support for cache
++ * coherency, at which time we could safely remove this
++ * branch-overlapping test.
++ */
++ for (i = 0; i < branches; i++) {
++ dent1 = lower_root_info->lower_paths[i].dentry;
++ for (j = i + 1; j < branches; j++) {
++ dent2 = lower_root_info->lower_paths[j].dentry;
++ if (is_branch_overlap(dent1, dent2)) {
++ printk(KERN_ERR "unionfs: branches %d and "
++ "%d overlap\n", i, j);
++ err = -EINVAL;
++ goto out;
++ }
++ }
++ }
++
++out:
++ if (err) {
++ for (i = 0; i < branches; i++)
++ path_put(&lower_root_info->lower_paths[i]);
++
++ kfree(lower_root_info->lower_paths);
++ kfree(UNIONFS_SB(sb)->data);
++
++ /*
++ * MUST clear the pointers to prevent potential double free if
++ * the caller dies later on
++ */
++ lower_root_info->lower_paths = NULL;
++ UNIONFS_SB(sb)->data = NULL;
++ }
++out_return:
++ return err;
++}
++
++/*
++ * Parse mount options. See the manual page for usage instructions.
++ *
++ * Returns the dentry object of the lower-level (lower) directory;
++ * We want to mount our stackable file system on top of that lower directory.
++ */
++static struct unionfs_dentry_info *unionfs_parse_options(
++ struct super_block *sb,
++ char *options)
++{
++ struct unionfs_dentry_info *lower_root_info;
++ char *optname;
++ int err = 0;
++ int bindex;
++ int dirsfound = 0;
++
++ /* allocate private data area */
++ err = -ENOMEM;
++ lower_root_info =
++ kzalloc(sizeof(struct unionfs_dentry_info), GFP_KERNEL);
++ if (unlikely(!lower_root_info))
++ goto out_error;
++ lower_root_info->bstart = -1;
++ lower_root_info->bend = -1;
++ lower_root_info->bopaque = -1;
++
++ while ((optname = strsep(&options, ",")) != NULL) {
++ char *optarg;
++
++ if (!optname || !*optname)
++ continue;
++
++ optarg = strchr(optname, '=');
++ if (optarg)
++ *optarg++ = '\0';
++
++ /*
++ * All of our options take an argument now. Insert ones that
++ * don't, above this check.
++ */
++ if (!optarg) {
++ printk(KERN_ERR "unionfs: %s requires an argument\n",
++ optname);
++ err = -EINVAL;
++ goto out_error;
++ }
++
++ if (!strcmp("dirs", optname)) {
++ if (++dirsfound > 1) {
++ printk(KERN_ERR
++ "unionfs: multiple dirs specified\n");
++ err = -EINVAL;
++ goto out_error;
++ }
++ err = parse_dirs_option(sb, lower_root_info, optarg);
++ if (err)
++ goto out_error;
++ continue;
++ }
++
++ err = -EINVAL;
++ printk(KERN_ERR
++ "unionfs: unrecognized option '%s'\n", optname);
++ goto out_error;
++ }
++ if (dirsfound != 1) {
++ printk(KERN_ERR "unionfs: dirs option required\n");
++ err = -EINVAL;
++ goto out_error;
++ }
++ goto out;
++
++out_error:
++ if (lower_root_info && lower_root_info->lower_paths) {
++ for (bindex = lower_root_info->bstart;
++ bindex >= 0 && bindex <= lower_root_info->bend;
++ bindex++)
++ path_put(&lower_root_info->lower_paths[bindex]);
++ }
++
++ kfree(lower_root_info->lower_paths);
++ kfree(lower_root_info);
++
++ kfree(UNIONFS_SB(sb)->data);
++ UNIONFS_SB(sb)->data = NULL;
++
++ lower_root_info = ERR_PTR(err);
++out:
++ return lower_root_info;
++}
++
++/*
++ * our custom d_alloc_root work-alike
++ *
++ * we can't use d_alloc_root if we want to use our own interpose function
++ * unchanged, so we simply call our own "fake" d_alloc_root
++ */
++static struct dentry *unionfs_d_alloc_root(struct super_block *sb)
++{
++ struct dentry *ret = NULL;
++
++ if (sb) {
++ static const struct qstr name = {
++ .name = "/",
++ .len = 1
++ };
++
++ ret = d_alloc(NULL, &name);
++ if (likely(ret)) {
++ ret->d_op = &unionfs_dops;
++ ret->d_sb = sb;
++ ret->d_parent = ret;
++ }
++ }
++ return ret;
++}
++
++/*
++ * There is no need to lock the unionfs_super_info's rwsem as there is no
++ * way anyone can have a reference to the superblock at this point in time.
++ */
++static int unionfs_read_super(struct super_block *sb, void *raw_data,
++ int silent)
++{
++ int err = 0;
++ struct unionfs_dentry_info *lower_root_info = NULL;
++ int bindex, bstart, bend;
++
++ if (!raw_data) {
++ printk(KERN_ERR
++ "unionfs: read_super: missing data argument\n");
++ err = -EINVAL;
++ goto out;
++ }
++
++ /* Allocate superblock private data */
++ sb->s_fs_info = kzalloc(sizeof(struct unionfs_sb_info), GFP_KERNEL);
++ if (unlikely(!UNIONFS_SB(sb))) {
++ printk(KERN_CRIT "unionfs: read_super: out of memory\n");
++ err = -ENOMEM;
++ goto out;
++ }
++
++ UNIONFS_SB(sb)->bend = -1;
++ atomic_set(&UNIONFS_SB(sb)->generation, 1);
++ init_rwsem(&UNIONFS_SB(sb)->rwsem);
++ UNIONFS_SB(sb)->high_branch_id = -1; /* -1 == invalid branch ID */
++
++ lower_root_info = unionfs_parse_options(sb, raw_data);
++ if (IS_ERR(lower_root_info)) {
++ printk(KERN_ERR
++ "unionfs: read_super: error while parsing options "
++ "(err = %ld)\n", PTR_ERR(lower_root_info));
++ err = PTR_ERR(lower_root_info);
++ lower_root_info = NULL;
++ goto out_free;
++ }
++ if (lower_root_info->bstart == -1) {
++ err = -ENOENT;
++ goto out_free;
++ }
++
++ /* set the lower superblock field of upper superblock */
++ bstart = lower_root_info->bstart;
++ BUG_ON(bstart != 0);
++ sbend(sb) = bend = lower_root_info->bend;
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ struct dentry *d = lower_root_info->lower_paths[bindex].dentry;
++ atomic_inc(&d->d_sb->s_active);
++ unionfs_set_lower_super_idx(sb, bindex, d->d_sb);
++ }
++
++ /* max Bytes is the maximum bytes from highest priority branch */
++ sb->s_maxbytes = unionfs_lower_super_idx(sb, 0)->s_maxbytes;
++
++ /*
++ * Our c/m/atime granularity is 1 ns because we may stack on file
++ * systems whose granularity is as good. This is important for our
++ * time-based cache coherency.
++ */
++ sb->s_time_gran = 1;
++
++ sb->s_op = &unionfs_sops;
++
++ /* See comment next to the definition of unionfs_d_alloc_root */
++ sb->s_root = unionfs_d_alloc_root(sb);
++ if (unlikely(!sb->s_root)) {
++ err = -ENOMEM;
++ goto out_dput;
++ }
++
++ /* link the upper and lower dentries */
++ sb->s_root->d_fsdata = NULL;
++ err = new_dentry_private_data(sb->s_root, UNIONFS_DMUTEX_ROOT);
++ if (unlikely(err))
++ goto out_freedpd;
++
++ /* Set the lower dentries for s_root */
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ struct dentry *d;
++ struct vfsmount *m;
++
++ d = lower_root_info->lower_paths[bindex].dentry;
++ m = lower_root_info->lower_paths[bindex].mnt;
++
++ unionfs_set_lower_dentry_idx(sb->s_root, bindex, d);
++ unionfs_set_lower_mnt_idx(sb->s_root, bindex, m);
++ }
++ dbstart(sb->s_root) = bstart;
++ dbend(sb->s_root) = bend;
++
++ /* Set the generation number to one, since this is for the mount. */
++ atomic_set(&UNIONFS_D(sb->s_root)->generation, 1);
++
++ /*
++ * Call interpose to create the upper level inode. Only
++ * INTERPOSE_LOOKUP can return a value other than 0 on err.
++ */
++ err = PTR_ERR(unionfs_interpose(sb->s_root, sb, 0));
++ unionfs_unlock_dentry(sb->s_root);
++ if (!err)
++ goto out;
++ /* else fall through */
++
++out_freedpd:
++ if (UNIONFS_D(sb->s_root)) {
++ kfree(UNIONFS_D(sb->s_root)->lower_paths);
++ free_dentry_private_data(sb->s_root);
++ }
++ dput(sb->s_root);
++
++out_dput:
++ if (lower_root_info && !IS_ERR(lower_root_info)) {
++ for (bindex = lower_root_info->bstart;
++ bindex <= lower_root_info->bend; bindex++) {
++ struct dentry *d;
++ d = lower_root_info->lower_paths[bindex].dentry;
++ /* drop refs we took earlier */
++ atomic_dec(&d->d_sb->s_active);
++ path_put(&lower_root_info->lower_paths[bindex]);
++ }
++ kfree(lower_root_info->lower_paths);
++ kfree(lower_root_info);
++ lower_root_info = NULL;
++ }
++
++out_free:
++ kfree(UNIONFS_SB(sb)->data);
++ kfree(UNIONFS_SB(sb));
++ sb->s_fs_info = NULL;
++
++out:
++ if (lower_root_info && !IS_ERR(lower_root_info)) {
++ kfree(lower_root_info->lower_paths);
++ kfree(lower_root_info);
++ }
++ return err;
++}
++
++static struct dentry *unionfs_mount(struct file_system_type *fs_type,
++ int flags, const char *dev_name,
++ void *raw_data)
++{
++ struct dentry *dentry;
++
++ dentry = mount_nodev(fs_type, flags, raw_data, unionfs_read_super);
++ if (!PTR_ERR(dentry))
++ UNIONFS_SB(dentry->d_sb)->dev_name =
++ kstrdup(dev_name, GFP_KERNEL);
++ return dentry;
++}
++
++static struct file_system_type unionfs_fs_type = {
++ .owner = THIS_MODULE,
++ .name = UNIONFS_NAME,
++ .mount = unionfs_mount,
++ .kill_sb = generic_shutdown_super,
++ .fs_flags = FS_REVAL_DOT,
++};
++
++static int __init init_unionfs_fs(void)
++{
++ int err;
++
++ pr_info("Registering unionfs " UNIONFS_VERSION "\n");
++
++ err = unionfs_init_filldir_cache();
++ if (unlikely(err))
++ goto out;
++ err = unionfs_init_inode_cache();
++ if (unlikely(err))
++ goto out;
++ err = unionfs_init_dentry_cache();
++ if (unlikely(err))
++ goto out;
++ err = init_sioq();
++ if (unlikely(err))
++ goto out;
++ err = register_filesystem(&unionfs_fs_type);
++out:
++ if (unlikely(err)) {
++ stop_sioq();
++ unionfs_destroy_filldir_cache();
++ unionfs_destroy_inode_cache();
++ unionfs_destroy_dentry_cache();
++ }
++ return err;
++}
++
++static void __exit exit_unionfs_fs(void)
++{
++ stop_sioq();
++ unionfs_destroy_filldir_cache();
++ unionfs_destroy_inode_cache();
++ unionfs_destroy_dentry_cache();
++ unregister_filesystem(&unionfs_fs_type);
++ pr_info("Completed unionfs module unload\n");
++}
++
++MODULE_AUTHOR("Erez Zadok, Filesystems and Storage Lab, Stony Brook University"
++ " (http://www.fsl.cs.sunysb.edu)");
++MODULE_DESCRIPTION("Unionfs " UNIONFS_VERSION
++ " (http://unionfs.filesystems.org)");
++MODULE_LICENSE("GPL");
++
++module_init(init_unionfs_fs);
++module_exit(exit_unionfs_fs);
+diff --git a/fs/unionfs/mmap.c b/fs/unionfs/mmap.c
+new file mode 100644
+index 0000000..bcc5652
+--- /dev/null
++++ b/fs/unionfs/mmap.c
+@@ -0,0 +1,89 @@
++/*
++ * Copyright (c) 2003-2011 Erez Zadok
++ * Copyright (c) 2003-2006 Charles P. Wright
++ * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
++ * Copyright (c) 2005-2006 Junjiro Okajima
++ * Copyright (c) 2006 Shaya Potter
++ * Copyright (c) 2005 Arun M. Krishnakumar
++ * Copyright (c) 2004-2006 David P. Quigley
++ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
++ * Copyright (c) 2003 Puja Gupta
++ * Copyright (c) 2003 Harikesavan Krishnan
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 The Research Foundation of SUNY
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "union.h"
++
++
++/*
++ * XXX: we need a dummy readpage handler because generic_file_mmap (which we
++ * use in unionfs_mmap) checks for the existence of
++ * mapping->a_ops->readpage, else it returns -ENOEXEC. The VFS will need to
++ * be fixed to allow a file system to define vm_ops->fault without any
++ * address_space_ops whatsoever.
++ *
++ * Otherwise, we don't want to use our readpage method at all.
++ */
++static int unionfs_readpage(struct file *file, struct page *page)
++{
++ BUG();
++ return -EINVAL;
++}
++
++static int unionfs_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
++{
++ int err;
++ struct file *file, *lower_file;
++ const struct vm_operations_struct *lower_vm_ops;
++ struct vm_area_struct lower_vma;
++
++ BUG_ON(!vma);
++ memcpy(&lower_vma, vma, sizeof(struct vm_area_struct));
++ file = lower_vma.vm_file;
++ lower_vm_ops = UNIONFS_F(file)->lower_vm_ops;
++ BUG_ON(!lower_vm_ops);
++
++ lower_file = unionfs_lower_file(file);
++ BUG_ON(!lower_file);
++ /*
++ * XXX: vm_ops->fault may be called in parallel. Because we have to
++ * resort to temporarily changing the vma->vm_file to point to the
++ * lower file, a concurrent invocation of unionfs_fault could see a
++ * different value. In this workaround, we keep a different copy of
++ * the vma structure in our stack, so we never expose a different
++ * value of the vma->vm_file called to us, even temporarily. A
++ * better fix would be to change the calling semantics of ->fault to
++ * take an explicit file pointer.
++ */
++ lower_vma.vm_file = lower_file;
++ err = lower_vm_ops->fault(&lower_vma, vmf);
++ return err;
++}
++
++/*
++ * XXX: the default address_space_ops for unionfs is empty. We cannot set
++ * our inode->i_mapping->a_ops to NULL because too many code paths expect
++ * the a_ops vector to be non-NULL.
++ */
++struct address_space_operations unionfs_aops = {
++ /* empty on purpose */
++};
++
++/*
++ * XXX: we need a second, dummy address_space_ops vector, to be used
++ * temporarily during unionfs_mmap, because the latter calls
++ * generic_file_mmap, which checks if ->readpage exists, else returns
++ * -ENOEXEC.
++ */
++struct address_space_operations unionfs_dummy_aops = {
++ .readpage = unionfs_readpage,
++};
++
++struct vm_operations_struct unionfs_vm_ops = {
++ .fault = unionfs_fault,
++};
+diff --git a/fs/unionfs/rdstate.c b/fs/unionfs/rdstate.c
+new file mode 100644
+index 0000000..59b7333
+--- /dev/null
++++ b/fs/unionfs/rdstate.c
+@@ -0,0 +1,285 @@
++/*
++ * Copyright (c) 2003-2011 Erez Zadok
++ * Copyright (c) 2003-2006 Charles P. Wright
++ * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
++ * Copyright (c) 2005-2006 Junjiro Okajima
++ * Copyright (c) 2005 Arun M. Krishnakumar
++ * Copyright (c) 2004-2006 David P. Quigley
++ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
++ * Copyright (c) 2003 Puja Gupta
++ * Copyright (c) 2003 Harikesavan Krishnan
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 The Research Foundation of SUNY
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "union.h"
++
++/* This file contains the routines for maintaining readdir state. */
++
++/*
++ * There are two structures here, rdstate which is a hash table
++ * of the second structure which is a filldir_node.
++ */
++
++/*
++ * This is a struct kmem_cache for filldir nodes, because we allocate a lot
++ * of them and they shouldn't waste memory. If the node has a small name
++ * (as defined by the dentry structure), then we use an inline name to
++ * preserve kmalloc space.
++ */
++static struct kmem_cache *unionfs_filldir_cachep;
++
++int unionfs_init_filldir_cache(void)
++{
++ unionfs_filldir_cachep =
++ kmem_cache_create("unionfs_filldir",
++ sizeof(struct filldir_node), 0,
++ SLAB_RECLAIM_ACCOUNT, NULL);
++
++ return (unionfs_filldir_cachep ? 0 : -ENOMEM);
++}
++
++void unionfs_destroy_filldir_cache(void)
++{
++ if (unionfs_filldir_cachep)
++ kmem_cache_destroy(unionfs_filldir_cachep);
++}
++
++/*
++ * This is a tuning parameter that tells us roughly how big to make the
++ * hash table in directory entries per page. This isn't perfect, but
++ * at least we get a hash table size that shouldn't be too overloaded.
++ * The following averages are based on my home directory.
++ * 14.44693 Overall
++ * 12.29 Single Page Directories
++ * 117.93 Multi-page directories
++ */
++#define DENTPAGE 4096
++#define DENTPERONEPAGE 12
++#define DENTPERPAGE 118
++#define MINHASHSIZE 1
++static int guesstimate_hash_size(struct inode *inode)
++{
++ struct inode *lower_inode;
++ int bindex;
++ int hashsize = MINHASHSIZE;
++
++ if (UNIONFS_I(inode)->hashsize > 0)
++ return UNIONFS_I(inode)->hashsize;
++
++ for (bindex = ibstart(inode); bindex <= ibend(inode); bindex++) {
++ lower_inode = unionfs_lower_inode_idx(inode, bindex);
++ if (!lower_inode)
++ continue;
++
++ if (i_size_read(lower_inode) == DENTPAGE)
++ hashsize += DENTPERONEPAGE;
++ else
++ hashsize += (i_size_read(lower_inode) / DENTPAGE) *
++ DENTPERPAGE;
++ }
++
++ return hashsize;
++}
++
++int init_rdstate(struct file *file)
++{
++ BUG_ON(sizeof(loff_t) !=
++ (sizeof(unsigned int) + sizeof(unsigned int)));
++ BUG_ON(UNIONFS_F(file)->rdstate != NULL);
++
++ UNIONFS_F(file)->rdstate = alloc_rdstate(file->f_path.dentry->d_inode,
++ fbstart(file));
++
++ return (UNIONFS_F(file)->rdstate ? 0 : -ENOMEM);
++}
++
++struct unionfs_dir_state *find_rdstate(struct inode *inode, loff_t fpos)
++{
++ struct unionfs_dir_state *rdstate = NULL;
++ struct list_head *pos;
++
++ spin_lock(&UNIONFS_I(inode)->rdlock);
++ list_for_each(pos, &UNIONFS_I(inode)->readdircache) {
++ struct unionfs_dir_state *r =
++ list_entry(pos, struct unionfs_dir_state, cache);
++ if (fpos == rdstate2offset(r)) {
++ UNIONFS_I(inode)->rdcount--;
++ list_del(&r->cache);
++ rdstate = r;
++ break;
++ }
++ }
++ spin_unlock(&UNIONFS_I(inode)->rdlock);
++ return rdstate;
++}
++
++struct unionfs_dir_state *alloc_rdstate(struct inode *inode, int bindex)
++{
++ int i = 0;
++ int hashsize;
++ unsigned long mallocsize = sizeof(struct unionfs_dir_state);
++ struct unionfs_dir_state *rdstate;
++
++ hashsize = guesstimate_hash_size(inode);
++ mallocsize += hashsize * sizeof(struct list_head);
++ mallocsize = __roundup_pow_of_two(mallocsize);
++
++ /* This should give us about 500 entries anyway. */
++ if (mallocsize > PAGE_SIZE)
++ mallocsize = PAGE_SIZE;
++
++ hashsize = (mallocsize - sizeof(struct unionfs_dir_state)) /
++ sizeof(struct list_head);
++
++ rdstate = kmalloc(mallocsize, GFP_KERNEL);
++ if (unlikely(!rdstate))
++ return NULL;
++
++ spin_lock(&UNIONFS_I(inode)->rdlock);
++ if (UNIONFS_I(inode)->cookie >= (MAXRDCOOKIE - 1))
++ UNIONFS_I(inode)->cookie = 1;
++ else
++ UNIONFS_I(inode)->cookie++;
++
++ rdstate->cookie = UNIONFS_I(inode)->cookie;
++ spin_unlock(&UNIONFS_I(inode)->rdlock);
++ rdstate->offset = 1;
++ rdstate->access = jiffies;
++ rdstate->bindex = bindex;
++ rdstate->dirpos = 0;
++ rdstate->hashentries = 0;
++ rdstate->size = hashsize;
++ for (i = 0; i < rdstate->size; i++)
++ INIT_LIST_HEAD(&rdstate->list[i]);
++
++ return rdstate;
++}
++
++static void free_filldir_node(struct filldir_node *node)
++{
++ if (node->namelen >= DNAME_INLINE_LEN)
++ kfree(node->name);
++ kmem_cache_free(unionfs_filldir_cachep, node);
++}
++
++void free_rdstate(struct unionfs_dir_state *state)
++{
++ struct filldir_node *tmp;
++ int i;
++
++ for (i = 0; i < state->size; i++) {
++ struct list_head *head = &(state->list[i]);
++ struct list_head *pos, *n;
++
++ /* traverse the list and deallocate space */
++ list_for_each_safe(pos, n, head) {
++ tmp = list_entry(pos, struct filldir_node, file_list);
++ list_del(&tmp->file_list);
++ free_filldir_node(tmp);
++ }
++ }
++
++ kfree(state);
++}
++
++struct filldir_node *find_filldir_node(struct unionfs_dir_state *rdstate,
++ const char *name, int namelen,
++ int is_whiteout)
++{
++ int index;
++ unsigned int hash;
++ struct list_head *head;
++ struct list_head *pos;
++ struct filldir_node *cursor = NULL;
++ int found = 0;
++
++ BUG_ON(namelen <= 0);
++
++ hash = full_name_hash(name, namelen);
++ index = hash % rdstate->size;
++
++ head = &(rdstate->list[index]);
++ list_for_each(pos, head) {
++ cursor = list_entry(pos, struct filldir_node, file_list);
++
++ if (cursor->namelen == namelen && cursor->hash == hash &&
++ !strncmp(cursor->name, name, namelen)) {
++ /*
++ * a duplicate exists, and hence no need to create
++ * entry to the list
++ */
++ found = 1;
++
++ /*
++ * if a duplicate is found in this branch, and is
++ * not due to the caller looking for an entry to
++ * whiteout, then the file system may be corrupted.
++ */
++ if (unlikely(!is_whiteout &&
++ cursor->bindex == rdstate->bindex))
++ printk(KERN_ERR "unionfs: filldir: possible "
++ "I/O error: a file is duplicated "
++ "in the same branch %d: %s\n",
++ rdstate->bindex, cursor->name);
++ break;
++ }
++ }
++
++ if (!found)
++ cursor = NULL;
++
++ return cursor;
++}
++
++int add_filldir_node(struct unionfs_dir_state *rdstate, const char *name,
++ int namelen, int bindex, int whiteout)
++{
++ struct filldir_node *new;
++ unsigned int hash;
++ int index;
++ int err = 0;
++ struct list_head *head;
++
++ BUG_ON(namelen <= 0);
++
++ hash = full_name_hash(name, namelen);
++ index = hash % rdstate->size;
++ head = &(rdstate->list[index]);
++
++ new = kmem_cache_alloc(unionfs_filldir_cachep, GFP_KERNEL);
++ if (unlikely(!new)) {
++ err = -ENOMEM;
++ goto out;
++ }
++
++ INIT_LIST_HEAD(&new->file_list);
++ new->namelen = namelen;
++ new->hash = hash;
++ new->bindex = bindex;
++ new->whiteout = whiteout;
++
++ if (namelen < DNAME_INLINE_LEN) {
++ new->name = new->iname;
++ } else {
++ new->name = kmalloc(namelen + 1, GFP_KERNEL);
++ if (unlikely(!new->name)) {
++ kmem_cache_free(unionfs_filldir_cachep, new);
++ new = NULL;
++ goto out;
++ }
++ }
++
++ memcpy(new->name, name, namelen);
++ new->name[namelen] = '\0';
++
++ rdstate->hashentries++;
++
++ list_add(&(new->file_list), head);
++out:
++ return err;
++}
+diff --git a/fs/unionfs/rename.c b/fs/unionfs/rename.c
+new file mode 100644
+index 0000000..c8ab910
+--- /dev/null
++++ b/fs/unionfs/rename.c
+@@ -0,0 +1,522 @@
++/*
++ * Copyright (c) 2003-2011 Erez Zadok
++ * Copyright (c) 2003-2006 Charles P. Wright
++ * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
++ * Copyright (c) 2005-2006 Junjiro Okajima
++ * Copyright (c) 2005 Arun M. Krishnakumar
++ * Copyright (c) 2004-2006 David P. Quigley
++ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
++ * Copyright (c) 2003 Puja Gupta
++ * Copyright (c) 2003 Harikesavan Krishnan
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 The Research Foundation of SUNY
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "union.h"
++
++/*
++ * This is a helper function for rename, used when rename ends up with hosed
++ * over dentries and we need to revert.
++ */
++static int unionfs_refresh_lower_dentry(struct dentry *dentry,
++ struct dentry *parent, int bindex)
++{
++ struct dentry *lower_dentry;
++ struct dentry *lower_parent;
++ int err = 0;
++ struct nameidata lower_nd;
++
++ verify_locked(dentry);
++
++ lower_parent = unionfs_lower_dentry_idx(parent, bindex);
++
++ BUG_ON(!S_ISDIR(lower_parent->d_inode->i_mode));
++
++ err = init_lower_nd(&lower_nd, LOOKUP_OPEN);
++ if (unlikely(err < 0))
++ goto out;
++ lower_dentry = lookup_one_len_nd(dentry->d_name.name, lower_parent,
++ dentry->d_name.len, &lower_nd);
++ release_lower_nd(&lower_nd, err);
++ if (IS_ERR(lower_dentry)) {
++ err = PTR_ERR(lower_dentry);
++ goto out;
++ }
++
++ dput(unionfs_lower_dentry_idx(dentry, bindex));
++ iput(unionfs_lower_inode_idx(dentry->d_inode, bindex));
++ unionfs_set_lower_inode_idx(dentry->d_inode, bindex, NULL);
++
++ if (!lower_dentry->d_inode) {
++ dput(lower_dentry);
++ unionfs_set_lower_dentry_idx(dentry, bindex, NULL);
++ } else {
++ unionfs_set_lower_dentry_idx(dentry, bindex, lower_dentry);
++ unionfs_set_lower_inode_idx(dentry->d_inode, bindex,
++ igrab(lower_dentry->d_inode));
++ }
++
++out:
++ return err;
++}
++
++static int __unionfs_rename(struct inode *old_dir, struct dentry *old_dentry,
++ struct dentry *old_parent,
++ struct inode *new_dir, struct dentry *new_dentry,
++ struct dentry *new_parent,
++ int bindex)
++{
++ int err = 0;
++ struct dentry *lower_old_dentry;
++ struct dentry *lower_new_dentry;
++ struct dentry *lower_old_dir_dentry;
++ struct dentry *lower_new_dir_dentry;
++ struct dentry *trap;
++
++ lower_new_dentry = unionfs_lower_dentry_idx(new_dentry, bindex);
++ lower_old_dentry = unionfs_lower_dentry_idx(old_dentry, bindex);
++
++ if (!lower_new_dentry) {
++ lower_new_dentry =
++ create_parents(new_parent->d_inode,
++ new_dentry, new_dentry->d_name.name,
++ bindex);
++ if (IS_ERR(lower_new_dentry)) {
++ err = PTR_ERR(lower_new_dentry);
++ if (IS_COPYUP_ERR(err))
++ goto out;
++ printk(KERN_ERR "unionfs: error creating directory "
++ "tree for rename, bindex=%d err=%d\n",
++ bindex, err);
++ goto out;
++ }
++ }
++
++ /* check for and remove whiteout, if any */
++ err = check_unlink_whiteout(new_dentry, lower_new_dentry, bindex);
++ if (err > 0) /* ignore if whiteout found and successfully removed */
++ err = 0;
++ if (err)
++ goto out;
++
++ /* check of old_dentry branch is writable */
++ err = is_robranch_super(old_dentry->d_sb, bindex);
++ if (err)
++ goto out;
++
++ dget(lower_old_dentry);
++ dget(lower_new_dentry);
++ lower_old_dir_dentry = dget_parent(lower_old_dentry);
++ lower_new_dir_dentry = dget_parent(lower_new_dentry);
++
++ trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
++ /* source should not be ancenstor of target */
++ if (trap == lower_old_dentry) {
++ err = -EINVAL;
++ goto out_err_unlock;
++ }
++ /* target should not be ancenstor of source */
++ if (trap == lower_new_dentry) {
++ err = -ENOTEMPTY;
++ goto out_err_unlock;
++ }
++ err = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry,
++ lower_new_dir_dentry->d_inode, lower_new_dentry);
++out_err_unlock:
++ if (!err) {
++ /* update parent dir times */
++ fsstack_copy_attr_times(old_dir, lower_old_dir_dentry->d_inode);
++ fsstack_copy_attr_times(new_dir, lower_new_dir_dentry->d_inode);
++ }
++ unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
++
++ dput(lower_old_dir_dentry);
++ dput(lower_new_dir_dentry);
++ dput(lower_old_dentry);
++ dput(lower_new_dentry);
++
++out:
++ if (!err) {
++ /* Fixup the new_dentry. */
++ if (bindex < dbstart(new_dentry))
++ dbstart(new_dentry) = bindex;
++ else if (bindex > dbend(new_dentry))
++ dbend(new_dentry) = bindex;
++ }
++
++ return err;
++}
++
++/*
++ * Main rename code. This is sufficiently complex, that it's documented in
++ * Documentation/filesystems/unionfs/rename.txt. This routine calls
++ * __unionfs_rename() above to perform some of the work.
++ */
++static int do_unionfs_rename(struct inode *old_dir,
++ struct dentry *old_dentry,
++ struct dentry *old_parent,
++ struct inode *new_dir,
++ struct dentry *new_dentry,
++ struct dentry *new_parent)
++{
++ int err = 0;
++ int bindex;
++ int old_bstart, old_bend;
++ int new_bstart, new_bend;
++ int do_copyup = -1;
++ int local_err = 0;
++ int eio = 0;
++ int revert = 0;
++
++ old_bstart = dbstart(old_dentry);
++ old_bend = dbend(old_dentry);
++
++ new_bstart = dbstart(new_dentry);
++ new_bend = dbend(new_dentry);
++
++ /* Rename source to destination. */
++ err = __unionfs_rename(old_dir, old_dentry, old_parent,
++ new_dir, new_dentry, new_parent,
++ old_bstart);
++ if (err) {
++ if (!IS_COPYUP_ERR(err))
++ goto out;
++ do_copyup = old_bstart - 1;
++ } else {
++ revert = 1;
++ }
++
++ /*
++ * Unlink all instances of destination that exist to the left of
++ * bstart of source. On error, revert back, goto out.
++ */
++ for (bindex = old_bstart - 1; bindex >= new_bstart; bindex--) {
++ struct dentry *unlink_dentry;
++ struct dentry *unlink_dir_dentry;
++
++ BUG_ON(bindex < 0);
++ unlink_dentry = unionfs_lower_dentry_idx(new_dentry, bindex);
++ if (!unlink_dentry)
++ continue;
++
++ unlink_dir_dentry = lock_parent(unlink_dentry);
++ err = is_robranch_super(old_dir->i_sb, bindex);
++ if (!err)
++ err = vfs_unlink(unlink_dir_dentry->d_inode,
++ unlink_dentry);
++
++ fsstack_copy_attr_times(new_parent->d_inode,
++ unlink_dir_dentry->d_inode);
++ /* propagate number of hard-links */
++ new_parent->d_inode->i_nlink =
++ unionfs_get_nlinks(new_parent->d_inode);
++
++ unlock_dir(unlink_dir_dentry);
++ if (!err) {
++ if (bindex != new_bstart) {
++ dput(unlink_dentry);
++ unionfs_set_lower_dentry_idx(new_dentry,
++ bindex, NULL);
++ }
++ } else if (IS_COPYUP_ERR(err)) {
++ do_copyup = bindex - 1;
++ } else if (revert) {
++ goto revert;
++ }
++ }
++
++ if (do_copyup != -1) {
++ for (bindex = do_copyup; bindex >= 0; bindex--) {
++ /*
++ * copyup the file into some left directory, so that
++ * you can rename it
++ */
++ err = copyup_dentry(old_parent->d_inode,
++ old_dentry, old_bstart, bindex,
++ old_dentry->d_name.name,
++ old_dentry->d_name.len, NULL,
++ i_size_read(old_dentry->d_inode));
++ /* if copyup failed, try next branch to the left */
++ if (err)
++ continue;
++ /*
++ * create whiteout before calling __unionfs_rename
++ * because the latter will change the old_dentry's
++ * lower name and parent dir, resulting in the
++ * whiteout getting created in the wrong dir.
++ */
++ err = create_whiteout(old_dentry, bindex);
++ if (err) {
++ printk(KERN_ERR "unionfs: can't create a "
++ "whiteout for %s in rename (err=%d)\n",
++ old_dentry->d_name.name, err);
++ continue;
++ }
++ err = __unionfs_rename(old_dir, old_dentry, old_parent,
++ new_dir, new_dentry, new_parent,
++ bindex);
++ break;
++ }
++ }
++
++ /* make it opaque */
++ if (S_ISDIR(old_dentry->d_inode->i_mode)) {
++ err = make_dir_opaque(old_dentry, dbstart(old_dentry));
++ if (err)
++ goto revert;
++ }
++
++ /*
++ * Create whiteout for source, only if:
++ * (1) There is more than one underlying instance of source.
++ * (We did a copy_up is taken care of above).
++ */
++ if ((old_bstart != old_bend) && (do_copyup == -1)) {
++ err = create_whiteout(old_dentry, old_bstart);
++ if (err) {
++ /* can't fix anything now, so we exit with -EIO */
++ printk(KERN_ERR "unionfs: can't create a whiteout for "
++ "%s in rename!\n", old_dentry->d_name.name);
++ err = -EIO;
++ }
++ }
++
++out:
++ return err;
++
++revert:
++ /* Do revert here. */
++ local_err = unionfs_refresh_lower_dentry(new_dentry, new_parent,
++ old_bstart);
++ if (local_err) {
++ printk(KERN_ERR "unionfs: revert failed in rename: "
++ "the new refresh failed\n");
++ eio = -EIO;
++ }
++
++ local_err = unionfs_refresh_lower_dentry(old_dentry, old_parent,
++ old_bstart);
++ if (local_err) {
++ printk(KERN_ERR "unionfs: revert failed in rename: "
++ "the old refresh failed\n");
++ eio = -EIO;
++ goto revert_out;
++ }
++
++ if (!unionfs_lower_dentry_idx(new_dentry, bindex) ||
++ !unionfs_lower_dentry_idx(new_dentry, bindex)->d_inode) {
++ printk(KERN_ERR "unionfs: revert failed in rename: "
++ "the object disappeared from under us!\n");
++ eio = -EIO;
++ goto revert_out;
++ }
++
++ if (unionfs_lower_dentry_idx(old_dentry, bindex) &&
++ unionfs_lower_dentry_idx(old_dentry, bindex)->d_inode) {
++ printk(KERN_ERR "unionfs: revert failed in rename: "
++ "the object was created underneath us!\n");
++ eio = -EIO;
++ goto revert_out;
++ }
++
++ local_err = __unionfs_rename(new_dir, new_dentry, new_parent,
++ old_dir, old_dentry, old_parent,
++ old_bstart);
++
++ /* If we can't fix it, then we cop-out with -EIO. */
++ if (local_err) {
++ printk(KERN_ERR "unionfs: revert failed in rename!\n");
++ eio = -EIO;
++ }
++
++ local_err = unionfs_refresh_lower_dentry(new_dentry, new_parent,
++ bindex);
++ if (local_err)
++ eio = -EIO;
++ local_err = unionfs_refresh_lower_dentry(old_dentry, old_parent,
++ bindex);
++ if (local_err)
++ eio = -EIO;
++
++revert_out:
++ if (eio)
++ err = eio;
++ return err;
++}
++
++/*
++ * We can't copyup a directory, because it may involve huge numbers of
++ * children, etc. Doing that in the kernel would be bad, so instead we
++ * return EXDEV to the user-space utility that caused this, and let the
++ * user-space recurse and ask us to copy up each file separately.
++ */
++static int may_rename_dir(struct dentry *dentry, struct dentry *parent)
++{
++ int err, bstart;
++
++ err = check_empty(dentry, parent, NULL);
++ if (err == -ENOTEMPTY) {
++ if (is_robranch(dentry))
++ return -EXDEV;
++ } else if (err) {
++ return err;
++ }
++
++ bstart = dbstart(dentry);
++ if (dbend(dentry) == bstart || dbopaque(dentry) == bstart)
++ return 0;
++
++ dbstart(dentry) = bstart + 1;
++ err = check_empty(dentry, parent, NULL);
++ dbstart(dentry) = bstart;
++ if (err == -ENOTEMPTY)
++ err = -EXDEV;
++ return err;
++}
++
++/*
++ * The locking rules in unionfs_rename are complex. We could use a simpler
++ * superblock-level name-space lock for renames and copy-ups.
++ */
++int unionfs_rename(struct inode *old_dir, struct dentry *old_dentry,
++ struct inode *new_dir, struct dentry *new_dentry)
++{
++ int err = 0;
++ struct dentry *wh_dentry;
++ struct dentry *old_parent, *new_parent;
++ int valid = true;
++
++ unionfs_read_lock(old_dentry->d_sb, UNIONFS_SMUTEX_CHILD);
++ old_parent = dget_parent(old_dentry);
++ new_parent = dget_parent(new_dentry);
++ /* un/lock parent dentries only if they differ from old/new_dentry */
++ if (old_parent != old_dentry &&
++ old_parent != new_dentry)
++ unionfs_lock_dentry(old_parent, UNIONFS_DMUTEX_REVAL_PARENT);
++ if (new_parent != old_dentry &&
++ new_parent != new_dentry &&
++ new_parent != old_parent)
++ unionfs_lock_dentry(new_parent, UNIONFS_DMUTEX_REVAL_CHILD);
++ unionfs_double_lock_dentry(old_dentry, new_dentry);
++
++ valid = __unionfs_d_revalidate(old_dentry, old_parent, false);
++ if (!valid) {
++ err = -ESTALE;
++ goto out;
++ }
++ if (!d_deleted(new_dentry) && new_dentry->d_inode) {
++ valid = __unionfs_d_revalidate(new_dentry, new_parent, false);
++ if (!valid) {
++ err = -ESTALE;
++ goto out;
++ }
++ }
++
++ if (!S_ISDIR(old_dentry->d_inode->i_mode))
++ err = unionfs_partial_lookup(old_dentry, old_parent);
++ else
++ err = may_rename_dir(old_dentry, old_parent);
++
++ if (err)
++ goto out;
++
++ err = unionfs_partial_lookup(new_dentry, new_parent);
++ if (err)
++ goto out;
++
++ /*
++ * if new_dentry is already lower because of whiteout,
++ * simply override it even if the whited-out dir is not empty.
++ */
++ wh_dentry = find_first_whiteout(new_dentry);
++ if (!IS_ERR(wh_dentry)) {
++ dput(wh_dentry);
++ } else if (new_dentry->d_inode) {
++ if (S_ISDIR(old_dentry->d_inode->i_mode) !=
++ S_ISDIR(new_dentry->d_inode->i_mode)) {
++ err = S_ISDIR(old_dentry->d_inode->i_mode) ?
++ -ENOTDIR : -EISDIR;
++ goto out;
++ }
++
++ if (S_ISDIR(new_dentry->d_inode->i_mode)) {
++ struct unionfs_dir_state *namelist = NULL;
++ /* check if this unionfs directory is empty or not */
++ err = check_empty(new_dentry, new_parent, &namelist);
++ if (err)
++ goto out;
++
++ if (!is_robranch(new_dentry))
++ err = delete_whiteouts(new_dentry,
++ dbstart(new_dentry),
++ namelist);
++
++ free_rdstate(namelist);
++
++ if (err)
++ goto out;
++ }
++ }
++
++ err = do_unionfs_rename(old_dir, old_dentry, old_parent,
++ new_dir, new_dentry, new_parent);
++ if (err)
++ goto out;
++
++ /*
++ * force re-lookup since the dir on ro branch is not renamed, and
++ * lower dentries still indicate the un-renamed ones.
++ */
++ if (S_ISDIR(old_dentry->d_inode->i_mode))
++ atomic_dec(&UNIONFS_D(old_dentry)->generation);
++ else
++ unionfs_postcopyup_release(old_dentry);
++ if (new_dentry->d_inode && !S_ISDIR(new_dentry->d_inode->i_mode)) {
++ unionfs_postcopyup_release(new_dentry);
++ unionfs_postcopyup_setmnt(new_dentry);
++ if (!unionfs_lower_inode(new_dentry->d_inode)) {
++ /*
++ * If we get here, it means that no copyup was
++ * needed, and that a file by the old name already
++ * existing on the destination branch; that file got
++ * renamed earlier in this function, so all we need
++ * to do here is set the lower inode.
++ */
++ struct inode *inode;
++ inode = unionfs_lower_inode(old_dentry->d_inode);
++ igrab(inode);
++ unionfs_set_lower_inode_idx(new_dentry->d_inode,
++ dbstart(new_dentry),
++ inode);
++ }
++ }
++ /* if all of this renaming succeeded, update our times */
++ unionfs_copy_attr_times(old_dentry->d_inode);
++ unionfs_copy_attr_times(new_dentry->d_inode);
++ unionfs_check_inode(old_dir);
++ unionfs_check_inode(new_dir);
++ unionfs_check_dentry(old_dentry);
++ unionfs_check_dentry(new_dentry);
++
++out:
++ if (err) /* clear the new_dentry stuff created */
++ d_drop(new_dentry);
++
++ unionfs_double_unlock_dentry(old_dentry, new_dentry);
++ if (new_parent != old_dentry &&
++ new_parent != new_dentry &&
++ new_parent != old_parent)
++ unionfs_unlock_dentry(new_parent);
++ if (old_parent != old_dentry &&
++ old_parent != new_dentry)
++ unionfs_unlock_dentry(old_parent);
++ dput(new_parent);
++ dput(old_parent);
++ unionfs_read_unlock(old_dentry->d_sb);
++
++ return err;
++}
+diff --git a/fs/unionfs/sioq.c b/fs/unionfs/sioq.c
+new file mode 100644
+index 0000000..b923742
+--- /dev/null
++++ b/fs/unionfs/sioq.c
+@@ -0,0 +1,101 @@
++/*
++ * Copyright (c) 2006-2011 Erez Zadok
++ * Copyright (c) 2006 Charles P. Wright
++ * Copyright (c) 2006-2007 Josef 'Jeff' Sipek
++ * Copyright (c) 2006 Junjiro Okajima
++ * Copyright (c) 2006 David P. Quigley
++ * Copyright (c) 2006-2011 Stony Brook University
++ * Copyright (c) 2006-2011 The Research Foundation of SUNY
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "union.h"
++
++/*
++ * Super-user IO work Queue - sometimes we need to perform actions which
++ * would fail due to the unix permissions on the parent directory (e.g.,
++ * rmdir a directory which appears empty, but in reality contains
++ * whiteouts).
++ */
++
++static struct workqueue_struct *superio_workqueue;
++
++int __init init_sioq(void)
++{
++ int err;
++
++ superio_workqueue = create_workqueue("unionfs_siod");
++ if (!IS_ERR(superio_workqueue))
++ return 0;
++
++ err = PTR_ERR(superio_workqueue);
++ printk(KERN_ERR "unionfs: create_workqueue failed %d\n", err);
++ superio_workqueue = NULL;
++ return err;
++}
++
++void stop_sioq(void)
++{
++ if (superio_workqueue)
++ destroy_workqueue(superio_workqueue);
++}
++
++void run_sioq(work_func_t func, struct sioq_args *args)
++{
++ INIT_WORK(&args->work, func);
++
++ init_completion(&args->comp);
++ while (!queue_work(superio_workqueue, &args->work)) {
++ /* TODO: do accounting if needed */
++ schedule();
++ }
++ wait_for_completion(&args->comp);
++}
++
++void __unionfs_create(struct work_struct *work)
++{
++ struct sioq_args *args = container_of(work, struct sioq_args, work);
++ struct create_args *c = &args->create;
++
++ args->err = vfs_create(c->parent, c->dentry, c->mode, c->nd);
++ complete(&args->comp);
++}
++
++void __unionfs_mkdir(struct work_struct *work)
++{
++ struct sioq_args *args = container_of(work, struct sioq_args, work);
++ struct mkdir_args *m = &args->mkdir;
++
++ args->err = vfs_mkdir(m->parent, m->dentry, m->mode);
++ complete(&args->comp);
++}
++
++void __unionfs_mknod(struct work_struct *work)
++{
++ struct sioq_args *args = container_of(work, struct sioq_args, work);
++ struct mknod_args *m = &args->mknod;
++
++ args->err = vfs_mknod(m->parent, m->dentry, m->mode, m->dev);
++ complete(&args->comp);
++}
++
++void __unionfs_symlink(struct work_struct *work)
++{
++ struct sioq_args *args = container_of(work, struct sioq_args, work);
++ struct symlink_args *s = &args->symlink;
++
++ args->err = vfs_symlink(s->parent, s->dentry, s->symbuf);
++ complete(&args->comp);
++}
++
++void __unionfs_unlink(struct work_struct *work)
++{
++ struct sioq_args *args = container_of(work, struct sioq_args, work);
++ struct unlink_args *u = &args->unlink;
++
++ args->err = vfs_unlink(u->parent, u->dentry);
++ complete(&args->comp);
++}
+diff --git a/fs/unionfs/sioq.h b/fs/unionfs/sioq.h
+new file mode 100644
+index 0000000..c2dfb94
+--- /dev/null
++++ b/fs/unionfs/sioq.h
+@@ -0,0 +1,91 @@
++/*
++ * Copyright (c) 2006-2011 Erez Zadok
++ * Copyright (c) 2006 Charles P. Wright
++ * Copyright (c) 2006-2007 Josef 'Jeff' Sipek
++ * Copyright (c) 2006 Junjiro Okajima
++ * Copyright (c) 2006 David P. Quigley
++ * Copyright (c) 2006-2011 Stony Brook University
++ * Copyright (c) 2006-2011 The Research Foundation of SUNY
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#ifndef _SIOQ_H
++#define _SIOQ_H
++
++struct deletewh_args {
++ struct unionfs_dir_state *namelist;
++ struct dentry *dentry;
++ int bindex;
++};
++
++struct is_opaque_args {
++ struct dentry *dentry;
++};
++
++struct create_args {
++ struct inode *parent;
++ struct dentry *dentry;
++ umode_t mode;
++ struct nameidata *nd;
++};
++
++struct mkdir_args {
++ struct inode *parent;
++ struct dentry *dentry;
++ umode_t mode;
++};
++
++struct mknod_args {
++ struct inode *parent;
++ struct dentry *dentry;
++ umode_t mode;
++ dev_t dev;
++};
++
++struct symlink_args {
++ struct inode *parent;
++ struct dentry *dentry;
++ char *symbuf;
++};
++
++struct unlink_args {
++ struct inode *parent;
++ struct dentry *dentry;
++};
++
++
++struct sioq_args {
++ struct completion comp;
++ struct work_struct work;
++ int err;
++ void *ret;
++
++ union {
++ struct deletewh_args deletewh;
++ struct is_opaque_args is_opaque;
++ struct create_args create;
++ struct mkdir_args mkdir;
++ struct mknod_args mknod;
++ struct symlink_args symlink;
++ struct unlink_args unlink;
++ };
++};
++
++/* Extern definitions for SIOQ functions */
++extern int __init init_sioq(void);
++extern void stop_sioq(void);
++extern void run_sioq(work_func_t func, struct sioq_args *args);
++
++/* Extern definitions for our privilege escalation helpers */
++extern void __unionfs_create(struct work_struct *work);
++extern void __unionfs_mkdir(struct work_struct *work);
++extern void __unionfs_mknod(struct work_struct *work);
++extern void __unionfs_symlink(struct work_struct *work);
++extern void __unionfs_unlink(struct work_struct *work);
++extern void __delete_whiteouts(struct work_struct *work);
++extern void __is_opaque_dir(struct work_struct *work);
++
++#endif /* not _SIOQ_H */
+diff --git a/fs/unionfs/subr.c b/fs/unionfs/subr.c
+new file mode 100644
+index 0000000..bdca2f7
+--- /dev/null
++++ b/fs/unionfs/subr.c
+@@ -0,0 +1,95 @@
++/*
++ * Copyright (c) 2003-2011 Erez Zadok
++ * Copyright (c) 2003-2006 Charles P. Wright
++ * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
++ * Copyright (c) 2005-2006 Junjiro Okajima
++ * Copyright (c) 2005 Arun M. Krishnakumar
++ * Copyright (c) 2004-2006 David P. Quigley
++ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
++ * Copyright (c) 2003 Puja Gupta
++ * Copyright (c) 2003 Harikesavan Krishnan
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 The Research Foundation of SUNY
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "union.h"
++
++/*
++ * returns the right n_link value based on the inode type
++ */
++int unionfs_get_nlinks(const struct inode *inode)
++{
++ /* don't bother to do all the work since we're unlinked */
++ if (inode->i_nlink == 0)
++ return 0;
++
++ if (!S_ISDIR(inode->i_mode))
++ return unionfs_lower_inode(inode)->i_nlink;
++
++ /*
++ * For directories, we return 1. The only place that could cares
++ * about links is readdir, and there's d_type there so even that
++ * doesn't matter.
++ */
++ return 1;
++}
++
++/* copy a/m/ctime from the lower branch with the newest times */
++void unionfs_copy_attr_times(struct inode *upper)
++{
++ int bindex;
++ struct inode *lower;
++
++ if (!upper)
++ return;
++ if (ibstart(upper) < 0) {
++#ifdef CONFIG_UNION_FS_DEBUG
++ WARN_ON(ibstart(upper) < 0);
++#endif /* CONFIG_UNION_FS_DEBUG */
++ return;
++ }
++ for (bindex = ibstart(upper); bindex <= ibend(upper); bindex++) {
++ lower = unionfs_lower_inode_idx(upper, bindex);
++ if (!lower)
++ continue; /* not all lower dir objects may exist */
++ if (unlikely(timespec_compare(&upper->i_mtime,
++ &lower->i_mtime) < 0))
++ upper->i_mtime = lower->i_mtime;
++ if (unlikely(timespec_compare(&upper->i_ctime,
++ &lower->i_ctime) < 0))
++ upper->i_ctime = lower->i_ctime;
++ if (unlikely(timespec_compare(&upper->i_atime,
++ &lower->i_atime) < 0))
++ upper->i_atime = lower->i_atime;
++ }
++}
++
++/*
++ * A unionfs/fanout version of fsstack_copy_attr_all. Uses a
++ * unionfs_get_nlinks to properly calcluate the number of links to a file.
++ * Also, copies the max() of all a/m/ctimes for all lower inodes (which is
++ * important if the lower inode is a directory type)
++ */
++void unionfs_copy_attr_all(struct inode *dest,
++ const struct inode *src)
++{
++ dest->i_mode = src->i_mode;
++ dest->i_uid = src->i_uid;
++ dest->i_gid = src->i_gid;
++ dest->i_rdev = src->i_rdev;
++
++ unionfs_copy_attr_times(dest);
++
++ dest->i_blkbits = src->i_blkbits;
++ dest->i_flags = src->i_flags;
++
++ /*
++ * Update the nlinks AFTER updating the above fields, because the
++ * get_links callback may depend on them.
++ */
++ dest->i_nlink = unionfs_get_nlinks(dest);
++}
+diff --git a/fs/unionfs/super.c b/fs/unionfs/super.c
+new file mode 100644
+index 0000000..c3ac814
+--- /dev/null
++++ b/fs/unionfs/super.c
+@@ -0,0 +1,1030 @@
++/*
++ * Copyright (c) 2003-2011 Erez Zadok
++ * Copyright (c) 2003-2006 Charles P. Wright
++ * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
++ * Copyright (c) 2005-2006 Junjiro Okajima
++ * Copyright (c) 2005 Arun M. Krishnakumar
++ * Copyright (c) 2004-2006 David P. Quigley
++ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
++ * Copyright (c) 2003 Puja Gupta
++ * Copyright (c) 2003 Harikesavan Krishnan
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 The Research Foundation of SUNY
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "union.h"
++
++/*
++ * The inode cache is used with alloc_inode for both our inode info and the
++ * vfs inode.
++ */
++static struct kmem_cache *unionfs_inode_cachep;
++
++struct inode *unionfs_iget(struct super_block *sb, unsigned long ino)
++{
++ int size;
++ struct unionfs_inode_info *info;
++ struct inode *inode;
++
++ inode = iget_locked(sb, ino);
++ if (!inode)
++ return ERR_PTR(-ENOMEM);
++ if (!(inode->i_state & I_NEW))
++ return inode;
++
++ info = UNIONFS_I(inode);
++ memset(info, 0, offsetof(struct unionfs_inode_info, vfs_inode));
++ info->bstart = -1;
++ info->bend = -1;
++ atomic_set(&info->generation,
++ atomic_read(&UNIONFS_SB(inode->i_sb)->generation));
++ spin_lock_init(&info->rdlock);
++ info->rdcount = 1;
++ info->hashsize = -1;
++ INIT_LIST_HEAD(&info->readdircache);
++
++ size = sbmax(inode->i_sb) * sizeof(struct inode *);
++ info->lower_inodes = kzalloc(size, GFP_KERNEL);
++ if (unlikely(!info->lower_inodes)) {
++ printk(KERN_CRIT "unionfs: no kernel memory when allocating "
++ "lower-pointer array!\n");
++ iget_failed(inode);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ inode->i_version++;
++ inode->i_op = &unionfs_main_iops;
++ inode->i_fop = &unionfs_main_fops;
++
++ inode->i_mapping->a_ops = &unionfs_aops;
++
++ /*
++ * reset times so unionfs_copy_attr_all can keep out time invariants
++ * right (upper inode time being the max of all lower ones).
++ */
++ inode->i_atime.tv_sec = inode->i_atime.tv_nsec = 0;
++ inode->i_mtime.tv_sec = inode->i_mtime.tv_nsec = 0;
++ inode->i_ctime.tv_sec = inode->i_ctime.tv_nsec = 0;
++ unlock_new_inode(inode);
++ return inode;
++}
++
++/*
++ * final actions when unmounting a file system
++ *
++ * No need to lock rwsem.
++ */
++static void unionfs_put_super(struct super_block *sb)
++{
++ int bindex, bstart, bend;
++ struct unionfs_sb_info *spd;
++ int leaks = 0;
++
++ spd = UNIONFS_SB(sb);
++ if (!spd)
++ return;
++
++ bstart = sbstart(sb);
++ bend = sbend(sb);
++
++ /* Make sure we have no leaks of branchget/branchput. */
++ for (bindex = bstart; bindex <= bend; bindex++)
++ if (unlikely(branch_count(sb, bindex) != 0)) {
++ printk(KERN_CRIT
++ "unionfs: branch %d has %d references left!\n",
++ bindex, branch_count(sb, bindex));
++ leaks = 1;
++ }
++ WARN_ON(leaks != 0);
++
++ /* decrement lower super references */
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ struct super_block *s;
++ s = unionfs_lower_super_idx(sb, bindex);
++ unionfs_set_lower_super_idx(sb, bindex, NULL);
++ atomic_dec(&s->s_active);
++ }
++
++ kfree(spd->dev_name);
++ kfree(spd->data);
++ kfree(spd);
++ sb->s_fs_info = NULL;
++}
++
++/*
++ * Since people use this to answer the "How big of a file can I write?"
++ * question, we report the size of the highest priority branch as the size of
++ * the union.
++ */
++static int unionfs_statfs(struct dentry *dentry, struct kstatfs *buf)
++{
++ int err = 0;
++ struct super_block *sb;
++ struct dentry *lower_dentry;
++ struct dentry *parent;
++ struct path lower_path;
++ bool valid;
++
++ sb = dentry->d_sb;
++
++ unionfs_read_lock(sb, UNIONFS_SMUTEX_CHILD);
++ parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ valid = __unionfs_d_revalidate(dentry, parent, false);
++ if (unlikely(!valid)) {
++ err = -ESTALE;
++ goto out;
++ }
++ unionfs_check_dentry(dentry);
++
++ lower_dentry = unionfs_lower_dentry(sb->s_root);
++ lower_path.dentry = lower_dentry;
++ lower_path.mnt = unionfs_mntget(sb->s_root, 0);
++ err = vfs_statfs(&lower_path, buf);
++ mntput(lower_path.mnt);
++
++ /* set return buf to our f/s to avoid confusing user-level utils */
++ buf->f_type = UNIONFS_SUPER_MAGIC;
++ /*
++ * Our maximum file name can is shorter by a few bytes because every
++ * file name could potentially be whited-out.
++ *
++ * XXX: this restriction goes away with ODF.
++ */
++ unionfs_set_max_namelen(&buf->f_namelen);
++
++ /*
++ * reset two fields to avoid confusing user-land.
++ * XXX: is this still necessary?
++ */
++ memset(&buf->f_fsid, 0, sizeof(__kernel_fsid_t));
++ memset(&buf->f_spare, 0, sizeof(buf->f_spare));
++
++out:
++ unionfs_check_dentry(dentry);
++ unionfs_unlock_dentry(dentry);
++ unionfs_unlock_parent(dentry, parent);
++ unionfs_read_unlock(sb);
++ return err;
++}
++
++/* handle mode changing during remount */
++static noinline_for_stack int do_remount_mode_option(
++ char *optarg,
++ int cur_branches,
++ struct unionfs_data *new_data,
++ struct path *new_lower_paths)
++{
++ int err = -EINVAL;
++ int perms, idx;
++ char *modename = strchr(optarg, '=');
++ struct path path;
++
++ /* by now, optarg contains the branch name */
++ if (!*optarg) {
++ printk(KERN_ERR
++ "unionfs: no branch specified for mode change\n");
++ goto out;
++ }
++ if (!modename) {
++ printk(KERN_ERR "unionfs: branch \"%s\" requires a mode\n",
++ optarg);
++ goto out;
++ }
++ *modename++ = '\0';
++ err = parse_branch_mode(modename, &perms);
++ if (err) {
++ printk(KERN_ERR "unionfs: invalid mode \"%s\" for \"%s\"\n",
++ modename, optarg);
++ goto out;
++ }
++
++ /*
++ * Find matching branch index. For now, this assumes that nothing
++ * has been mounted on top of this Unionfs stack. Once we have /odf
++ * and cache-coherency resolved, we'll address the branch-path
++ * uniqueness.
++ */
++ err = kern_path(optarg, LOOKUP_FOLLOW, &path);
++ if (err) {
++ printk(KERN_ERR "unionfs: error accessing "
++ "lower directory \"%s\" (error %d)\n",
++ optarg, err);
++ goto out;
++ }
++ for (idx = 0; idx < cur_branches; idx++)
++ if (path.mnt == new_lower_paths[idx].mnt &&
++ path.dentry == new_lower_paths[idx].dentry)
++ break;
++ path_put(&path); /* no longer needed */
++ if (idx == cur_branches) {
++ err = -ENOENT; /* err may have been reset above */
++ printk(KERN_ERR "unionfs: branch \"%s\" "
++ "not found\n", optarg);
++ goto out;
++ }
++ /* check/change mode for existing branch */
++ /* we don't warn if perms==branchperms */
++ new_data[idx].branchperms = perms;
++ err = 0;
++out:
++ return err;
++}
++
++/* handle branch deletion during remount */
++static noinline_for_stack int do_remount_del_option(
++ char *optarg, int cur_branches,
++ struct unionfs_data *new_data,
++ struct path *new_lower_paths)
++{
++ int err = -EINVAL;
++ int idx;
++ struct path path;
++
++ /* optarg contains the branch name to delete */
++
++ /*
++ * Find matching branch index. For now, this assumes that nothing
++ * has been mounted on top of this Unionfs stack. Once we have /odf
++ * and cache-coherency resolved, we'll address the branch-path
++ * uniqueness.
++ */
++ err = kern_path(optarg, LOOKUP_FOLLOW, &path);
++ if (err) {
++ printk(KERN_ERR "unionfs: error accessing "
++ "lower directory \"%s\" (error %d)\n",
++ optarg, err);
++ goto out;
++ }
++ for (idx = 0; idx < cur_branches; idx++)
++ if (path.mnt == new_lower_paths[idx].mnt &&
++ path.dentry == new_lower_paths[idx].dentry)
++ break;
++ path_put(&path); /* no longer needed */
++ if (idx == cur_branches) {
++ printk(KERN_ERR "unionfs: branch \"%s\" "
++ "not found\n", optarg);
++ err = -ENOENT;
++ goto out;
++ }
++ /* check if there are any open files on the branch to be deleted */
++ if (atomic_read(&new_data[idx].open_files) > 0) {
++ err = -EBUSY;
++ goto out;
++ }
++
++ /*
++ * Now we have to delete the branch. First, release any handles it
++ * has. Then, move the remaining array indexes past "idx" in
++ * new_data and new_lower_paths one to the left. Finally, adjust
++ * cur_branches.
++ */
++ path_put(&new_lower_paths[idx]);
++
++ if (idx < cur_branches - 1) {
++ /* if idx==cur_branches-1, we delete last branch: easy */
++ memmove(&new_data[idx], &new_data[idx+1],
++ (cur_branches - 1 - idx) *
++ sizeof(struct unionfs_data));
++ memmove(&new_lower_paths[idx], &new_lower_paths[idx+1],
++ (cur_branches - 1 - idx) * sizeof(struct path));
++ }
++
++ err = 0;
++out:
++ return err;
++}
++
++/* handle branch insertion during remount */
++static noinline_for_stack int do_remount_add_option(
++ char *optarg, int cur_branches,
++ struct unionfs_data *new_data,
++ struct path *new_lower_paths,
++ int *high_branch_id)
++{
++ int err = -EINVAL;
++ int perms;
++ int idx = 0; /* default: insert at beginning */
++ char *new_branch , *modename = NULL;
++ struct path path;
++
++ /*
++ * optarg can be of several forms:
++ *
++ * /bar:/foo insert /foo before /bar
++ * /bar:/foo=ro insert /foo in ro mode before /bar
++ * /foo insert /foo in the beginning (prepend)
++ * :/foo insert /foo at the end (append)
++ */
++ if (*optarg == ':') { /* append? */
++ new_branch = optarg + 1; /* skip ':' */
++ idx = cur_branches;
++ goto found_insertion_point;
++ }
++ new_branch = strchr(optarg, ':');
++ if (!new_branch) { /* prepend? */
++ new_branch = optarg;
++ goto found_insertion_point;
++ }
++ *new_branch++ = '\0'; /* holds path+mode of new branch */
++
++ /*
++ * Find matching branch index. For now, this assumes that nothing
++ * has been mounted on top of this Unionfs stack. Once we have /odf
++ * and cache-coherency resolved, we'll address the branch-path
++ * uniqueness.
++ */
++ err = kern_path(optarg, LOOKUP_FOLLOW, &path);
++ if (err) {
++ printk(KERN_ERR "unionfs: error accessing "
++ "lower directory \"%s\" (error %d)\n",
++ optarg, err);
++ goto out;
++ }
++ for (idx = 0; idx < cur_branches; idx++)
++ if (path.mnt == new_lower_paths[idx].mnt &&
++ path.dentry == new_lower_paths[idx].dentry)
++ break;
++ path_put(&path); /* no longer needed */
++ if (idx == cur_branches) {
++ printk(KERN_ERR "unionfs: branch \"%s\" "
++ "not found\n", optarg);
++ err = -ENOENT;
++ goto out;
++ }
++
++ /*
++ * At this point idx will hold the index where the new branch should
++ * be inserted before.
++ */
++found_insertion_point:
++ /* find the mode for the new branch */
++ if (new_branch)
++ modename = strchr(new_branch, '=');
++ if (modename)
++ *modename++ = '\0';
++ if (!new_branch || !*new_branch) {
++ printk(KERN_ERR "unionfs: null new branch\n");
++ err = -EINVAL;
++ goto out;
++ }
++ err = parse_branch_mode(modename, &perms);
++ if (err) {
++ printk(KERN_ERR "unionfs: invalid mode \"%s\" for "
++ "branch \"%s\"\n", modename, new_branch);
++ goto out;
++ }
++ err = kern_path(new_branch, LOOKUP_FOLLOW, &path);
++ if (err) {
++ printk(KERN_ERR "unionfs: error accessing "
++ "lower directory \"%s\" (error %d)\n",
++ new_branch, err);
++ goto out;
++ }
++ /*
++ * It's probably safe to check_mode the new branch to insert. Note:
++ * we don't allow inserting branches which are unionfs's by
++ * themselves (check_branch returns EINVAL in that case). This is
++ * because this code base doesn't support stacking unionfs: the ODF
++ * code base supports that correctly.
++ */
++ err = check_branch(&path);
++ if (err) {
++ printk(KERN_ERR "unionfs: lower directory "
++ "\"%s\" is not a valid branch\n", optarg);
++ path_put(&path);
++ goto out;
++ }
++
++ /*
++ * Now we have to insert the new branch. But first, move the bits
++ * to make space for the new branch, if needed. Finally, adjust
++ * cur_branches.
++ * We don't release nd here; it's kept until umount/remount.
++ */
++ if (idx < cur_branches) {
++ /* if idx==cur_branches, we append: easy */
++ memmove(&new_data[idx+1], &new_data[idx],
++ (cur_branches - idx) * sizeof(struct unionfs_data));
++ memmove(&new_lower_paths[idx+1], &new_lower_paths[idx],
++ (cur_branches - idx) * sizeof(struct path));
++ }
++ new_lower_paths[idx].dentry = path.dentry;
++ new_lower_paths[idx].mnt = path.mnt;
++
++ new_data[idx].sb = path.dentry->d_sb;
++ atomic_set(&new_data[idx].open_files, 0);
++ new_data[idx].branchperms = perms;
++ new_data[idx].branch_id = ++*high_branch_id; /* assign new branch ID */
++
++ err = 0;
++out:
++ return err;
++}
++
++
++/*
++ * Support branch management options on remount.
++ *
++ * See Documentation/filesystems/unionfs/ for details.
++ *
++ * @flags: numeric mount options
++ * @options: mount options string
++ *
++ * This function can rearrange a mounted union dynamically, adding and
++ * removing branches, including changing branch modes. Clearly this has to
++ * be done safely and atomically. Luckily, the VFS already calls this
++ * function with lock_super(sb) and lock_kernel() held, preventing
++ * concurrent mixing of new mounts, remounts, and unmounts. Moreover,
++ * do_remount_sb(), our caller function, already called shrink_dcache_sb(sb)
++ * to purge dentries/inodes from our superblock, and also called
++ * fsync_super(sb) to purge any dirty pages. So we're good.
++ *
++ * XXX: however, our remount code may also need to invalidate mapped pages
++ * so as to force them to be re-gotten from the (newly reconfigured) lower
++ * branches. This has to wait for proper mmap and cache coherency support
++ * in the VFS.
++ *
++ */
++static int unionfs_remount_fs(struct super_block *sb, int *flags,
++ char *options)
++{
++ int err = 0;
++ int i;
++ char *optionstmp, *tmp_to_free; /* kstrdup'ed of "options" */
++ char *optname;
++ int cur_branches = 0; /* no. of current branches */
++ int new_branches = 0; /* no. of branches actually left in the end */
++ int add_branches; /* est. no. of branches to add */
++ int del_branches; /* est. no. of branches to del */
++ int max_branches; /* max possible no. of branches */
++ struct unionfs_data *new_data = NULL, *tmp_data = NULL;
++ struct path *new_lower_paths = NULL, *tmp_lower_paths = NULL;
++ struct inode **new_lower_inodes = NULL;
++ int new_high_branch_id; /* new high branch ID */
++ int size; /* memory allocation size, temp var */
++ int old_ibstart, old_ibend;
++
++ unionfs_write_lock(sb);
++
++ /*
++ * The VFS will take care of "ro" and "rw" flags, and we can safely
++ * ignore MS_SILENT, but anything else left over is an error. So we
++ * need to check if any other flags may have been passed (none are
++ * allowed/supported as of now).
++ */
++ if ((*flags & ~(MS_RDONLY | MS_SILENT)) != 0) {
++ printk(KERN_ERR
++ "unionfs: remount flags 0x%x unsupported\n", *flags);
++ err = -EINVAL;
++ goto out_error;
++ }
++
++ /*
++ * If 'options' is NULL, it's probably because the user just changed
++ * the union to a "ro" or "rw" and the VFS took care of it. So
++ * nothing to do and we're done.
++ */
++ if (!options || options[0] == '\0')
++ goto out_error;
++
++ /*
++ * Find out how many branches we will have in the end, counting
++ * "add" and "del" commands. Copy the "options" string because
++ * strsep modifies the string and we need it later.
++ */
++ tmp_to_free = kstrdup(options, GFP_KERNEL);
++ optionstmp = tmp_to_free;
++ if (unlikely(!optionstmp)) {
++ err = -ENOMEM;
++ goto out_free;
++ }
++ cur_branches = sbmax(sb); /* current no. branches */
++ new_branches = sbmax(sb);
++ del_branches = 0;
++ add_branches = 0;
++ new_high_branch_id = sbhbid(sb); /* save current high_branch_id */
++ while ((optname = strsep(&optionstmp, ",")) != NULL) {
++ char *optarg;
++
++ if (!optname || !*optname)
++ continue;
++
++ optarg = strchr(optname, '=');
++ if (optarg)
++ *optarg++ = '\0';
++
++ if (!strcmp("add", optname))
++ add_branches++;
++ else if (!strcmp("del", optname))
++ del_branches++;
++ }
++ kfree(tmp_to_free);
++ /* after all changes, will we have at least one branch left? */
++ if ((new_branches + add_branches - del_branches) < 1) {
++ printk(KERN_ERR
++ "unionfs: no branches left after remount\n");
++ err = -EINVAL;
++ goto out_free;
++ }
++
++ /*
++ * Since we haven't actually parsed all the add/del options, nor
++ * have we checked them for errors, we don't know for sure how many
++ * branches we will have after all changes have taken place. In
++ * fact, the total number of branches left could be less than what
++ * we have now. So we need to allocate space for a temporary
++ * placeholder that is at least as large as the maximum number of
++ * branches we *could* have, which is the current number plus all
++ * the additions. Once we're done with these temp placeholders, we
++ * may have to re-allocate the final size, copy over from the temp,
++ * and then free the temps (done near the end of this function).
++ */
++ max_branches = cur_branches + add_branches;
++ /* allocate space for new pointers to lower dentry */
++ tmp_data = kcalloc(max_branches,
++ sizeof(struct unionfs_data), GFP_KERNEL);
++ if (unlikely(!tmp_data)) {
++ err = -ENOMEM;
++ goto out_free;
++ }
++ /* allocate space for new pointers to lower paths */
++ tmp_lower_paths = kcalloc(max_branches,
++ sizeof(struct path), GFP_KERNEL);
++ if (unlikely(!tmp_lower_paths)) {
++ err = -ENOMEM;
++ goto out_free;
++ }
++ /* copy current info into new placeholders, incrementing refcnts */
++ memcpy(tmp_data, UNIONFS_SB(sb)->data,
++ cur_branches * sizeof(struct unionfs_data));
++ memcpy(tmp_lower_paths, UNIONFS_D(sb->s_root)->lower_paths,
++ cur_branches * sizeof(struct path));
++ for (i = 0; i < cur_branches; i++)
++ path_get(&tmp_lower_paths[i]); /* drop refs at end of fxn */
++
++ /*******************************************************************
++ * For each branch command, do kern_path on the requested branch,
++ * and apply the change to a temp branch list. To handle errors, we
++ * already dup'ed the old arrays (above), and increased the refcnts
++ * on various f/s objects. So now we can do all the kern_path'ss
++ * and branch-management commands on the new arrays. If it fail mid
++ * way, we free the tmp arrays and *put all objects. If we succeed,
++ * then we free old arrays and *put its objects, and then replace
++ * the arrays with the new tmp list (we may have to re-allocate the
++ * memory because the temp lists could have been larger than what we
++ * actually needed).
++ *******************************************************************/
++
++ while ((optname = strsep(&options, ",")) != NULL) {
++ char *optarg;
++
++ if (!optname || !*optname)
++ continue;
++ /*
++ * At this stage optname holds a comma-delimited option, but
++ * without the commas. Next, we need to break the string on
++ * the '=' symbol to separate CMD=ARG, where ARG itself can
++ * be KEY=VAL. For example, in mode=/foo=rw, CMD is "mode",
++ * KEY is "/foo", and VAL is "rw".
++ */
++ optarg = strchr(optname, '=');
++ if (optarg)
++ *optarg++ = '\0';
++ /* incgen remount option (instead of old ioctl) */
++ if (!strcmp("incgen", optname)) {
++ err = 0;
++ goto out_no_change;
++ }
++
++ /*
++ * All of our options take an argument now. (Insert ones
++ * that don't above this check.) So at this stage optname
++ * contains the CMD part and optarg contains the ARG part.
++ */
++ if (!optarg || !*optarg) {
++ printk(KERN_ERR "unionfs: all remount options require "
++ "an argument (%s)\n", optname);
++ err = -EINVAL;
++ goto out_release;
++ }
++
++ if (!strcmp("add", optname)) {
++ err = do_remount_add_option(optarg, new_branches,
++ tmp_data,
++ tmp_lower_paths,
++ &new_high_branch_id);
++ if (err)
++ goto out_release;
++ new_branches++;
++ if (new_branches > UNIONFS_MAX_BRANCHES) {
++ printk(KERN_ERR "unionfs: command exceeds "
++ "%d branches\n", UNIONFS_MAX_BRANCHES);
++ err = -E2BIG;
++ goto out_release;
++ }
++ continue;
++ }
++ if (!strcmp("del", optname)) {
++ err = do_remount_del_option(optarg, new_branches,
++ tmp_data,
++ tmp_lower_paths);
++ if (err)
++ goto out_release;
++ new_branches--;
++ continue;
++ }
++ if (!strcmp("mode", optname)) {
++ err = do_remount_mode_option(optarg, new_branches,
++ tmp_data,
++ tmp_lower_paths);
++ if (err)
++ goto out_release;
++ continue;
++ }
++
++ /*
++ * When you use "mount -o remount,ro", mount(8) will
++ * reportedly pass the original dirs= string from
++ * /proc/mounts. So for now, we have to ignore dirs= and
++ * not consider it an error, unless we want to allow users
++ * to pass dirs= in remount. Note that to allow the VFS to
++ * actually process the ro/rw remount options, we have to
++ * return 0 from this function.
++ */
++ if (!strcmp("dirs", optname)) {
++ printk(KERN_WARNING
++ "unionfs: remount ignoring option \"%s\"\n",
++ optname);
++ continue;
++ }
++
++ err = -EINVAL;
++ printk(KERN_ERR
++ "unionfs: unrecognized option \"%s\"\n", optname);
++ goto out_release;
++ }
++
++out_no_change:
++
++ /******************************************************************
++ * WE'RE ALMOST DONE: check if leftmost branch might be read-only,
++ * see if we need to allocate a small-sized new vector, copy the
++ * vectors to their correct place, release the refcnt of the older
++ * ones, and return. Also handle invalidating any pages that will
++ * have to be re-read.
++ *******************************************************************/
++
++ if (!(tmp_data[0].branchperms & MAY_WRITE)) {
++ printk(KERN_ERR "unionfs: leftmost branch cannot be read-only "
++ "(use \"remount,ro\" to create a read-only union)\n");
++ err = -EINVAL;
++ goto out_release;
++ }
++
++ /* (re)allocate space for new pointers to lower dentry */
++ size = new_branches * sizeof(struct unionfs_data);
++ new_data = krealloc(tmp_data, size, GFP_KERNEL);
++ if (unlikely(!new_data)) {
++ err = -ENOMEM;
++ goto out_release;
++ }
++
++ /* allocate space for new pointers to lower paths */
++ size = new_branches * sizeof(struct path);
++ new_lower_paths = krealloc(tmp_lower_paths, size, GFP_KERNEL);
++ if (unlikely(!new_lower_paths)) {
++ err = -ENOMEM;
++ goto out_release;
++ }
++
++ /* allocate space for new pointers to lower inodes */
++ new_lower_inodes = kcalloc(new_branches,
++ sizeof(struct inode *), GFP_KERNEL);
++ if (unlikely(!new_lower_inodes)) {
++ err = -ENOMEM;
++ goto out_release;
++ }
++
++ /*
++ * OK, just before we actually put the new set of branches in place,
++ * we need to ensure that our own f/s has no dirty objects left.
++ * Luckily, do_remount_sb() already calls shrink_dcache_sb(sb) and
++ * fsync_super(sb), taking care of dentries, inodes, and dirty
++ * pages. So all that's left is for us to invalidate any leftover
++ * (non-dirty) pages to ensure that they will be re-read from the
++ * new lower branches (and to support mmap).
++ */
++
++ /*
++ * Once we finish the remounting successfully, our superblock
++ * generation number will have increased. This will be detected by
++ * our dentry-revalidation code upon subsequent f/s operations
++ * through unionfs. The revalidation code will rebuild the union of
++ * lower inodes for a given unionfs inode and invalidate any pages
++ * of such "stale" inodes (by calling our purge_inode_data
++ * function). This revalidation will happen lazily and
++ * incrementally, as users perform operations on cached inodes. We
++ * would like to encourage this revalidation to happen sooner if
++ * possible, so we like to try to invalidate as many other pages in
++ * our superblock as we can. We used to call drop_pagecache_sb() or
++ * a variant thereof, but either method was racy (drop_caches alone
++ * is known to be racy). So now we let the revalidation happen on a
++ * per file basis in ->d_revalidate.
++ */
++
++ /* grab new lower super references; release old ones */
++ for (i = 0; i < new_branches; i++)
++ atomic_inc(&new_data[i].sb->s_active);
++ for (i = 0; i < sbmax(sb); i++)
++ atomic_dec(&UNIONFS_SB(sb)->data[i].sb->s_active);
++
++ /* copy new vectors into their correct place */
++ tmp_data = UNIONFS_SB(sb)->data;
++ UNIONFS_SB(sb)->data = new_data;
++ new_data = NULL; /* so don't free good pointers below */
++ tmp_lower_paths = UNIONFS_D(sb->s_root)->lower_paths;
++ UNIONFS_D(sb->s_root)->lower_paths = new_lower_paths;
++ new_lower_paths = NULL; /* so don't free good pointers below */
++
++ /* update our unionfs_sb_info and root dentry index of last branch */
++ i = sbmax(sb); /* save no. of branches to release at end */
++ sbend(sb) = new_branches - 1;
++ dbend(sb->s_root) = new_branches - 1;
++ old_ibstart = ibstart(sb->s_root->d_inode);
++ old_ibend = ibend(sb->s_root->d_inode);
++ ibend(sb->s_root->d_inode) = new_branches - 1;
++ UNIONFS_D(sb->s_root)->bcount = new_branches;
++ new_branches = i; /* no. of branches to release below */
++
++ /*
++ * Update lower inodes: 3 steps
++ * 1. grab ref on all new lower inodes
++ */
++ for (i = dbstart(sb->s_root); i <= dbend(sb->s_root); i++) {
++ struct dentry *lower_dentry =
++ unionfs_lower_dentry_idx(sb->s_root, i);
++ igrab(lower_dentry->d_inode);
++ new_lower_inodes[i] = lower_dentry->d_inode;
++ }
++ /* 2. release reference on all older lower inodes */
++ iput_lowers(sb->s_root->d_inode, old_ibstart, old_ibend, true);
++ /* 3. update root dentry's inode to new lower_inodes array */
++ UNIONFS_I(sb->s_root->d_inode)->lower_inodes = new_lower_inodes;
++ new_lower_inodes = NULL;
++
++ /* maxbytes may have changed */
++ sb->s_maxbytes = unionfs_lower_super_idx(sb, 0)->s_maxbytes;
++ /* update high branch ID */
++ sbhbid(sb) = new_high_branch_id;
++
++ /* update our sb->generation for revalidating objects */
++ i = atomic_inc_return(&UNIONFS_SB(sb)->generation);
++ atomic_set(&UNIONFS_D(sb->s_root)->generation, i);
++ atomic_set(&UNIONFS_I(sb->s_root->d_inode)->generation, i);
++ if (!(*flags & MS_SILENT))
++ pr_info("unionfs: %s: new generation number %d\n",
++ UNIONFS_SB(sb)->dev_name, i);
++ /* finally, update the root dentry's times */
++ unionfs_copy_attr_times(sb->s_root->d_inode);
++ err = 0; /* reset to success */
++
++ /*
++ * The code above falls through to the next label, and releases the
++ * refcnts of the older ones (stored in tmp_*): if we fell through
++ * here, it means success. However, if we jump directly to this
++ * label from any error above, then an error occurred after we
++ * grabbed various refcnts, and so we have to release the
++ * temporarily constructed structures.
++ */
++out_release:
++ /* no need to cleanup/release anything in tmp_data */
++ if (tmp_lower_paths)
++ for (i = 0; i < new_branches; i++)
++ path_put(&tmp_lower_paths[i]);
++out_free:
++ kfree(tmp_lower_paths);
++ kfree(tmp_data);
++ kfree(new_lower_paths);
++ kfree(new_data);
++ kfree(new_lower_inodes);
++out_error:
++ unionfs_check_dentry(sb->s_root);
++ unionfs_write_unlock(sb);
++ return err;
++}
++
++/*
++ * Called by iput() when the inode reference count reached zero
++ * and the inode is not hashed anywhere. Used to clear anything
++ * that needs to be, before the inode is completely destroyed and put
++ * on the inode free list.
++ *
++ * No need to lock sb info's rwsem.
++ */
++static void unionfs_evict_inode(struct inode *inode)
++{
++ int bindex, bstart, bend;
++ struct inode *lower_inode;
++ struct list_head *pos, *n;
++ struct unionfs_dir_state *rdstate;
++
++ truncate_inode_pages(&inode->i_data, 0);
++ end_writeback(inode);
++
++ list_for_each_safe(pos, n, &UNIONFS_I(inode)->readdircache) {
++ rdstate = list_entry(pos, struct unionfs_dir_state, cache);
++ list_del(&rdstate->cache);
++ free_rdstate(rdstate);
++ }
++
++ /*
++ * Decrement a reference to a lower_inode, which was incremented
++ * by our read_inode when it was created initially.
++ */
++ bstart = ibstart(inode);
++ bend = ibend(inode);
++ if (bstart >= 0) {
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ lower_inode = unionfs_lower_inode_idx(inode, bindex);
++ if (!lower_inode)
++ continue;
++ unionfs_set_lower_inode_idx(inode, bindex, NULL);
++ /* see Documentation/filesystems/unionfs/issues.txt */
++ lockdep_off();
++ iput(lower_inode);
++ lockdep_on();
++ }
++ }
++
++ kfree(UNIONFS_I(inode)->lower_inodes);
++ UNIONFS_I(inode)->lower_inodes = NULL;
++}
++
++static struct inode *unionfs_alloc_inode(struct super_block *sb)
++{
++ struct unionfs_inode_info *i;
++
++ i = kmem_cache_alloc(unionfs_inode_cachep, GFP_KERNEL);
++ if (unlikely(!i))
++ return NULL;
++
++ /* memset everything up to the inode to 0 */
++ memset(i, 0, offsetof(struct unionfs_inode_info, vfs_inode));
++
++ i->vfs_inode.i_version = 1;
++ return &i->vfs_inode;
++}
++
++static void unionfs_destroy_inode(struct inode *inode)
++{
++ kmem_cache_free(unionfs_inode_cachep, UNIONFS_I(inode));
++}
++
++/* unionfs inode cache constructor */
++static void init_once(void *obj)
++{
++ struct unionfs_inode_info *i = obj;
++
++ inode_init_once(&i->vfs_inode);
++}
++
++int unionfs_init_inode_cache(void)
++{
++ int err = 0;
++
++ unionfs_inode_cachep =
++ kmem_cache_create("unionfs_inode_cache",
++ sizeof(struct unionfs_inode_info), 0,
++ SLAB_RECLAIM_ACCOUNT, init_once);
++ if (unlikely(!unionfs_inode_cachep))
++ err = -ENOMEM;
++ return err;
++}
++
++/* unionfs inode cache destructor */
++void unionfs_destroy_inode_cache(void)
++{
++ if (unionfs_inode_cachep)
++ kmem_cache_destroy(unionfs_inode_cachep);
++}
++
++/*
++ * Called when we have a dirty inode, right here we only throw out
++ * parts of our readdir list that are too old.
++ *
++ * No need to grab sb info's rwsem.
++ */
++static int unionfs_write_inode(struct inode *inode,
++ struct writeback_control *wbc)
++{
++ struct list_head *pos, *n;
++ struct unionfs_dir_state *rdstate;
++
++ spin_lock(&UNIONFS_I(inode)->rdlock);
++ list_for_each_safe(pos, n, &UNIONFS_I(inode)->readdircache) {
++ rdstate = list_entry(pos, struct unionfs_dir_state, cache);
++ /* We keep this list in LRU order. */
++ if ((rdstate->access + RDCACHE_JIFFIES) > jiffies)
++ break;
++ UNIONFS_I(inode)->rdcount--;
++ list_del(&rdstate->cache);
++ free_rdstate(rdstate);
++ }
++ spin_unlock(&UNIONFS_I(inode)->rdlock);
++
++ return 0;
++}
++
++/*
++ * Used only in nfs, to kill any pending RPC tasks, so that subsequent
++ * code can actually succeed and won't leave tasks that need handling.
++ */
++static void unionfs_umount_begin(struct super_block *sb)
++{
++ struct super_block *lower_sb;
++ int bindex, bstart, bend;
++
++ unionfs_read_lock(sb, UNIONFS_SMUTEX_CHILD);
++
++ bstart = sbstart(sb);
++ bend = sbend(sb);
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ lower_sb = unionfs_lower_super_idx(sb, bindex);
++
++ if (lower_sb && lower_sb->s_op &&
++ lower_sb->s_op->umount_begin)
++ lower_sb->s_op->umount_begin(lower_sb);
++ }
++
++ unionfs_read_unlock(sb);
++}
++
++static int unionfs_show_options(struct seq_file *m, struct vfsmount *mnt)
++{
++ struct super_block *sb = mnt->mnt_sb;
++ int ret = 0;
++ char *tmp_page;
++ char *path;
++ int bindex, bstart, bend;
++ int perms;
++
++ /* to prevent a silly lockdep warning with namespace_sem */
++ lockdep_off();
++ unionfs_read_lock(sb, UNIONFS_SMUTEX_CHILD);
++ unionfs_lock_dentry(sb->s_root, UNIONFS_DMUTEX_CHILD);
++
++ tmp_page = (char *) __get_free_page(GFP_KERNEL);
++ if (unlikely(!tmp_page)) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ bstart = sbstart(sb);
++ bend = sbend(sb);
++
++ seq_printf(m, ",dirs=");
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ struct path p;
++ p.dentry = unionfs_lower_dentry_idx(sb->s_root, bindex);
++ p.mnt = unionfs_lower_mnt_idx(sb->s_root, bindex);
++ path = d_path(&p, tmp_page, PAGE_SIZE);
++ if (IS_ERR(path)) {
++ ret = PTR_ERR(path);
++ goto out;
++ }
++
++ perms = branchperms(sb, bindex);
++
++ seq_printf(m, "%s=%s", path,
++ perms & MAY_WRITE ? "rw" : "ro");
++ if (bindex != bend)
++ seq_printf(m, ":");
++ }
++
++out:
++ free_page((unsigned long) tmp_page);
++
++ unionfs_unlock_dentry(sb->s_root);
++ unionfs_read_unlock(sb);
++ lockdep_on();
++
++ return ret;
++}
++
++struct super_operations unionfs_sops = {
++ .put_super = unionfs_put_super,
++ .statfs = unionfs_statfs,
++ .remount_fs = unionfs_remount_fs,
++ .evict_inode = unionfs_evict_inode,
++ .umount_begin = unionfs_umount_begin,
++ .show_options = unionfs_show_options,
++ .write_inode = unionfs_write_inode,
++ .alloc_inode = unionfs_alloc_inode,
++ .destroy_inode = unionfs_destroy_inode,
++};
+diff --git a/fs/unionfs/union.h b/fs/unionfs/union.h
+new file mode 100644
+index 0000000..1821705
+--- /dev/null
++++ b/fs/unionfs/union.h
+@@ -0,0 +1,679 @@
++/*
++ * Copyright (c) 2003-2011 Erez Zadok
++ * Copyright (c) 2003-2006 Charles P. Wright
++ * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
++ * Copyright (c) 2005 Arun M. Krishnakumar
++ * Copyright (c) 2004-2006 David P. Quigley
++ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
++ * Copyright (c) 2003 Puja Gupta
++ * Copyright (c) 2003 Harikesavan Krishnan
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 The Research Foundation of SUNY
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#ifndef _UNION_H_
++#define _UNION_H_
++
++#include <linux/dcache.h>
++#include <linux/file.h>
++#include <linux/list.h>
++#include <linux/fs.h>
++#include <linux/mm.h>
++#include <linux/module.h>
++#include <linux/mount.h>
++#include <linux/namei.h>
++#include <linux/page-flags.h>
++#include <linux/pagemap.h>
++#include <linux/poll.h>
++#include <linux/security.h>
++#include <linux/seq_file.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/statfs.h>
++#include <linux/string.h>
++#include <linux/vmalloc.h>
++#include <linux/writeback.h>
++#include <linux/buffer_head.h>
++#include <linux/xattr.h>
++#include <linux/fs_stack.h>
++#include <linux/magic.h>
++#include <linux/log2.h>
++#include <linux/poison.h>
++#include <linux/mman.h>
++#include <linux/backing-dev.h>
++#include <linux/splice.h>
++#include <linux/sched.h>
++
++#include <asm/system.h>
++
++#include <linux/union_fs.h>
++
++/* the file system name */
++#define UNIONFS_NAME "unionfs"
++
++/* unionfs root inode number */
++#define UNIONFS_ROOT_INO 1
++
++/* number of times we try to get a unique temporary file name */
++#define GET_TMPNAM_MAX_RETRY 5
++
++/* maximum number of branches we support, to avoid memory blowup */
++#define UNIONFS_MAX_BRANCHES 128
++
++/* minimum time (seconds) required for time-based cache-coherency */
++#define UNIONFS_MIN_CC_TIME 3
++
++/* Operations vectors defined in specific files. */
++extern struct file_operations unionfs_main_fops;
++extern struct file_operations unionfs_dir_fops;
++extern struct inode_operations unionfs_main_iops;
++extern struct inode_operations unionfs_dir_iops;
++extern struct inode_operations unionfs_symlink_iops;
++extern struct super_operations unionfs_sops;
++extern struct dentry_operations unionfs_dops;
++extern struct address_space_operations unionfs_aops, unionfs_dummy_aops;
++extern struct vm_operations_struct unionfs_vm_ops;
++
++/* How long should an entry be allowed to persist */
++#define RDCACHE_JIFFIES (5*HZ)
++
++/* compatibility with Real-Time patches */
++#ifdef CONFIG_PREEMPT_RT
++# define unionfs_rw_semaphore compat_rw_semaphore
++#else /* not CONFIG_PREEMPT_RT */
++# define unionfs_rw_semaphore rw_semaphore
++#endif /* not CONFIG_PREEMPT_RT */
++
++/* file private data. */
++struct unionfs_file_info {
++ int bstart;
++ int bend;
++ atomic_t generation;
++
++ struct unionfs_dir_state *rdstate;
++ struct file **lower_files;
++ int *saved_branch_ids; /* IDs of branches when file was opened */
++ const struct vm_operations_struct *lower_vm_ops;
++ bool wrote_to_file; /* for delayed copyup */
++};
++
++/* unionfs inode data in memory */
++struct unionfs_inode_info {
++ int bstart;
++ int bend;
++ atomic_t generation;
++ /* Stuff for readdir over NFS. */
++ spinlock_t rdlock;
++ struct list_head readdircache;
++ int rdcount;
++ int hashsize;
++ int cookie;
++
++ /* The lower inodes */
++ struct inode **lower_inodes;
++
++ struct inode vfs_inode;
++};
++
++/* unionfs dentry data in memory */
++struct unionfs_dentry_info {
++ /*
++ * The semaphore is used to lock the dentry as soon as we get into a
++ * unionfs function from the VFS. Our lock ordering is that children
++ * go before their parents.
++ */
++ struct mutex lock;
++ int bstart;
++ int bend;
++ int bopaque;
++ int bcount;
++ atomic_t generation;
++ struct path *lower_paths;
++};
++
++/* These are the pointers to our various objects. */
++struct unionfs_data {
++ struct super_block *sb; /* lower super_block */
++ atomic_t open_files; /* number of open files on branch */
++ int branchperms;
++ int branch_id; /* unique branch ID at re/mount time */
++};
++
++/* unionfs super-block data in memory */
++struct unionfs_sb_info {
++ int bend;
++
++ atomic_t generation;
++
++ /*
++ * This rwsem is used to make sure that a branch management
++ * operation...
++ * 1) will not begin before all currently in-flight operations
++ * complete.
++ * 2) any new operations do not execute until the currently
++ * running branch management operation completes.
++ *
++ * The write_lock_owner records the PID of the task which grabbed
++ * the rw_sem for writing. If the same task also tries to grab the
++ * read lock, we allow it. This prevents a self-deadlock when
++ * branch-management is used on a pivot_root'ed union, because we
++ * have to ->lookup paths which belong to the same union.
++ */
++ struct unionfs_rw_semaphore rwsem;
++ pid_t write_lock_owner; /* PID of rw_sem owner (write lock) */
++ int high_branch_id; /* last unique branch ID given */
++ char *dev_name; /* to identify different unions in pr_debug */
++ struct unionfs_data *data;
++};
++
++/*
++ * structure for making the linked list of entries by readdir on left branch
++ * to compare with entries on right branch
++ */
++struct filldir_node {
++ struct list_head file_list; /* list for directory entries */
++ char *name; /* name entry */
++ int hash; /* name hash */
++ int namelen; /* name len since name is not 0 terminated */
++
++ /*
++ * we can check for duplicate whiteouts and files in the same branch
++ * in order to return -EIO.
++ */
++ int bindex;
++
++ /* is this a whiteout entry? */
++ int whiteout;
++
++ /* Inline name, so we don't need to separately kmalloc small ones */
++ char iname[DNAME_INLINE_LEN];
++};
++
++/* Directory hash table. */
++struct unionfs_dir_state {
++ unsigned int cookie; /* the cookie, based off of rdversion */
++ unsigned int offset; /* The entry we have returned. */
++ int bindex;
++ loff_t dirpos; /* offset within the lower level directory */
++ int size; /* How big is the hash table? */
++ int hashentries; /* How many entries have been inserted? */
++ unsigned long access;
++
++ /* This cache list is used when the inode keeps us around. */
++ struct list_head cache;
++ struct list_head list[0];
++};
++
++/* externs needed for fanout.h or sioq.h */
++extern int unionfs_get_nlinks(const struct inode *inode);
++extern void unionfs_copy_attr_times(struct inode *upper);
++extern void unionfs_copy_attr_all(struct inode *dest, const struct inode *src);
++
++/* include miscellaneous macros */
++#include "fanout.h"
++#include "sioq.h"
++
++/* externs for cache creation/deletion routines */
++extern void unionfs_destroy_filldir_cache(void);
++extern int unionfs_init_filldir_cache(void);
++extern int unionfs_init_inode_cache(void);
++extern void unionfs_destroy_inode_cache(void);
++extern int unionfs_init_dentry_cache(void);
++extern void unionfs_destroy_dentry_cache(void);
++
++/* Initialize and free readdir-specific state. */
++extern int init_rdstate(struct file *file);
++extern struct unionfs_dir_state *alloc_rdstate(struct inode *inode,
++ int bindex);
++extern struct unionfs_dir_state *find_rdstate(struct inode *inode,
++ loff_t fpos);
++extern void free_rdstate(struct unionfs_dir_state *state);
++extern int add_filldir_node(struct unionfs_dir_state *rdstate,
++ const char *name, int namelen, int bindex,
++ int whiteout);
++extern struct filldir_node *find_filldir_node(struct unionfs_dir_state *rdstate,
++ const char *name, int namelen,
++ int is_whiteout);
++
++extern struct dentry **alloc_new_dentries(int objs);
++extern struct unionfs_data *alloc_new_data(int objs);
++
++/* We can only use 32-bits of offset for rdstate --- blech! */
++#define DIREOF (0xfffff)
++#define RDOFFBITS 20 /* This is the number of bits in DIREOF. */
++#define MAXRDCOOKIE (0xfff)
++/* Turn an rdstate into an offset. */
++static inline off_t rdstate2offset(struct unionfs_dir_state *buf)
++{
++ off_t tmp;
++
++ tmp = ((buf->cookie & MAXRDCOOKIE) << RDOFFBITS)
++ | (buf->offset & DIREOF);
++ return tmp;
++}
++
++/* Macros for locking a super_block. */
++enum unionfs_super_lock_class {
++ UNIONFS_SMUTEX_NORMAL,
++ UNIONFS_SMUTEX_PARENT, /* when locking on behalf of file */
++ UNIONFS_SMUTEX_CHILD, /* when locking on behalf of dentry */
++};
++static inline void unionfs_read_lock(struct super_block *sb, int subclass)
++{
++ if (UNIONFS_SB(sb)->write_lock_owner &&
++ UNIONFS_SB(sb)->write_lock_owner == current->pid)
++ return;
++ down_read_nested(&UNIONFS_SB(sb)->rwsem, subclass);
++}
++static inline void unionfs_read_unlock(struct super_block *sb)
++{
++ if (UNIONFS_SB(sb)->write_lock_owner &&
++ UNIONFS_SB(sb)->write_lock_owner == current->pid)
++ return;
++ up_read(&UNIONFS_SB(sb)->rwsem);
++}
++static inline void unionfs_write_lock(struct super_block *sb)
++{
++ down_write(&UNIONFS_SB(sb)->rwsem);
++ UNIONFS_SB(sb)->write_lock_owner = current->pid;
++}
++static inline void unionfs_write_unlock(struct super_block *sb)
++{
++ up_write(&UNIONFS_SB(sb)->rwsem);
++ UNIONFS_SB(sb)->write_lock_owner = 0;
++}
++
++static inline void unionfs_double_lock_dentry(struct dentry *d1,
++ struct dentry *d2)
++{
++ BUG_ON(d1 == d2);
++ if (d1 < d2) {
++ unionfs_lock_dentry(d1, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(d2, UNIONFS_DMUTEX_CHILD);
++ } else {
++ unionfs_lock_dentry(d2, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(d1, UNIONFS_DMUTEX_CHILD);
++ }
++}
++
++static inline void unionfs_double_unlock_dentry(struct dentry *d1,
++ struct dentry *d2)
++{
++ BUG_ON(d1 == d2);
++ if (d1 < d2) { /* unlock in reverse order than double_lock_dentry */
++ unionfs_unlock_dentry(d1);
++ unionfs_unlock_dentry(d2);
++ } else {
++ unionfs_unlock_dentry(d2);
++ unionfs_unlock_dentry(d1);
++ }
++}
++
++static inline void unionfs_double_lock_parents(struct dentry *p1,
++ struct dentry *p2)
++{
++ if (p1 == p2) {
++ unionfs_lock_dentry(p1, UNIONFS_DMUTEX_REVAL_PARENT);
++ return;
++ }
++ if (p1 < p2) {
++ unionfs_lock_dentry(p1, UNIONFS_DMUTEX_REVAL_PARENT);
++ unionfs_lock_dentry(p2, UNIONFS_DMUTEX_REVAL_CHILD);
++ } else {
++ unionfs_lock_dentry(p2, UNIONFS_DMUTEX_REVAL_PARENT);
++ unionfs_lock_dentry(p1, UNIONFS_DMUTEX_REVAL_CHILD);
++ }
++}
++
++static inline void unionfs_double_unlock_parents(struct dentry *p1,
++ struct dentry *p2)
++{
++ if (p1 == p2) {
++ unionfs_unlock_dentry(p1);
++ return;
++ }
++ if (p1 < p2) { /* unlock in reverse order of double_lock_parents */
++ unionfs_unlock_dentry(p1);
++ unionfs_unlock_dentry(p2);
++ } else {
++ unionfs_unlock_dentry(p2);
++ unionfs_unlock_dentry(p1);
++ }
++}
++
++extern int new_dentry_private_data(struct dentry *dentry, int subclass);
++extern int realloc_dentry_private_data(struct dentry *dentry);
++extern void free_dentry_private_data(struct dentry *dentry);
++extern void update_bstart(struct dentry *dentry);
++extern int init_lower_nd(struct nameidata *nd, unsigned int flags);
++extern void release_lower_nd(struct nameidata *nd, int err);
++
++/*
++ * EXTERNALS:
++ */
++
++/* replicates the directory structure up to given dentry in given branch */
++extern struct dentry *create_parents(struct inode *dir, struct dentry *dentry,
++ const char *name, int bindex);
++
++/* partial lookup */
++extern int unionfs_partial_lookup(struct dentry *dentry,
++ struct dentry *parent);
++extern struct dentry *unionfs_lookup_full(struct dentry *dentry,
++ struct dentry *parent,
++ int lookupmode);
++
++/* copies a file from dbstart to newbindex branch */
++extern int copyup_file(struct inode *dir, struct file *file, int bstart,
++ int newbindex, loff_t size);
++extern int copyup_named_file(struct inode *dir, struct file *file,
++ char *name, int bstart, int new_bindex,
++ loff_t len);
++/* copies a dentry from dbstart to newbindex branch */
++extern int copyup_dentry(struct inode *dir, struct dentry *dentry,
++ int bstart, int new_bindex, const char *name,
++ int namelen, struct file **copyup_file, loff_t len);
++/* helper functions for post-copyup actions */
++extern void unionfs_postcopyup_setmnt(struct dentry *dentry);
++extern void unionfs_postcopyup_release(struct dentry *dentry);
++
++/* Is this directory empty: 0 if it is empty, -ENOTEMPTY if not. */
++extern int check_empty(struct dentry *dentry, struct dentry *parent,
++ struct unionfs_dir_state **namelist);
++/* whiteout and opaque directory helpers */
++extern char *alloc_whname(const char *name, int len);
++extern bool is_whiteout_name(char **namep, int *namelenp);
++extern bool is_validname(const char *name);
++extern struct dentry *lookup_whiteout(const char *name,
++ struct dentry *lower_parent);
++extern struct dentry *find_first_whiteout(struct dentry *dentry);
++extern int unlink_whiteout(struct dentry *wh_dentry);
++extern int check_unlink_whiteout(struct dentry *dentry,
++ struct dentry *lower_dentry, int bindex);
++extern int create_whiteout(struct dentry *dentry, int start);
++extern int delete_whiteouts(struct dentry *dentry, int bindex,
++ struct unionfs_dir_state *namelist);
++extern int is_opaque_dir(struct dentry *dentry, int bindex);
++extern int make_dir_opaque(struct dentry *dir, int bindex);
++extern void unionfs_set_max_namelen(long *namelen);
++
++extern void unionfs_reinterpose(struct dentry *this_dentry);
++extern struct super_block *unionfs_duplicate_super(struct super_block *sb);
++
++/* Locking functions. */
++extern int unionfs_setlk(struct file *file, int cmd, struct file_lock *fl);
++extern int unionfs_getlk(struct file *file, struct file_lock *fl);
++
++/* Common file operations. */
++extern int unionfs_file_revalidate(struct file *file, struct dentry *parent,
++ bool willwrite);
++extern int unionfs_open(struct inode *inode, struct file *file);
++extern int unionfs_file_release(struct inode *inode, struct file *file);
++extern int unionfs_flush(struct file *file, fl_owner_t id);
++extern long unionfs_ioctl(struct file *file, unsigned int cmd,
++ unsigned long arg);
++extern int unionfs_fsync(struct file *file, int datasync);
++extern int unionfs_fasync(int fd, struct file *file, int flag);
++
++/* Inode operations */
++extern struct inode *unionfs_iget(struct super_block *sb, unsigned long ino);
++extern int unionfs_rename(struct inode *old_dir, struct dentry *old_dentry,
++ struct inode *new_dir, struct dentry *new_dentry);
++extern int unionfs_unlink(struct inode *dir, struct dentry *dentry);
++extern int unionfs_rmdir(struct inode *dir, struct dentry *dentry);
++
++extern bool __unionfs_d_revalidate(struct dentry *dentry,
++ struct dentry *parent, bool willwrite);
++extern bool is_negative_lower(const struct dentry *dentry);
++extern bool is_newer_lower(const struct dentry *dentry);
++extern void purge_sb_data(struct super_block *sb);
++
++/* The values for unionfs_interpose's flag. */
++#define INTERPOSE_DEFAULT 0
++#define INTERPOSE_LOOKUP 1
++#define INTERPOSE_REVAL 2
++#define INTERPOSE_REVAL_NEG 3
++#define INTERPOSE_PARTIAL 4
++
++extern struct dentry *unionfs_interpose(struct dentry *this_dentry,
++ struct super_block *sb, int flag);
++
++#ifdef CONFIG_UNION_FS_XATTR
++/* Extended attribute functions. */
++extern void *unionfs_xattr_alloc(size_t size, size_t limit);
++static inline void unionfs_xattr_kfree(const void *p)
++{
++ kfree(p);
++}
++extern ssize_t unionfs_getxattr(struct dentry *dentry, const char *name,
++ void *value, size_t size);
++extern int unionfs_removexattr(struct dentry *dentry, const char *name);
++extern ssize_t unionfs_listxattr(struct dentry *dentry, char *list,
++ size_t size);
++extern int unionfs_setxattr(struct dentry *dentry, const char *name,
++ const void *value, size_t size, int flags);
++#endif /* CONFIG_UNION_FS_XATTR */
++
++/* The root directory is unhashed, but isn't deleted. */
++static inline int d_deleted(struct dentry *d)
++{
++ return d_unhashed(d) && (d != d->d_sb->s_root);
++}
++
++/* unionfs_permission, check if we should bypass error to facilitate copyup */
++#define IS_COPYUP_ERR(err) ((err) == -EROFS)
++
++/* unionfs_open, check if we need to copyup the file */
++#define OPEN_WRITE_FLAGS (O_WRONLY | O_RDWR | O_APPEND)
++#define IS_WRITE_FLAG(flag) ((flag) & OPEN_WRITE_FLAGS)
++
++static inline int branchperms(const struct super_block *sb, int index)
++{
++ BUG_ON(index < 0);
++ return UNIONFS_SB(sb)->data[index].branchperms;
++}
++
++static inline int set_branchperms(struct super_block *sb, int index, int perms)
++{
++ BUG_ON(index < 0);
++ UNIONFS_SB(sb)->data[index].branchperms = perms;
++ return perms;
++}
++
++/* check if readonly lower inode, but possibly unlinked (no inode->i_sb) */
++static inline int __is_rdonly(const struct inode *inode)
++{
++ /* if unlinked, can't be readonly (?) */
++ if (!inode->i_sb)
++ return 0;
++ return IS_RDONLY(inode);
++
++}
++/* Is this file on a read-only branch? */
++static inline int is_robranch_super(const struct super_block *sb, int index)
++{
++ int ret;
++
++ ret = (!(branchperms(sb, index) & MAY_WRITE)) ? -EROFS : 0;
++ return ret;
++}
++
++/* Is this file on a read-only branch? */
++static inline int is_robranch_idx(const struct dentry *dentry, int index)
++{
++ struct super_block *lower_sb;
++
++ BUG_ON(index < 0);
++
++ if (!(branchperms(dentry->d_sb, index) & MAY_WRITE))
++ return -EROFS;
++
++ lower_sb = unionfs_lower_super_idx(dentry->d_sb, index);
++ BUG_ON(lower_sb == NULL);
++ /*
++ * test sb flags directly, not IS_RDONLY(lower_inode) because the
++ * lower_dentry could be a negative.
++ */
++ if (lower_sb->s_flags & MS_RDONLY)
++ return -EROFS;
++
++ return 0;
++}
++
++static inline int is_robranch(const struct dentry *dentry)
++{
++ int index;
++
++ index = UNIONFS_D(dentry)->bstart;
++ BUG_ON(index < 0);
++
++ return is_robranch_idx(dentry, index);
++}
++
++/*
++ * EXTERNALS:
++ */
++extern int check_branch(const struct path *path);
++extern int parse_branch_mode(const char *name, int *perms);
++
++/* locking helpers */
++static inline struct dentry *lock_parent(struct dentry *dentry)
++{
++ struct dentry *dir = dget_parent(dentry);
++ mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
++ return dir;
++}
++static inline struct dentry *lock_parent_wh(struct dentry *dentry)
++{
++ struct dentry *dir = dget_parent(dentry);
++
++ mutex_lock_nested(&dir->d_inode->i_mutex, UNIONFS_DMUTEX_WHITEOUT);
++ return dir;
++}
++
++static inline void unlock_dir(struct dentry *dir)
++{
++ mutex_unlock(&dir->d_inode->i_mutex);
++ dput(dir);
++}
++
++/* lock base inode mutex before calling lookup_one_len */
++static inline struct dentry *lookup_lck_len(const char *name,
++ struct dentry *base, int len)
++{
++ struct dentry *d;
++ struct nameidata lower_nd;
++ int err;
++
++ err = init_lower_nd(&lower_nd, LOOKUP_OPEN);
++ if (unlikely(err < 0)) {
++ d = ERR_PTR(err);
++ goto out;
++ }
++ mutex_lock(&base->d_inode->i_mutex);
++ d = lookup_one_len_nd(name, base, len, &lower_nd);
++ release_lower_nd(&lower_nd, err);
++ mutex_unlock(&base->d_inode->i_mutex);
++out:
++ return d;
++}
++
++static inline struct vfsmount *unionfs_mntget(struct dentry *dentry,
++ int bindex)
++{
++ struct vfsmount *mnt;
++
++ BUG_ON(!dentry || bindex < 0);
++
++ mnt = mntget(unionfs_lower_mnt_idx(dentry, bindex));
++#ifdef CONFIG_UNION_FS_DEBUG
++ if (!mnt)
++ pr_debug("unionfs: mntget: mnt=%p bindex=%d\n",
++ mnt, bindex);
++#endif /* CONFIG_UNION_FS_DEBUG */
++
++ return mnt;
++}
++
++static inline void unionfs_mntput(struct dentry *dentry, int bindex)
++{
++ struct vfsmount *mnt;
++
++ if (!dentry && bindex < 0)
++ return;
++ BUG_ON(!dentry || bindex < 0);
++
++ mnt = unionfs_lower_mnt_idx(dentry, bindex);
++#ifdef CONFIG_UNION_FS_DEBUG
++ /*
++ * Directories can have NULL lower objects in between start/end, but
++ * NOT if at the start/end range. We cannot verify that this dentry
++ * is a type=DIR, because it may already be a negative dentry. But
++ * if dbstart is greater than dbend, we know that this couldn't have
++ * been a regular file: it had to have been a directory.
++ */
++ if (!mnt && !(bindex > dbstart(dentry) && bindex < dbend(dentry)))
++ pr_debug("unionfs: mntput: mnt=%p bindex=%d\n", mnt, bindex);
++#endif /* CONFIG_UNION_FS_DEBUG */
++ mntput(mnt);
++}
++
++#ifdef CONFIG_UNION_FS_DEBUG
++
++/* useful for tracking code reachability */
++#define UDBG pr_debug("DBG:%s:%s:%d\n", __FILE__, __func__, __LINE__)
++
++#define unionfs_check_inode(i) __unionfs_check_inode((i), \
++ __FILE__, __func__, __LINE__)
++#define unionfs_check_dentry(d) __unionfs_check_dentry((d), \
++ __FILE__, __func__, __LINE__)
++#define unionfs_check_file(f) __unionfs_check_file((f), \
++ __FILE__, __func__, __LINE__)
++#define unionfs_check_nd(n) __unionfs_check_nd((n), \
++ __FILE__, __func__, __LINE__)
++#define show_branch_counts(sb) __show_branch_counts((sb), \
++ __FILE__, __func__, __LINE__)
++#define show_inode_times(i) __show_inode_times((i), \
++ __FILE__, __func__, __LINE__)
++#define show_dinode_times(d) __show_dinode_times((d), \
++ __FILE__, __func__, __LINE__)
++#define show_inode_counts(i) __show_inode_counts((i), \
++ __FILE__, __func__, __LINE__)
++
++extern void __unionfs_check_inode(const struct inode *inode, const char *fname,
++ const char *fxn, int line);
++extern void __unionfs_check_dentry(const struct dentry *dentry,
++ const char *fname, const char *fxn,
++ int line);
++extern void __unionfs_check_file(const struct file *file,
++ const char *fname, const char *fxn, int line);
++extern void __unionfs_check_nd(const struct nameidata *nd,
++ const char *fname, const char *fxn, int line);
++extern void __show_branch_counts(const struct super_block *sb,
++ const char *file, const char *fxn, int line);
++extern void __show_inode_times(const struct inode *inode,
++ const char *file, const char *fxn, int line);
++extern void __show_dinode_times(const struct dentry *dentry,
++ const char *file, const char *fxn, int line);
++extern void __show_inode_counts(const struct inode *inode,
++ const char *file, const char *fxn, int line);
++
++#else /* not CONFIG_UNION_FS_DEBUG */
++
++/* we leave useful hooks for these check functions throughout the code */
++#define unionfs_check_inode(i) do { } while (0)
++#define unionfs_check_dentry(d) do { } while (0)
++#define unionfs_check_file(f) do { } while (0)
++#define unionfs_check_nd(n) do { } while (0)
++#define show_branch_counts(sb) do { } while (0)
++#define show_inode_times(i) do { } while (0)
++#define show_dinode_times(d) do { } while (0)
++#define show_inode_counts(i) do { } while (0)
++
++#endif /* not CONFIG_UNION_FS_DEBUG */
++
++#endif /* not _UNION_H_ */
+diff --git a/fs/unionfs/unlink.c b/fs/unionfs/unlink.c
+new file mode 100644
+index 0000000..bf447bb
+--- /dev/null
++++ b/fs/unionfs/unlink.c
+@@ -0,0 +1,278 @@
++/*
++ * Copyright (c) 2003-2011 Erez Zadok
++ * Copyright (c) 2003-2006 Charles P. Wright
++ * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
++ * Copyright (c) 2005-2006 Junjiro Okajima
++ * Copyright (c) 2005 Arun M. Krishnakumar
++ * Copyright (c) 2004-2006 David P. Quigley
++ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
++ * Copyright (c) 2003 Puja Gupta
++ * Copyright (c) 2003 Harikesavan Krishnan
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 The Research Foundation of SUNY
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "union.h"
++
++/*
++ * Helper function for Unionfs's unlink operation.
++ *
++ * The main goal of this function is to optimize the unlinking of non-dir
++ * objects in unionfs by deleting all possible lower inode objects from the
++ * underlying branches having same dentry name as the non-dir dentry on
++ * which this unlink operation is called. This way we delete as many lower
++ * inodes as possible, and save space. Whiteouts need to be created in
++ * branch0 only if unlinking fails on any of the lower branch other than
++ * branch0, or if a lower branch is marked read-only.
++ *
++ * Also, while unlinking a file, if we encounter any dir type entry in any
++ * intermediate branch, then we remove the directory by calling vfs_rmdir.
++ * The following special cases are also handled:
++
++ * (1) If an error occurs in branch0 during vfs_unlink, then we return
++ * appropriate error.
++ *
++ * (2) If we get an error during unlink in any of other lower branch other
++ * than branch0, then we create a whiteout in branch0.
++ *
++ * (3) If a whiteout already exists in any intermediate branch, we delete
++ * all possible inodes only up to that branch (this is an "opaqueness"
++ * as as per Documentation/filesystems/unionfs/concepts.txt).
++ *
++ */
++static int unionfs_unlink_whiteout(struct inode *dir, struct dentry *dentry,
++ struct dentry *parent)
++{
++ struct dentry *lower_dentry;
++ struct dentry *lower_dir_dentry;
++ int bindex;
++ int err = 0;
++
++ err = unionfs_partial_lookup(dentry, parent);
++ if (err)
++ goto out;
++
++ /* trying to unlink all possible valid instances */
++ for (bindex = dbstart(dentry); bindex <= dbend(dentry); bindex++) {
++ lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
++ if (!lower_dentry || !lower_dentry->d_inode)
++ continue;
++
++ lower_dir_dentry = lock_parent(lower_dentry);
++
++ /* avoid destroying the lower inode if the object is in use */
++ dget(lower_dentry);
++ err = is_robranch_super(dentry->d_sb, bindex);
++ if (!err) {
++ /* see Documentation/filesystems/unionfs/issues.txt */
++ lockdep_off();
++ if (!S_ISDIR(lower_dentry->d_inode->i_mode))
++ err = vfs_unlink(lower_dir_dentry->d_inode,
++ lower_dentry);
++ else
++ err = vfs_rmdir(lower_dir_dentry->d_inode,
++ lower_dentry);
++ lockdep_on();
++ }
++
++ /* if lower object deletion succeeds, update inode's times */
++ if (!err)
++ unionfs_copy_attr_times(dentry->d_inode);
++ dput(lower_dentry);
++ fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
++ unlock_dir(lower_dir_dentry);
++
++ if (err)
++ break;
++ }
++
++ /*
++ * Create the whiteout in branch 0 (highest priority) only if (a)
++ * there was an error in any intermediate branch other than branch 0
++ * due to failure of vfs_unlink/vfs_rmdir or (b) a branch marked or
++ * mounted read-only.
++ */
++ if (err) {
++ if ((bindex == 0) ||
++ ((bindex == dbstart(dentry)) &&
++ (!IS_COPYUP_ERR(err))))
++ goto out;
++ else {
++ if (!IS_COPYUP_ERR(err))
++ pr_debug("unionfs: lower object deletion "
++ "failed in branch:%d\n", bindex);
++ err = create_whiteout(dentry, sbstart(dentry->d_sb));
++ }
++ }
++
++out:
++ if (!err)
++ inode_dec_link_count(dentry->d_inode);
++
++ /* We don't want to leave negative leftover dentries for revalidate. */
++ if (!err && (dbopaque(dentry) != -1))
++ update_bstart(dentry);
++
++ return err;
++}
++
++int unionfs_unlink(struct inode *dir, struct dentry *dentry)
++{
++ int err = 0;
++ struct inode *inode = dentry->d_inode;
++ struct dentry *parent;
++ int valid;
++
++ BUG_ON(S_ISDIR(inode->i_mode));
++ unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD);
++ parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ valid = __unionfs_d_revalidate(dentry, parent, false);
++ if (unlikely(!valid)) {
++ err = -ESTALE;
++ goto out;
++ }
++ unionfs_check_dentry(dentry);
++
++ err = unionfs_unlink_whiteout(dir, dentry, parent);
++ /* call d_drop so the system "forgets" about us */
++ if (!err) {
++ unionfs_postcopyup_release(dentry);
++ unionfs_postcopyup_setmnt(parent);
++ if (inode->i_nlink == 0) /* drop lower inodes */
++ iput_lowers_all(inode, false);
++ d_drop(dentry);
++ /*
++ * if unlink/whiteout succeeded, parent dir mtime has
++ * changed
++ */
++ unionfs_copy_attr_times(dir);
++ }
++
++out:
++ if (!err) {
++ unionfs_check_dentry(dentry);
++ unionfs_check_inode(dir);
++ }
++ unionfs_unlock_dentry(dentry);
++ unionfs_unlock_parent(dentry, parent);
++ unionfs_read_unlock(dentry->d_sb);
++ return err;
++}
++
++static int unionfs_rmdir_first(struct inode *dir, struct dentry *dentry,
++ struct unionfs_dir_state *namelist)
++{
++ int err;
++ struct dentry *lower_dentry;
++ struct dentry *lower_dir_dentry = NULL;
++
++ /* Here we need to remove whiteout entries. */
++ err = delete_whiteouts(dentry, dbstart(dentry), namelist);
++ if (err)
++ goto out;
++
++ lower_dentry = unionfs_lower_dentry(dentry);
++
++ lower_dir_dentry = lock_parent(lower_dentry);
++
++ /* avoid destroying the lower inode if the file is in use */
++ dget(lower_dentry);
++ err = is_robranch(dentry);
++ if (!err)
++ err = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry);
++ dput(lower_dentry);
++
++ fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
++ /* propagate number of hard-links */
++ dentry->d_inode->i_nlink = unionfs_get_nlinks(dentry->d_inode);
++
++out:
++ if (lower_dir_dentry)
++ unlock_dir(lower_dir_dentry);
++ return err;
++}
++
++int unionfs_rmdir(struct inode *dir, struct dentry *dentry)
++{
++ int err = 0;
++ struct unionfs_dir_state *namelist = NULL;
++ struct dentry *parent;
++ int dstart, dend;
++ bool valid;
++
++ unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD);
++ parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ valid = __unionfs_d_revalidate(dentry, parent, false);
++ if (unlikely(!valid)) {
++ err = -ESTALE;
++ goto out;
++ }
++ unionfs_check_dentry(dentry);
++
++ /* check if this unionfs directory is empty or not */
++ err = check_empty(dentry, parent, &namelist);
++ if (err)
++ goto out;
++
++ err = unionfs_rmdir_first(dir, dentry, namelist);
++ dstart = dbstart(dentry);
++ dend = dbend(dentry);
++ /*
++ * We create a whiteout for the directory if there was an error to
++ * rmdir the first directory entry in the union. Otherwise, we
++ * create a whiteout only if there is no chance that a lower
++ * priority branch might also have the same named directory. IOW,
++ * if there is not another same-named directory at a lower priority
++ * branch, then we don't need to create a whiteout for it.
++ */
++ if (!err) {
++ if (dstart < dend)
++ err = create_whiteout(dentry, dstart);
++ } else {
++ int new_err;
++
++ if (dstart == 0)
++ goto out;
++
++ /* exit if the error returned was NOT -EROFS */
++ if (!IS_COPYUP_ERR(err))
++ goto out;
++
++ new_err = create_whiteout(dentry, dstart - 1);
++ if (new_err != -EEXIST)
++ err = new_err;
++ }
++
++out:
++ /*
++ * Drop references to lower dentry/inode so storage space for them
++ * can be reclaimed. Then, call d_drop so the system "forgets"
++ * about us.
++ */
++ if (!err) {
++ iput_lowers_all(dentry->d_inode, false);
++ dput(unionfs_lower_dentry_idx(dentry, dstart));
++ unionfs_set_lower_dentry_idx(dentry, dstart, NULL);
++ d_drop(dentry);
++ /* update our lower vfsmnts, in case a copyup took place */
++ unionfs_postcopyup_setmnt(dentry);
++ unionfs_check_dentry(dentry);
++ unionfs_check_inode(dir);
++ }
++
++ if (namelist)
++ free_rdstate(namelist);
++
++ unionfs_unlock_dentry(dentry);
++ unionfs_unlock_parent(dentry, parent);
++ unionfs_read_unlock(dentry->d_sb);
++ return err;
++}
+diff --git a/fs/unionfs/whiteout.c b/fs/unionfs/whiteout.c
+new file mode 100644
+index 0000000..582cef2
+--- /dev/null
++++ b/fs/unionfs/whiteout.c
+@@ -0,0 +1,601 @@
++/*
++ * Copyright (c) 2003-2011 Erez Zadok
++ * Copyright (c) 2003-2006 Charles P. Wright
++ * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
++ * Copyright (c) 2005-2006 Junjiro Okajima
++ * Copyright (c) 2005 Arun M. Krishnakumar
++ * Copyright (c) 2004-2006 David P. Quigley
++ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
++ * Copyright (c) 2003 Puja Gupta
++ * Copyright (c) 2003 Harikesavan Krishnan
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 The Research Foundation of SUNY
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "union.h"
++
++/*
++ * whiteout and opaque directory helpers
++ */
++
++/* What do we use for whiteouts. */
++#define UNIONFS_WHPFX ".wh."
++#define UNIONFS_WHLEN 4
++/*
++ * If a directory contains this file, then it is opaque. We start with the
++ * .wh. flag so that it is blocked by lookup.
++ */
++#define UNIONFS_DIR_OPAQUE_NAME "__dir_opaque"
++#define UNIONFS_DIR_OPAQUE UNIONFS_WHPFX UNIONFS_DIR_OPAQUE_NAME
++
++/* construct whiteout filename */
++char *alloc_whname(const char *name, int len)
++{
++ char *buf;
++
++ buf = kmalloc(len + UNIONFS_WHLEN + 1, GFP_KERNEL);
++ if (unlikely(!buf))
++ return ERR_PTR(-ENOMEM);
++
++ strcpy(buf, UNIONFS_WHPFX);
++ strlcat(buf, name, len + UNIONFS_WHLEN + 1);
++
++ return buf;
++}
++
++/*
++ * XXX: this can be inline or CPP macro, but is here to keep all whiteout
++ * code in one place.
++ */
++void unionfs_set_max_namelen(long *namelen)
++{
++ *namelen -= UNIONFS_WHLEN;
++}
++
++/* check if @namep is a whiteout, update @namep and @namelenp accordingly */
++bool is_whiteout_name(char **namep, int *namelenp)
++{
++ if (*namelenp > UNIONFS_WHLEN &&
++ !strncmp(*namep, UNIONFS_WHPFX, UNIONFS_WHLEN)) {
++ *namep += UNIONFS_WHLEN;
++ *namelenp -= UNIONFS_WHLEN;
++ return true;
++ }
++ return false;
++}
++
++/* is the filename valid == !(whiteout for a file or opaque dir marker) */
++bool is_validname(const char *name)
++{
++ if (!strncmp(name, UNIONFS_WHPFX, UNIONFS_WHLEN))
++ return false;
++ if (!strncmp(name, UNIONFS_DIR_OPAQUE_NAME,
++ sizeof(UNIONFS_DIR_OPAQUE_NAME) - 1))
++ return false;
++ return true;
++}
++
++/*
++ * Look for a whiteout @name in @lower_parent directory. If error, return
++ * ERR_PTR. Caller must dput() the returned dentry if not an error.
++ *
++ * XXX: some callers can reuse the whname allocated buffer to avoid repeated
++ * free then re-malloc calls. Need to provide a different API for those
++ * callers.
++ */
++struct dentry *lookup_whiteout(const char *name, struct dentry *lower_parent)
++{
++ char *whname = NULL;
++ int err = 0, namelen;
++ struct dentry *wh_dentry = NULL;
++
++ namelen = strlen(name);
++ whname = alloc_whname(name, namelen);
++ if (unlikely(IS_ERR(whname))) {
++ err = PTR_ERR(whname);
++ goto out;
++ }
++
++ /* check if whiteout exists in this branch: lookup .wh.foo */
++ wh_dentry = lookup_lck_len(whname, lower_parent, strlen(whname));
++ if (IS_ERR(wh_dentry)) {
++ err = PTR_ERR(wh_dentry);
++ goto out;
++ }
++
++ /* check if negative dentry (ENOENT) */
++ if (!wh_dentry->d_inode)
++ goto out;
++
++ /* whiteout found: check if valid type */
++ if (!S_ISREG(wh_dentry->d_inode->i_mode)) {
++ printk(KERN_ERR "unionfs: invalid whiteout %s entry type %d\n",
++ whname, wh_dentry->d_inode->i_mode);
++ dput(wh_dentry);
++ err = -EIO;
++ goto out;
++ }
++
++out:
++ kfree(whname);
++ if (err)
++ wh_dentry = ERR_PTR(err);
++ return wh_dentry;
++}
++
++/* find and return first whiteout in parent directory, else ENOENT */
++struct dentry *find_first_whiteout(struct dentry *dentry)
++{
++ int bindex, bstart, bend;
++ struct dentry *parent, *lower_parent, *wh_dentry;
++
++ parent = dget_parent(dentry);
++
++ bstart = dbstart(parent);
++ bend = dbend(parent);
++ wh_dentry = ERR_PTR(-ENOENT);
++
++ for (bindex = bstart; bindex <= bend; bindex++) {
++ lower_parent = unionfs_lower_dentry_idx(parent, bindex);
++ if (!lower_parent)
++ continue;
++ wh_dentry = lookup_whiteout(dentry->d_name.name, lower_parent);
++ if (IS_ERR(wh_dentry))
++ continue;
++ if (wh_dentry->d_inode)
++ break;
++ dput(wh_dentry);
++ wh_dentry = ERR_PTR(-ENOENT);
++ }
++
++ dput(parent);
++
++ return wh_dentry;
++}
++
++/*
++ * Unlink a whiteout dentry. Returns 0 or -errno. Caller must hold and
++ * release dentry reference.
++ */
++int unlink_whiteout(struct dentry *wh_dentry)
++{
++ int err;
++ struct dentry *lower_dir_dentry;
++
++ /* dget and lock parent dentry */
++ lower_dir_dentry = lock_parent_wh(wh_dentry);
++
++ /* see Documentation/filesystems/unionfs/issues.txt */
++ lockdep_off();
++ err = vfs_unlink(lower_dir_dentry->d_inode, wh_dentry);
++ lockdep_on();
++ unlock_dir(lower_dir_dentry);
++
++ /*
++ * Whiteouts are special files and should be deleted no matter what
++ * (as if they never existed), in order to allow this create
++ * operation to succeed. This is especially important in sticky
++ * directories: a whiteout may have been created by one user, but
++ * the newly created file may be created by another user.
++ * Therefore, in order to maintain Unix semantics, if the vfs_unlink
++ * above failed, then we have to try to directly unlink the
++ * whiteout. Note: in the ODF version of unionfs, whiteout are
++ * handled much more cleanly.
++ */
++ if (err == -EPERM) {
++ struct inode *inode = lower_dir_dentry->d_inode;
++ err = inode->i_op->unlink(inode, wh_dentry);
++ }
++ if (err)
++ printk(KERN_ERR "unionfs: could not unlink whiteout %s, "
++ "err = %d\n", wh_dentry->d_name.name, err);
++
++ return err;
++
++}
++
++/*
++ * Helper function when creating new objects (create, symlink, mknod, etc.).
++ * Checks to see if there's a whiteout in @lower_dentry's parent directory,
++ * whose name is taken from @dentry. Then tries to remove that whiteout, if
++ * found. If <dentry,bindex> is a branch marked readonly, return -EROFS.
++ * If it finds both a regular file and a whiteout, delete whiteout (this
++ * should never happen).
++ *
++ * Return 0 if no whiteout was found. Return 1 if one was found and
++ * successfully removed. Therefore a value >= 0 tells the caller that
++ * @lower_dentry belongs to a good branch to create the new object in).
++ * Return -ERRNO if an error occurred during whiteout lookup or in trying to
++ * unlink the whiteout.
++ */
++int check_unlink_whiteout(struct dentry *dentry, struct dentry *lower_dentry,
++ int bindex)
++{
++ int err;
++ struct dentry *wh_dentry = NULL;
++ struct dentry *lower_dir_dentry = NULL;
++
++ /* look for whiteout dentry first */
++ lower_dir_dentry = dget_parent(lower_dentry);
++ wh_dentry = lookup_whiteout(dentry->d_name.name, lower_dir_dentry);
++ dput(lower_dir_dentry);
++ if (IS_ERR(wh_dentry)) {
++ err = PTR_ERR(wh_dentry);
++ goto out;
++ }
++
++ if (!wh_dentry->d_inode) { /* no whiteout exists*/
++ err = 0;
++ goto out_dput;
++ }
++
++ /* check if regular file and whiteout were both found */
++ if (unlikely(lower_dentry->d_inode))
++ printk(KERN_WARNING "unionfs: removing whiteout; regular "
++ "file exists in directory %s (branch %d)\n",
++ lower_dir_dentry->d_name.name, bindex);
++
++ /* check if branch is writeable */
++ err = is_robranch_super(dentry->d_sb, bindex);
++ if (err)
++ goto out_dput;
++
++ /* .wh.foo has been found, so let's unlink it */
++ err = unlink_whiteout(wh_dentry);
++ if (!err)
++ err = 1; /* a whiteout was found and successfully removed */
++out_dput:
++ dput(wh_dentry);
++out:
++ return err;
++}
++
++/*
++ * Pass an unionfs dentry and an index. It will try to create a whiteout
++ * for the filename in dentry, and will try in branch 'index'. On error,
++ * it will proceed to a branch to the left.
++ */
++int create_whiteout(struct dentry *dentry, int start)
++{
++ int bstart, bend, bindex;
++ struct dentry *lower_dir_dentry;
++ struct dentry *lower_dentry;
++ struct dentry *lower_wh_dentry;
++ struct nameidata nd;
++ char *name = NULL;
++ int err = -EINVAL;
++
++ verify_locked(dentry);
++
++ bstart = dbstart(dentry);
++ bend = dbend(dentry);
++
++ /* create dentry's whiteout equivalent */
++ name = alloc_whname(dentry->d_name.name, dentry->d_name.len);
++ if (unlikely(IS_ERR(name))) {
++ err = PTR_ERR(name);
++ goto out;
++ }
++
++ for (bindex = start; bindex >= 0; bindex--) {
++ lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
++
++ if (!lower_dentry) {
++ /*
++ * if lower dentry is not present, create the
++ * entire lower dentry directory structure and go
++ * ahead. Since we want to just create whiteout, we
++ * only want the parent dentry, and hence get rid of
++ * this dentry.
++ */
++ lower_dentry = create_parents(dentry->d_inode,
++ dentry,
++ dentry->d_name.name,
++ bindex);
++ if (!lower_dentry || IS_ERR(lower_dentry)) {
++ int ret = PTR_ERR(lower_dentry);
++ if (!IS_COPYUP_ERR(ret))
++ printk(KERN_ERR
++ "unionfs: create_parents for "
++ "whiteout failed: bindex=%d "
++ "err=%d\n", bindex, ret);
++ continue;
++ }
++ }
++
++ lower_wh_dentry =
++ lookup_lck_len(name, lower_dentry->d_parent,
++ dentry->d_name.len + UNIONFS_WHLEN);
++ if (IS_ERR(lower_wh_dentry))
++ continue;
++
++ /*
++ * The whiteout already exists. This used to be impossible,
++ * but now is possible because of opaqueness.
++ */
++ if (lower_wh_dentry->d_inode) {
++ dput(lower_wh_dentry);
++ err = 0;
++ goto out;
++ }
++
++ err = init_lower_nd(&nd, LOOKUP_CREATE);
++ if (unlikely(err < 0))
++ goto out;
++ lower_dir_dentry = lock_parent_wh(lower_wh_dentry);
++ err = is_robranch_super(dentry->d_sb, bindex);
++ if (!err)
++ err = vfs_create(lower_dir_dentry->d_inode,
++ lower_wh_dentry,
++ current_umask() & S_IRUGO,
++ &nd);
++ unlock_dir(lower_dir_dentry);
++ dput(lower_wh_dentry);
++ release_lower_nd(&nd, err);
++
++ if (!err || !IS_COPYUP_ERR(err))
++ break;
++ }
++
++ /* set dbopaque so that lookup will not proceed after this branch */
++ if (!err)
++ dbopaque(dentry) = bindex;
++
++out:
++ kfree(name);
++ return err;
++}
++
++/*
++ * Delete all of the whiteouts in a given directory for rmdir.
++ *
++ * lower directory inode should be locked
++ */
++static int do_delete_whiteouts(struct dentry *dentry, int bindex,
++ struct unionfs_dir_state *namelist)
++{
++ int err = 0;
++ struct dentry *lower_dir_dentry = NULL;
++ struct dentry *lower_dentry;
++ char *name = NULL, *p;
++ struct inode *lower_dir;
++ int i;
++ struct list_head *pos;
++ struct filldir_node *cursor;
++
++ /* Find out lower parent dentry */
++ lower_dir_dentry = unionfs_lower_dentry_idx(dentry, bindex);
++ BUG_ON(!S_ISDIR(lower_dir_dentry->d_inode->i_mode));
++ lower_dir = lower_dir_dentry->d_inode;
++ BUG_ON(!S_ISDIR(lower_dir->i_mode));
++
++ err = -ENOMEM;
++ name = __getname();
++ if (unlikely(!name))
++ goto out;
++ strcpy(name, UNIONFS_WHPFX);
++ p = name + UNIONFS_WHLEN;
++
++ err = 0;
++ for (i = 0; !err && i < namelist->size; i++) {
++ list_for_each(pos, &namelist->list[i]) {
++ cursor =
++ list_entry(pos, struct filldir_node,
++ file_list);
++ /* Only operate on whiteouts in this branch. */
++ if (cursor->bindex != bindex)
++ continue;
++ if (!cursor->whiteout)
++ continue;
++
++ strlcpy(p, cursor->name, PATH_MAX - UNIONFS_WHLEN);
++ lower_dentry =
++ lookup_lck_len(name, lower_dir_dentry,
++ cursor->namelen +
++ UNIONFS_WHLEN);
++ if (IS_ERR(lower_dentry)) {
++ err = PTR_ERR(lower_dentry);
++ break;
++ }
++ if (lower_dentry->d_inode)
++ err = vfs_unlink(lower_dir, lower_dentry);
++ dput(lower_dentry);
++ if (err)
++ break;
++ }
++ }
++
++ __putname(name);
++
++ /* After all of the removals, we should copy the attributes once. */
++ fsstack_copy_attr_times(dentry->d_inode, lower_dir_dentry->d_inode);
++
++out:
++ return err;
++}
++
++
++void __delete_whiteouts(struct work_struct *work)
++{
++ struct sioq_args *args = container_of(work, struct sioq_args, work);
++ struct deletewh_args *d = &args->deletewh;
++
++ args->err = do_delete_whiteouts(d->dentry, d->bindex, d->namelist);
++ complete(&args->comp);
++}
++
++/* delete whiteouts in a dir (for rmdir operation) using sioq if necessary */
++int delete_whiteouts(struct dentry *dentry, int bindex,
++ struct unionfs_dir_state *namelist)
++{
++ int err;
++ struct super_block *sb;
++ struct dentry *lower_dir_dentry;
++ struct inode *lower_dir;
++ struct sioq_args args;
++
++ sb = dentry->d_sb;
++
++ BUG_ON(!S_ISDIR(dentry->d_inode->i_mode));
++ BUG_ON(bindex < dbstart(dentry));
++ BUG_ON(bindex > dbend(dentry));
++ err = is_robranch_super(sb, bindex);
++ if (err)
++ goto out;
++
++ lower_dir_dentry = unionfs_lower_dentry_idx(dentry, bindex);
++ BUG_ON(!S_ISDIR(lower_dir_dentry->d_inode->i_mode));
++ lower_dir = lower_dir_dentry->d_inode;
++ BUG_ON(!S_ISDIR(lower_dir->i_mode));
++
++ if (!inode_permission(lower_dir, MAY_WRITE | MAY_EXEC)) {
++ err = do_delete_whiteouts(dentry, bindex, namelist);
++ } else {
++ args.deletewh.namelist = namelist;
++ args.deletewh.dentry = dentry;
++ args.deletewh.bindex = bindex;
++ run_sioq(__delete_whiteouts, &args);
++ err = args.err;
++ }
++
++out:
++ return err;
++}
++
++/****************************************************************************
++ * Opaque directory helpers *
++ ****************************************************************************/
++
++/*
++ * is_opaque_dir: returns 0 if it is NOT an opaque dir, 1 if it is, and
++ * -errno if an error occurred trying to figure this out.
++ */
++int is_opaque_dir(struct dentry *dentry, int bindex)
++{
++ int err = 0;
++ struct dentry *lower_dentry;
++ struct dentry *wh_lower_dentry;
++ struct inode *lower_inode;
++ struct sioq_args args;
++ struct nameidata lower_nd;
++
++ lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
++ lower_inode = lower_dentry->d_inode;
++
++ BUG_ON(!S_ISDIR(lower_inode->i_mode));
++
++ mutex_lock(&lower_inode->i_mutex);
++
++ if (!inode_permission(lower_inode, MAY_EXEC)) {
++ err = init_lower_nd(&lower_nd, LOOKUP_OPEN);
++ if (unlikely(err < 0)) {
++ mutex_unlock(&lower_inode->i_mutex);
++ goto out;
++ }
++ wh_lower_dentry =
++ lookup_one_len_nd(UNIONFS_DIR_OPAQUE, lower_dentry,
++ sizeof(UNIONFS_DIR_OPAQUE) - 1,
++ &lower_nd);
++ release_lower_nd(&lower_nd, err);
++ } else {
++ args.is_opaque.dentry = lower_dentry;
++ run_sioq(__is_opaque_dir, &args);
++ wh_lower_dentry = args.ret;
++ }
++
++ mutex_unlock(&lower_inode->i_mutex);
++
++ if (IS_ERR(wh_lower_dentry)) {
++ err = PTR_ERR(wh_lower_dentry);
++ goto out;
++ }
++
++ /* This is an opaque dir iff wh_lower_dentry is positive */
++ err = !!wh_lower_dentry->d_inode;
++
++ dput(wh_lower_dentry);
++out:
++ return err;
++}
++
++void __is_opaque_dir(struct work_struct *work)
++{
++ struct sioq_args *args = container_of(work, struct sioq_args, work);
++ struct nameidata lower_nd;
++ int err;
++
++ err = init_lower_nd(&lower_nd, LOOKUP_OPEN);
++ if (unlikely(err < 0))
++ return;
++ args->ret = lookup_one_len_nd(UNIONFS_DIR_OPAQUE,
++ args->is_opaque.dentry,
++ sizeof(UNIONFS_DIR_OPAQUE) - 1,
++ &lower_nd);
++ release_lower_nd(&lower_nd, err);
++ complete(&args->comp);
++}
++
++int make_dir_opaque(struct dentry *dentry, int bindex)
++{
++ int err = 0;
++ struct dentry *lower_dentry, *diropq;
++ struct inode *lower_dir;
++ struct nameidata nd;
++ const struct cred *old_creds;
++ struct cred *new_creds;
++
++ /*
++ * Opaque directory whiteout markers are special files (like regular
++ * whiteouts), and should appear to the users as if they don't
++ * exist. They should be created/deleted regardless of directory
++ * search/create permissions, but only for the duration of this
++ * creation of the .wh.__dir_opaque: file. Note, this does not
++ * circumvent normal ->permission).
++ */
++ new_creds = prepare_creds();
++ if (unlikely(!new_creds)) {
++ err = -ENOMEM;
++ goto out_err;
++ }
++ cap_raise(new_creds->cap_effective, CAP_DAC_READ_SEARCH);
++ cap_raise(new_creds->cap_effective, CAP_DAC_OVERRIDE);
++ old_creds = override_creds(new_creds);
++
++ lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
++ lower_dir = lower_dentry->d_inode;
++ BUG_ON(!S_ISDIR(dentry->d_inode->i_mode) ||
++ !S_ISDIR(lower_dir->i_mode));
++
++ mutex_lock(&lower_dir->i_mutex);
++ err = init_lower_nd(&nd, LOOKUP_OPEN);
++ if (unlikely(err < 0))
++ goto out;
++ diropq = lookup_one_len_nd(UNIONFS_DIR_OPAQUE, lower_dentry,
++ sizeof(UNIONFS_DIR_OPAQUE) - 1, &nd);
++ release_lower_nd(&nd, err);
++ if (IS_ERR(diropq)) {
++ err = PTR_ERR(diropq);
++ goto out;
++ }
++
++ err = init_lower_nd(&nd, LOOKUP_CREATE);
++ if (unlikely(err < 0))
++ goto out;
++ if (!diropq->d_inode)
++ err = vfs_create(lower_dir, diropq, S_IRUGO, &nd);
++ if (!err)
++ dbopaque(dentry) = bindex;
++ release_lower_nd(&nd, err);
++
++ dput(diropq);
++
++out:
++ mutex_unlock(&lower_dir->i_mutex);
++ revert_creds(old_creds);
++out_err:
++ return err;
++}
+diff --git a/fs/unionfs/xattr.c b/fs/unionfs/xattr.c
+new file mode 100644
+index 0000000..a93d803
+--- /dev/null
++++ b/fs/unionfs/xattr.c
+@@ -0,0 +1,173 @@
++/*
++ * Copyright (c) 2003-2011 Erez Zadok
++ * Copyright (c) 2003-2006 Charles P. Wright
++ * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
++ * Copyright (c) 2005-2006 Junjiro Okajima
++ * Copyright (c) 2005 Arun M. Krishnakumar
++ * Copyright (c) 2004-2006 David P. Quigley
++ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
++ * Copyright (c) 2003 Puja Gupta
++ * Copyright (c) 2003 Harikesavan Krishnan
++ * Copyright (c) 2003-2011 Stony Brook University
++ * Copyright (c) 2003-2011 The Research Foundation of SUNY
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "union.h"
++
++/* This is lifted from fs/xattr.c */
++void *unionfs_xattr_alloc(size_t size, size_t limit)
++{
++ void *ptr;
++
++ if (size > limit)
++ return ERR_PTR(-E2BIG);
++
++ if (!size) /* size request, no buffer is needed */
++ return NULL;
++
++ ptr = kmalloc(size, GFP_KERNEL);
++ if (unlikely(!ptr))
++ return ERR_PTR(-ENOMEM);
++ return ptr;
++}
++
++/*
++ * BKL held by caller.
++ * dentry->d_inode->i_mutex locked
++ */
++ssize_t unionfs_getxattr(struct dentry *dentry, const char *name, void *value,
++ size_t size)
++{
++ struct dentry *lower_dentry = NULL;
++ struct dentry *parent;
++ int err = -EOPNOTSUPP;
++ bool valid;
++
++ unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD);
++ parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ valid = __unionfs_d_revalidate(dentry, parent, false);
++ if (unlikely(!valid)) {
++ err = -ESTALE;
++ goto out;
++ }
++
++ lower_dentry = unionfs_lower_dentry(dentry);
++
++ err = vfs_getxattr(lower_dentry, (char *) name, value, size);
++
++out:
++ unionfs_check_dentry(dentry);
++ unionfs_unlock_dentry(dentry);
++ unionfs_unlock_parent(dentry, parent);
++ unionfs_read_unlock(dentry->d_sb);
++ return err;
++}
++
++/*
++ * BKL held by caller.
++ * dentry->d_inode->i_mutex locked
++ */
++int unionfs_setxattr(struct dentry *dentry, const char *name,
++ const void *value, size_t size, int flags)
++{
++ struct dentry *lower_dentry = NULL;
++ struct dentry *parent;
++ int err = -EOPNOTSUPP;
++ bool valid;
++
++ unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD);
++ parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ valid = __unionfs_d_revalidate(dentry, parent, false);
++ if (unlikely(!valid)) {
++ err = -ESTALE;
++ goto out;
++ }
++
++ lower_dentry = unionfs_lower_dentry(dentry);
++
++ err = vfs_setxattr(lower_dentry, (char *) name, (void *) value,
++ size, flags);
++
++out:
++ unionfs_check_dentry(dentry);
++ unionfs_unlock_dentry(dentry);
++ unionfs_unlock_parent(dentry, parent);
++ unionfs_read_unlock(dentry->d_sb);
++ return err;
++}
++
++/*
++ * BKL held by caller.
++ * dentry->d_inode->i_mutex locked
++ */
++int unionfs_removexattr(struct dentry *dentry, const char *name)
++{
++ struct dentry *lower_dentry = NULL;
++ struct dentry *parent;
++ int err = -EOPNOTSUPP;
++ bool valid;
++
++ unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD);
++ parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ valid = __unionfs_d_revalidate(dentry, parent, false);
++ if (unlikely(!valid)) {
++ err = -ESTALE;
++ goto out;
++ }
++
++ lower_dentry = unionfs_lower_dentry(dentry);
++
++ err = vfs_removexattr(lower_dentry, (char *) name);
++
++out:
++ unionfs_check_dentry(dentry);
++ unionfs_unlock_dentry(dentry);
++ unionfs_unlock_parent(dentry, parent);
++ unionfs_read_unlock(dentry->d_sb);
++ return err;
++}
++
++/*
++ * BKL held by caller.
++ * dentry->d_inode->i_mutex locked
++ */
++ssize_t unionfs_listxattr(struct dentry *dentry, char *list, size_t size)
++{
++ struct dentry *lower_dentry = NULL;
++ struct dentry *parent;
++ int err = -EOPNOTSUPP;
++ char *encoded_list = NULL;
++ bool valid;
++
++ unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD);
++ parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
++ unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);
++
++ valid = __unionfs_d_revalidate(dentry, parent, false);
++ if (unlikely(!valid)) {
++ err = -ESTALE;
++ goto out;
++ }
++
++ lower_dentry = unionfs_lower_dentry(dentry);
++
++ encoded_list = list;
++ err = vfs_listxattr(lower_dentry, encoded_list, size);
++
++out:
++ unionfs_check_dentry(dentry);
++ unionfs_unlock_dentry(dentry);
++ unionfs_unlock_parent(dentry, parent);
++ unionfs_read_unlock(dentry->d_sb);
++ return err;
++}
+diff --git a/include/linux/fs_stack.h b/include/linux/fs_stack.h
+index da317c7..64f1ced 100644
+--- a/include/linux/fs_stack.h
++++ b/include/linux/fs_stack.h
+@@ -1,7 +1,19 @@
++/*
++ * Copyright (c) 2006-2009 Erez Zadok
++ * Copyright (c) 2006-2007 Josef 'Jeff' Sipek
++ * Copyright (c) 2006-2009 Stony Brook University
++ * Copyright (c) 2006-2009 The Research Foundation of SUNY
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
+ #ifndef _LINUX_FS_STACK_H
+ #define _LINUX_FS_STACK_H
+
+-/* This file defines generic functions used primarily by stackable
++/*
++ * This file defines generic functions used primarily by stackable
+ * filesystems; none of these functions require i_mutex to be held.
+ */
+
+diff --git a/include/linux/magic.h b/include/linux/magic.h
+index 1e5df2a..01ee54d 100644
+--- a/include/linux/magic.h
++++ b/include/linux/magic.h
+@@ -50,6 +50,8 @@
+ #define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs"
+ #define REISER2FS_JR_SUPER_MAGIC_STRING "ReIsEr3Fs"
+
++#define UNIONFS_SUPER_MAGIC 0xf15f083d
++
+ #define SMB_SUPER_MAGIC 0x517B
+ #define USBDEVICE_SUPER_MAGIC 0x9fa2
+ #define CGROUP_SUPER_MAGIC 0x27e0eb
+diff --git a/include/linux/namei.h b/include/linux/namei.h
+index eba45ea..8e19e9c 100644
+--- a/include/linux/namei.h
++++ b/include/linux/namei.h
+@@ -81,8 +81,11 @@ extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
+
+ extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry,
+ int (*open)(struct inode *, struct file *));
++extern void release_open_intent(struct nameidata *);
+
+ extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
++extern struct dentry *lookup_one_len_nd(const char *, struct dentry *, int,
++ struct nameidata *nd);
+
+ extern int follow_down_one(struct path *);
+ extern int follow_down(struct path *);
+diff --git a/include/linux/splice.h b/include/linux/splice.h
+index 997c3b4..54f5501 100644
+--- a/include/linux/splice.h
++++ b/include/linux/splice.h
+@@ -81,6 +81,11 @@ extern ssize_t splice_to_pipe(struct pipe_inode_info *,
+ struct splice_pipe_desc *);
+ extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *,
+ splice_direct_actor *);
++extern long vfs_splice_from(struct pipe_inode_info *pipe, struct file *out,
++ loff_t *ppos, size_t len, unsigned int flags);
++extern long vfs_splice_to(struct file *in, loff_t *ppos,
++ struct pipe_inode_info *pipe, size_t len,
++ unsigned int flags);
+
+ /*
+ * for dynamic pipe sizing
+diff --git a/include/linux/union_fs.h b/include/linux/union_fs.h
+new file mode 100644
+index 0000000..c84d97e
+--- /dev/null
++++ b/include/linux/union_fs.h
+@@ -0,0 +1,22 @@
++/*
++ * Copyright (c) 2003-2009 Erez Zadok
++ * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
++ * Copyright (c) 2003-2009 Stony Brook University
++ * Copyright (c) 2003-2009 The Research Foundation of SUNY
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#ifndef _LINUX_UNION_FS_H
++#define _LINUX_UNION_FS_H
++
++/*
++ * DEFINITIONS FOR USER AND KERNEL CODE:
++ */
++# define UNIONFS_IOCTL_INCGEN _IOR(0x15, 11, int)
++# define UNIONFS_IOCTL_QUERYFILE _IOR(0x15, 15, int)
++
++#endif /* _LINUX_UNIONFS_H */
++
+diff --git a/security/security.c b/security/security.c
+index 4ba6d4c..093d8b4 100644
+--- a/security/security.c
++++ b/security/security.c
+@@ -520,6 +520,7 @@ int security_inode_permission(struct inode *inode, int mask)
+ return 0;
+ return security_ops->inode_permission(inode, mask, 0);
+ }
++EXPORT_SYMBOL(security_inode_permission);
+
+ int security_inode_exec_permission(struct inode *inode, unsigned int flags)
+ {
+--
+1.6.6.1
+
diff --git a/recipes-kernel/linux/linux-omap_2.6.39.bb b/recipes-kernel/linux/linux-omap_2.6.39.bb
new file mode 100644
index 0000000000..b6927e179c
--- /dev/null
+++ b/recipes-kernel/linux/linux-omap_2.6.39.bb
@@ -0,0 +1,54 @@
+require multi-kernel.inc
+
+DESCRIPTION = "Linux kernel for OMAP processors"
+KERNEL_IMAGETYPE = "uImage"
+
+COMPATIBLE_MACHINE = "(beagleboard)"
+
+# The main PR is now using MACHINE_KERNEL_PR, for omap3 see conf/machine/include/omap3.inc
+SRCREV_pn-${PN} = "v2.6.39"
+
+FILESPATHPKG_prepend = "linux-omap-2.6.39:"
+
+SRC_URI += "git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap-2.6.git;protocol=git \
+ file://defconfig"
+
+SRC_URI_append = " \
+ file://sakoman/0001-OMAP-DSS2-DSI-fix-use_sys_clk-highfreq.patch \
+ file://sakoman/0002-OMAP-DSS2-DSI-fix-dsi_dump_clocks.patch \
+ file://sakoman/0003-OMAP2PLUS-DSS2-Fix-Return-correct-lcd-clock-source-f.patch \
+ file://sakoman/0004-OMAP-DSS-DSI-Fix-DSI-PLL-power-bug.patch \
+ file://sakoman/0005-OMAP-DSS2-fix-panel-Kconfig-dependencies.patch \
+ file://sakoman/0006-OMAP-DSS2-add-bootarg-for-selecting-svideo-or-compos.patch \
+ file://sakoman/0007-video-add-timings-for-hd720.patch \
+ file://sakoman/0008-drivers-net-smsc911x-return-ENODEV-if-device-is-not-.patch \
+ file://sakoman/0009-drivers-input-touchscreen-ads7846-return-ENODEV-if-d.patch \
+ file://sakoman/0010-Revert-omap2_mcspi-Flush-posted-writes.patch \
+ file://sakoman/0011-Revert-omap_hsmmc-improve-interrupt-synchronisation.patch \
+ file://sakoman/0012-Don-t-turn-SDIO-cards-off-to-save-power.-Doing-so-wi.patch \
+ file://sakoman/0013-Enable-the-use-of-SDIO-card-interrupts.patch \
+ file://sakoman/0014-soc-codecs-Enable-audio-capture-by-default-for-twl40.patch \
+ file://sakoman/0015-soc-codecs-twl4030-Turn-on-mic-bias-by-default.patch \
+ file://sakoman/0016-RTC-add-support-for-backup-battery-recharge.patch \
+ file://sakoman/0017-ARM-OMAP2-mmc-twl4030-move-clock-input-selection-pri.patch \
+ file://sakoman/0018-Add-power-off-support-for-the-TWL4030-companion.patch \
+ file://sakoman/0019-ARM-OMAP-Add-twl4030-madc-support-to-Overo.patch \
+ file://sakoman/0020-Enabling-Hwmon-driver-for-twl4030-madc.patch \
+ file://sakoman/0021-mfd-twl-core-enable-madc-clock.patch \
+ file://sakoman/0022-ARM-OMAP-automatically-set-musb-mode-in-platform-dat.patch \
+ file://sakoman/0023-omap-mmc-Adjust-dto-to-eliminate-timeout-errors.patch \
+ file://sakoman/0024-omap-Fix-mtd-subpage-read-alignment.patch \
+ file://sakoman/0025-mtd-nand-omap2-Force-all-buffer-reads-to-u32-alignme.patch \
+ file://sakoman/0026-omap-nand-fix-subpage-ecc-issue-with-prefetch.patch \
+ file://sakoman/0027-OMAP-Overo-Add-support-for-spidev.patch \
+ file://sakoman/0028-unionfs-Add-support-for-unionfs-2.5.9.patch \
+ \
+ file://beagle/0001-OMAP3-beagle-add-support-for-beagleboard-xM-revision.patch \
+ file://beagle/0002-OMAP3-beagle-add-support-for-expansionboards.patch \
+ "
+
+SRC_URI_append_beagleboard = " file://logo_linux_clut224.ppm \
+"
+
+S = "${WORKDIR}/git"
+