From d8639c9f3439e52097819df0e1f4b44ca2d80f8f Mon Sep 17 00:00:00 2001 From: Sipke Vriend Date: Tue, 29 Oct 2013 11:39:11 +1000 Subject: recipes-kernel:linux-yocto: Adjust recipes and patches to match xlnx_3.8. Utilise the xlnx_3.8 branch sources on linux-xlnx.git instead of master. Adjust linux-yocto recipes and include additional patches accordingly. Signed-off-by: Sipke Vriend --- recipes-kernel/linux/linux-yocto-common-3.8.inc | 11 + recipes-kernel/linux/linux-yocto-common.inc | 11 +- recipes-kernel/linux/linux-yocto-tiny_3.8.bbappend | 6 +- ...e-to-match-xlnx_3.8-branch-on-linux_xlnx..patch | 80135 +++++++++++++++++++ ...croblaze-Dont-mark-arch_kgdb_ops-as-const.patch | 35 + .../xlnx_3.8_modifications_to_v14.5.scc | 3 + recipes-kernel/linux/linux-yocto_3.8.bbappend | 6 +- 7 files changed, 80192 insertions(+), 15 deletions(-) create mode 100644 recipes-kernel/linux/linux-yocto-common-3.8.inc create mode 100644 recipes-kernel/linux/linux-yocto/xlnx_3.8/0001-Forward-code-to-match-xlnx_3.8-branch-on-linux_xlnx..patch create mode 100644 recipes-kernel/linux/linux-yocto/xlnx_3.8/0002-microblaze-Dont-mark-arch_kgdb_ops-as-const.patch create mode 100644 recipes-kernel/linux/linux-yocto/xlnx_3.8_modifications_to_v14.5.scc diff --git a/recipes-kernel/linux/linux-yocto-common-3.8.inc b/recipes-kernel/linux/linux-yocto-common-3.8.inc new file mode 100644 index 00000000..82f24435 --- /dev/null +++ b/recipes-kernel/linux/linux-yocto-common-3.8.inc @@ -0,0 +1,11 @@ +# linux patches +LINUX_XLNX_PATCHES = "file://xilinx-v14.5_modifications_to_v3.8.scc \ + file://microblaze-patches_v3.8.scc \ + file://xlnx_3.8_modifications_to_v14.5.scc \ + " +SRC_URI_append_zynq = " ${LINUX_XLNX_PATCHES}" +SRC_URI_append_microblaze = " ${LINUX_XLNX_PATCHES}" + +SRCREV_externalcache_zynq = "c1ddc3a3baddeec5f5d5a5d37448670be8aab7bd" +SRCREV_externalcache_microblaze = "c1ddc3a3baddeec5f5d5a5d37448670be8aab7bd" + diff --git a/recipes-kernel/linux/linux-yocto-common.inc b/recipes-kernel/linux/linux-yocto-common.inc index 92ececce..8c6a7246 100644 --- a/recipes-kernel/linux/linux-yocto-common.inc +++ b/recipes-kernel/linux/linux-yocto-common.inc @@ -4,19 +4,16 @@ FILESEXTRAPATHS_prepend := "${THISDIR}/linux-xlnx:" require linux-machine-common.inc -# linux patches -LINUX_XLNX_PATCHES = "file://xilinx-v14.5_modifications_to_v3.8.scc file://microblaze-patches_v3.8.scc" -SRC_URI_append_zynq = " ${LINUX_XLNX_PATCHES}" -SRC_URI_append_microblaze = " ${LINUX_XLNX_PATCHES}" - # External Cache XLNX_EXTERNAL_CACHE = "git://github.com/Xilinx/xilinx-kernel-cache;protocol=git;branch=master;type=kmeta;name=externalcache;destsuffix=external-cache/" SRC_URI_append_zynq += "${XLNX_EXTERNAL_CACHE}" SRC_URI_append_microblaze += "${XLNX_EXTERNAL_CACHE}" -SRCREV_externalcache_zynq = "c1ddc3a3baddeec5f5d5a5d37448670be8aab7bd" -SRCREV_externalcache_microblaze = "c1ddc3a3baddeec5f5d5a5d37448670be8aab7bd" COMPATIBLE_MACHINE_zynq = "zynq" COMPATIBLE_MACHINE_microblaze = "microblaze" +# default architecture configuration +SRC_URI_append_zynq = " file://zynq-default-tiny.scc" +SRC_URI_append_microblaze = " file://microblaze-default-tiny.scc" + diff --git a/recipes-kernel/linux/linux-yocto-tiny_3.8.bbappend b/recipes-kernel/linux/linux-yocto-tiny_3.8.bbappend index c98018a7..bc1f1e48 100644 --- a/recipes-kernel/linux/linux-yocto-tiny_3.8.bbappend +++ b/recipes-kernel/linux/linux-yocto-tiny_3.8.bbappend @@ -1,6 +1,4 @@ include linux-yocto-common.inc - -# default architecture configuration -SRC_URI_append_zynq = " file://zynq-default-tiny.scc" -SRC_URI_append_microblaze = " file://microblaze-default-tiny.scc" +# include some kernel version specifics shared between standard and tiny +include linux-yocto-common-3.8.inc diff --git a/recipes-kernel/linux/linux-yocto/xlnx_3.8/0001-Forward-code-to-match-xlnx_3.8-branch-on-linux_xlnx..patch b/recipes-kernel/linux/linux-yocto/xlnx_3.8/0001-Forward-code-to-match-xlnx_3.8-branch-on-linux_xlnx..patch new file mode 100644 index 00000000..27c237cf --- /dev/null +++ b/recipes-kernel/linux/linux-yocto/xlnx_3.8/0001-Forward-code-to-match-xlnx_3.8-branch-on-linux_xlnx..patch @@ -0,0 +1,80135 @@ +From d4b1e64e45771480df527ff7890be14fce90a61d Mon Sep 17 00:00:00 2001 +From: Sipke Vriend +Date: Fri, 25 Oct 2013 10:26:31 +1000 +Subject: [PATCH] Forward code to match xlnx_3.8 branch on linux_xlnx.git + +Forward to commit id 7a65c6dd165a8fc052ba0321eb706536e6cbef71 +xlnx_3.8 branch is based on 3.8.11. + +Signed-off-by: Sipke Vriend +--- + Documentation/ABI/testing/debugfs-aufs | 37 - + Documentation/ABI/testing/sysfs-aufs | 24 - + .../devicetree/bindings/clock/zynq-7000.txt | 122 +- + Documentation/filesystems/aufs/README | 333 -- + Documentation/filesystems/aufs/design/01intro.txt | 162 - + Documentation/filesystems/aufs/design/02struct.txt | 226 - + Documentation/filesystems/aufs/design/03lookup.txt | 106 - + Documentation/filesystems/aufs/design/04branch.txt | 76 - + .../filesystems/aufs/design/05wbr_policy.txt | 65 - + Documentation/filesystems/aufs/design/06mmap.txt | 47 - + Documentation/filesystems/aufs/design/07export.txt | 59 - + Documentation/filesystems/aufs/design/08shwh.txt | 53 - + Documentation/filesystems/aufs/design/10dynop.txt | 47 - + Documentation/filesystems/aufs/design/99plan.txt | 96 - + Makefile | 6 +- + arch/arm/Makefile | 3 - + arch/arm/boot/dts/Makefile | 1 + + arch/arm/boot/dts/at91sam9260.dtsi | 16 +- + arch/arm/boot/dts/at91sam9g15.dtsi | 2 +- + arch/arm/boot/dts/at91sam9g15ek.dts | 2 +- + arch/arm/boot/dts/at91sam9g25.dtsi | 2 +- + arch/arm/boot/dts/at91sam9g35.dtsi | 2 +- + arch/arm/boot/dts/at91sam9x25.dtsi | 2 +- + arch/arm/boot/dts/at91sam9x35.dtsi | 2 +- + arch/arm/boot/dts/at91sam9x5ek.dtsi | 2 +- + arch/arm/boot/dts/zynq-7000.dtsi | 63 +- + arch/arm/boot/dts/zynq-afx-nand.dts | 357 +- + arch/arm/boot/dts/zynq-afx-nor.dts | 337 +- + arch/arm/boot/dts/zynq-zc702-base-trd.dts | 658 +++ + arch/arm/boot/dts/zynq-zc702-xylon-snippet.dts | 164 - + arch/arm/boot/dts/zynq-zc702.dts | 494 +- + arch/arm/boot/dts/zynq-zc706.dts | 576 ++- + arch/arm/boot/dts/zynq-zc770-xm010.dts | 537 ++- + arch/arm/boot/dts/zynq-zc770-xm011.dts | 467 +- + arch/arm/boot/dts/zynq-zc770-xm012.dts | 472 +- + arch/arm/boot/dts/zynq-zc770-xm013.dts | 509 +- + arch/arm/boot/dts/zynq-zed.dts | 234 +- + arch/arm/configs/at91sam9g45_defconfig | 1 + + arch/arm/configs/xilinx_zynq_apf_defconfig | 2954 ++++++++++++ + arch/arm/configs/xilinx_zynq_base_trd_defconfig | 2843 +++++++++++ + arch/arm/configs/xilinx_zynq_defconfig | 15 +- + arch/arm/include/asm/pgtable.h | 9 - + arch/arm/kernel/entry-common.S | 3 +- + arch/arm/lib/memset.S | 33 +- + arch/arm/mach-at91/setup.c | 2 +- + arch/arm/mach-imx/headsmp.S | 47 - + arch/arm/mach-omap2/cpuidle34xx.c | 5 +- + arch/arm/mach-shmobile/headsmp.S | 48 - + arch/arm/mach-tegra/headsmp.S | 43 - + arch/arm/mach-u300/include/mach/u300-regs.h | 2 +- + arch/arm/mach-zynq/Makefile | 8 +- + arch/arm/mach-zynq/common.c | 133 +- + arch/arm/mach-zynq/common.h | 27 +- + arch/arm/mach-zynq/headsmp.S | 28 + + arch/arm/mach-zynq/hotplug.c | 84 +- + arch/arm/mach-zynq/platsmp.c | 144 +- + arch/arm/mach-zynq/pm.c | 43 +- + arch/arm/mach-zynq/slcr.c | 490 +- + arch/arm/mach-zynq/timer.c | 36 +- + arch/arm/mach-zynq/xaxipcie.c | 2 - + arch/arm/mm/cache-v7.S | 46 + + arch/arm/mm/fault.c | 13 +- + arch/arm/xen/enlighten.c | 2 +- + arch/arm64/mm/fault.c | 3 +- + arch/avr32/configs/favr-32_defconfig | 1 + + arch/avr32/configs/merisc_defconfig | 1 + + arch/ia64/include/asm/futex.h | 5 +- + arch/ia64/include/asm/mca.h | 1 - + arch/ia64/kernel/irq.c | 8 - + arch/ia64/kernel/mca.c | 37 +- + arch/ia64/kvm/vtlb.c | 2 +- + arch/microblaze/configs/mmu_defconfig | 1 - + arch/microblaze/include/asm/io.h | 2 +- + arch/microblaze/include/asm/pci.h | 2 - + arch/microblaze/kernel/cpu/cache.c | 148 +- + arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c | 21 +- + arch/microblaze/kernel/cpu/cpuinfo.c | 13 +- + arch/microblaze/kernel/cpu/pvr.c | 2 +- + arch/microblaze/kernel/dma.c | 6 +- + arch/microblaze/kernel/early_printk.c | 17 +- + arch/microblaze/kernel/exceptions.c | 27 +- + arch/microblaze/kernel/ftrace.c | 44 +- + arch/microblaze/kernel/head.S | 4 +- + arch/microblaze/kernel/heartbeat.c | 2 +- + arch/microblaze/kernel/intc.c | 4 +- + arch/microblaze/kernel/kgdb.c | 2 +- + arch/microblaze/kernel/microblaze_ksyms.c | 2 +- + arch/microblaze/kernel/module.c | 5 +- + arch/microblaze/kernel/process.c | 24 +- + arch/microblaze/kernel/prom.c | 2 +- + arch/microblaze/kernel/prom_parse.c | 2 +- + arch/microblaze/kernel/ptrace.c | 2 +- + arch/microblaze/kernel/setup.c | 30 +- + arch/microblaze/kernel/signal.c | 6 +- + arch/microblaze/kernel/stacktrace.c | 2 +- + arch/microblaze/kernel/sys_microblaze.c | 3 +- + arch/microblaze/kernel/traps.c | 8 +- + arch/microblaze/kernel/unwind.c | 2 +- + arch/microblaze/lib/ashldi3.c | 3 +- + arch/microblaze/lib/ashrdi3.c | 3 +- + arch/microblaze/lib/cmpdi2.c | 2 +- + arch/microblaze/lib/lshrdi3.c | 3 +- + arch/microblaze/lib/memcpy.c | 12 +- + arch/microblaze/lib/memmove.c | 11 +- + arch/microblaze/lib/memset.c | 2 +- + arch/microblaze/lib/muldi3.c | 2 +- + arch/microblaze/lib/ucmpdi2.c | 2 +- + arch/microblaze/mm/consistent.c | 7 +- + arch/microblaze/mm/fault.c | 10 +- + arch/microblaze/mm/highmem.c | 2 +- + arch/microblaze/mm/init.c | 28 +- + arch/microblaze/mm/pgtable.c | 17 +- + arch/microblaze/pci/indirect_pci.c | 2 +- + arch/microblaze/pci/iomap.c | 2 +- + arch/microblaze/pci/pci-common.c | 96 +- + arch/microblaze/pci/xilinx_pci.c | 16 +- + arch/mips/kernel/proc.c | 6 +- + arch/mips/mm/c-r4k.c | 8 +- + arch/mips/mm/tlbex.c | 3 +- + arch/powerpc/Makefile | 5 +- + arch/powerpc/boot/Makefile | 2 +- + arch/powerpc/include/asm/ppc-opcode.h | 4 - + arch/powerpc/kernel/cpu_setup_power.S | 1 - + arch/powerpc/kernel/exceptions-64s.S | 2 +- + arch/powerpc/kernel/head_64.S | 1 - + arch/powerpc/kernel/traps.c | 10 +- + arch/powerpc/kernel/vdso32/sigtramp.S | 34 - + arch/powerpc/mm/numa.c | 2 +- + arch/powerpc/mm/slb.c | 1 - + arch/powerpc/platforms/cell/spufs/inode.c | 1 - + arch/x86/crypto/crc32c-pcl-intel-asm_64.S | 6 +- + arch/x86/kernel/cpu/perf_event_intel_lbr.c | 27 +- + arch/x86/kernel/cpu/perf_event_intel_uncore.c | 17 +- + arch/x86/kernel/cpu/vmware.c | 1 - + arch/x86/kernel/irq.c | 4 + + arch/x86/kvm/emulate.c | 4 - + arch/x86/mm/init.c | 5 - + arch/x86/platform/efi/efi.c | 11 +- + arch/x86/xen/enlighten.c | 5 +- + arch/x86/xen/smp.c | 2 - + arch/x86/xen/time.c | 6 +- + drivers/acpi/osl.c | 2 +- + drivers/acpi/pci_root.c | 4 +- + drivers/acpi/thermal.c | 16 +- + drivers/ata/libata-acpi.c | 45 +- + drivers/ata/sata_highbank.c | 2 +- + drivers/char/tpm/tpm.c | 31 +- + drivers/char/tpm/tpm.h | 3 - + drivers/char/xilinx_devcfg.c | 66 +- + drivers/clk/clk-divider.c | 5 +- + drivers/clk/clk.c | 39 +- + drivers/clk/zynq/Makefile | 2 +- + drivers/clk/zynq/clk.c | 743 --- + drivers/clk/zynq/clk621.c | 171 - + drivers/clk/zynq/clkc.c | 590 +++ + drivers/clk/zynq/peripheral_clk.c | 515 -- + drivers/clk/zynq/pll.c | 243 + + drivers/cpufreq/zynq-cpufreq.c | 45 +- + drivers/edac/edac_mc_sysfs.c | 12 +- + drivers/gpio/gpio-sch.c | 37 +- + drivers/gpio/gpio-xilinxps.c | 7 +- + drivers/gpu/drm/ast/ast_drv.h | 2 - + drivers/gpu/drm/ast/ast_fb.c | 43 +- + drivers/gpu/drm/ast/ast_ttm.c | 2 +- + drivers/gpu/drm/cirrus/cirrus_drv.h | 2 - + drivers/gpu/drm/cirrus/cirrus_fbdev.c | 38 +- + drivers/gpu/drm/cirrus/cirrus_ttm.c | 2 +- + drivers/gpu/drm/drm_gem.c | 4 +- + drivers/gpu/drm/drm_prime.c | 76 +- + drivers/gpu/drm/gma500/psb_irq.c | 2 +- + drivers/gpu/drm/i915/i915_drv.h | 2 - + drivers/gpu/drm/i915/i915_gem.c | 28 +- + drivers/gpu/drm/i915/i915_gem_context.c | 7 - + drivers/gpu/drm/i915/i915_gem_stolen.c | 81 +- + drivers/gpu/drm/i915/i915_reg.h | 2 +- + drivers/gpu/drm/i915/intel_bios.c | 6 +- + drivers/gpu/drm/i915/intel_bios.h | 4 +- + drivers/gpu/drm/i915/intel_display.c | 26 +- + drivers/gpu/drm/i915/intel_dp.c | 5 +- + drivers/gpu/drm/i915/intel_dvo.c | 13 +- + drivers/gpu/drm/i915/intel_lvds.c | 9 +- + drivers/gpu/drm/i915/intel_panel.c | 7 +- + drivers/gpu/drm/i915/intel_pm.c | 9 +- + drivers/gpu/drm/i915/intel_sdvo.c | 5 +- + drivers/gpu/drm/mgag200/mgag200_drv.h | 2 - + drivers/gpu/drm/mgag200/mgag200_fb.c | 43 +- + drivers/gpu/drm/mgag200/mgag200_ttm.c | 4 +- + drivers/gpu/drm/radeon/atom.c | 6 +- + drivers/gpu/drm/radeon/atombios_crtc.c | 3 - + drivers/gpu/drm/radeon/evergreen.c | 111 +- + drivers/gpu/drm/radeon/evergreen_reg.h | 2 - + drivers/gpu/drm/radeon/ni.c | 8 +- + drivers/gpu/drm/radeon/nid.h | 4 - + drivers/gpu/drm/radeon/r100.c | 77 +- + drivers/gpu/drm/radeon/r500_reg.h | 2 - + drivers/gpu/drm/radeon/r600_hdmi.c | 4 +- + drivers/gpu/drm/radeon/radeon_atombios.c | 21 +- + drivers/gpu/drm/radeon/radeon_kms.c | 4 - + drivers/gpu/drm/radeon/radeon_pm.c | 6 +- + drivers/gpu/drm/radeon/radeon_ring.c | 3 +- + drivers/gpu/drm/radeon/rs600.c | 52 +- + drivers/gpu/drm/radeon/rv515.c | 56 +- + drivers/gpu/drm/radeon/si.c | 3 +- + drivers/gpu/drm/radeon/sid.h | 2 - + drivers/hwmon/xilinx-xadcps.c | 2 +- + drivers/i2c/busses/i2c-xiic.c | 6 +- + drivers/i2c/busses/i2c-xilinx_ps.c | 24 +- + drivers/infiniband/hw/cxgb4/qp.c | 25 +- + drivers/iommu/amd_iommu.c | 3 - + drivers/md/md.c | 9 +- + drivers/md/raid1.c | 7 +- + drivers/md/raid10.c | 7 +- + drivers/memory/zynq-smc.c | 8 +- + drivers/mfd/adp5520.c | 8 +- + drivers/mfd/lpc_sch.c | 147 +- + drivers/mmc/core/mmc.c | 2 +- + drivers/mmc/host/Kconfig | 10 + + drivers/mmc/host/atmel-mci.c | 16 +- + drivers/mmc/host/sdhci-of-xilinxps.c | 17 +- + drivers/net/ethernet/freescale/gianfar_ptp.c | 3 +- + drivers/net/ethernet/ibm/ibmveth.c | 23 +- + drivers/net/ethernet/intel/e1000e/ethtool.c | 13 - + drivers/net/ethernet/intel/e1000e/netdev.c | 80 +- + drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 10 - + .../net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c | 2 +- + drivers/net/ethernet/realtek/r8169.c | 9 - + drivers/net/ethernet/xilinx/xilinx_emacps.c | 433 +- + drivers/net/wireless/iwlwifi/dvm/debugfs.c | 16 +- + drivers/net/wireless/iwlwifi/dvm/sta.c | 5 +- + drivers/net/wireless/mwifiex/pcie.c | 4 +- + drivers/net/wireless/rt2x00/rt2800lib.c | 8 +- + drivers/pci/pci-driver.c | 4 - + drivers/pci/pci.c | 12 +- + drivers/pwm/pwm-spear.c | 6 +- + drivers/remoteproc/Kconfig | 5 +- + drivers/rpmsg/rpmsg_freertos_statistic.c | 1 - + drivers/rtc/rtc-cmos.c | 4 +- + drivers/s390/char/sclp_cmd.c | 4 +- + drivers/spi/spi-xilinx-ps.c | 16 +- + drivers/spi/spi-xilinx-qps.c | 21 +- + drivers/staging/Kconfig | 6 + + drivers/staging/Makefile | 3 + + drivers/staging/apf/Kconfig | 17 + + drivers/staging/apf/Makefile | 9 + + drivers/staging/apf/xilinx-dma-apf.c | 1120 +++++ + drivers/staging/apf/xilinx-dma-apf.h | 210 + + drivers/staging/apf/xlnk-eng.c | 223 + + drivers/staging/apf/xlnk-eng.h | 34 + + drivers/staging/apf/xlnk-event-tracer-type.h | 39 + + drivers/staging/apf/xlnk-ioctl.h | 39 + + drivers/staging/apf/xlnk.c | 1261 +++++ + drivers/staging/apf/xlnk.h | 116 + + drivers/staging/video/axivdma/Kconfig | 16 + + drivers/staging/video/axivdma/Makefile | 1 + + drivers/staging/video/axivdma/xvdma.c | 440 ++ + drivers/staging/video/axivdma/xvdma.h | 71 + + drivers/staging/video/imageon/Kconfig | 11 + + drivers/staging/video/imageon/Makefile | 3 + + drivers/staging/video/imageon/imageon-rx-driver.c | 251 + + drivers/staging/video/imageon/imageon-rx-driver.h | 109 + + drivers/staging/zsmalloc/Kconfig | 2 +- + drivers/staging/zsmalloc/zsmalloc-main.c | 5 +- + drivers/tty/pty.c | 3 - + drivers/tty/serial/pch_uart.c | 5 - + drivers/tty/serial/serial_core.c | 4 - + drivers/tty/serial/xilinx_uartps.c | 84 +- + drivers/tty/tty_io.c | 4 +- + drivers/usb/chipidea/udc.c | 8 - + drivers/usb/chipidea/udc.h | 4 +- + drivers/usb/core/devio.c | 2 - + drivers/usb/gadget/xilinx_usbps_udc.c | 23 +- + drivers/usb/host/Kconfig | 1 + + drivers/usb/host/ehci-hcd.c | 3 + + drivers/usb/host/ehci-xilinx-usbps.c | 7 +- + drivers/usb/host/pci-quirks.c | 14 +- + drivers/usb/host/uhci-q.c | 4 +- + drivers/usb/host/xhci-ring.c | 23 +- + drivers/usb/host/xusbps-dr-of.c | 23 +- + drivers/usb/misc/appledisplay.c | 1 - + drivers/usb/otg/xilinx_usbps_otg.c | 7 +- + drivers/usb/serial/ftdi_sio.c | 23 +- + drivers/usb/serial/ftdi_sio_ids.h | 4 +- + drivers/usb/serial/option.c | 8 - + drivers/usb/storage/cypress_atacb.c | 16 +- + drivers/video/console/fbcon.c | 2 - + drivers/video/xylon/xylonfb/core/xylonfb-pixclk.c | 22 +- + drivers/video/xylon/xylonfb/core/xylonfb.c | 60 +- + drivers/watchdog/Kconfig | 5 +- + drivers/watchdog/xilinx_wdtps.c | 2 +- + fs/Kconfig | 2 - + fs/Makefile | 2 - + fs/aufs/Kconfig | 203 - + fs/aufs/Makefile | 42 - + fs/aufs/aufs.h | 60 - + fs/aufs/branch.c | 1172 ----- + fs/aufs/branch.h | 236 - + fs/aufs/conf.mk | 38 - + fs/aufs/cpup.c | 1085 ----- + fs/aufs/cpup.h | 81 - + fs/aufs/dbgaufs.c | 332 -- + fs/aufs/dbgaufs.h | 49 - + fs/aufs/dcsub.c | 243 - + fs/aufs/dcsub.h | 94 - + fs/aufs/debug.c | 493 -- + fs/aufs/debug.h | 242 - + fs/aufs/dentry.c | 1060 ---- + fs/aufs/dentry.h | 234 - + fs/aufs/dinfo.c | 543 --- + fs/aufs/dir.c | 633 --- + fs/aufs/dir.h | 137 - + fs/aufs/dynop.c | 379 -- + fs/aufs/dynop.h | 76 - + fs/aufs/export.c | 827 ---- + fs/aufs/f_op.c | 723 --- + fs/aufs/f_op_sp.c | 295 -- + fs/aufs/file.c | 683 --- + fs/aufs/file.h | 298 -- + fs/aufs/finfo.c | 157 - + fs/aufs/fstype.h | 481 -- + fs/aufs/hfsnotify.c | 296 -- + fs/aufs/hfsplus.c | 57 - + fs/aufs/hnotify.c | 713 --- + fs/aufs/i_op.c | 1030 ---- + fs/aufs/i_op_add.c | 713 --- + fs/aufs/i_op_del.c | 477 -- + fs/aufs/i_op_ren.c | 1026 ---- + fs/aufs/iinfo.c | 276 -- + fs/aufs/inode.c | 492 -- + fs/aufs/inode.h | 588 --- + fs/aufs/ioctl.c | 196 - + fs/aufs/loop.c | 135 - + fs/aufs/loop.h | 50 - + fs/aufs/magic.mk | 54 - + fs/aufs/module.c | 202 - + fs/aufs/module.h | 105 - + fs/aufs/opts.c | 1677 ------- + fs/aufs/opts.h | 209 - + fs/aufs/plink.c | 511 -- + fs/aufs/poll.c | 56 - + fs/aufs/procfs.c | 170 - + fs/aufs/rdu.c | 384 -- + fs/aufs/rwsem.h | 188 - + fs/aufs/sbinfo.c | 343 -- + fs/aufs/spl.h | 62 - + fs/aufs/super.c | 993 ---- + fs/aufs/super.h | 538 --- + fs/aufs/sysaufs.c | 105 - + fs/aufs/sysaufs.h | 104 - + fs/aufs/sysfs.c | 257 - + fs/aufs/sysrq.c | 151 - + fs/aufs/vdir.c | 885 ---- + fs/aufs/vfsub.c | 769 --- + fs/aufs/vfsub.h | 302 -- + fs/aufs/wbr_policy.c | 700 --- + fs/aufs/whout.c | 1042 ---- + fs/aufs/whout.h | 88 - + fs/aufs/wkq.c | 214 - + fs/aufs/wkq.h | 92 - + fs/aufs/xino.c | 1265 ----- + fs/autofs4/expire.c | 9 + + fs/btrfs/delayed-ref.c | 24 +- + fs/btrfs/inode.c | 21 +- + fs/buffer.c | 2 - + fs/dcache.c | 4 +- + fs/exec.c | 7 +- + fs/ext4/Kconfig | 3 +- + fs/ext4/ext4_jbd2.h | 6 +- + fs/ext4/fsync.c | 3 +- + fs/ext4/inode.c | 11 +- + fs/ext4/mballoc.c | 8 +- + fs/ext4/mmp.c | 2 +- + fs/ext4/resize.c | 6 - + fs/ext4/super.c | 7 +- + fs/fat/Kconfig | 32 - + fs/fat/dir.c | 17 +- + fs/fat/namei_vfat.c | 113 +- + fs/file_table.c | 5 +- + fs/fscache/stats.c | 2 +- + fs/hugetlbfs/inode.c | 24 +- + fs/inode.c | 4 +- + fs/jbd2/commit.c | 50 +- + fs/jbd2/journal.c | 31 - + fs/lockd/clntlock.c | 3 - + fs/lockd/clntproc.c | 3 + + fs/namespace.c | 3 - + fs/nfs/Kconfig | 13 - + fs/nfs/client.c | 12 +- + fs/nfs/internal.h | 7 +- + fs/nfs/mount_clnt.c | 7 +- + fs/nfs/nfs4proc.c | 10 +- + fs/nfs/super.c | 33 +- + fs/nfsd/nfs4proc.c | 8 +- + fs/nfsd/nfs4state.c | 8 +- + fs/nfsd/nfs4xdr.c | 19 +- + fs/notify/group.c | 4 - + fs/notify/inotify/inotify_user.c | 6 +- + fs/notify/mark.c | 4 - + fs/open.c | 1 - + fs/proc/nommu.c | 4 - + fs/proc/task_mmu.c | 6 - + fs/proc/task_nommu.c | 4 - + fs/splice.c | 12 +- + fs/sysfs/dir.c | 15 +- + fs/yaffs2/Kconfig | 161 - + fs/yaffs2/Makefile | 18 - + fs/yaffs2/yaffs_allocator.c | 357 -- + fs/yaffs2/yaffs_allocator.h | 30 - + fs/yaffs2/yaffs_attribs.c | 124 - + fs/yaffs2/yaffs_attribs.h | 28 - + fs/yaffs2/yaffs_bitmap.c | 97 - + fs/yaffs2/yaffs_bitmap.h | 33 - + fs/yaffs2/yaffs_checkptrw.c | 474 -- + fs/yaffs2/yaffs_checkptrw.h | 33 - + fs/yaffs2/yaffs_ecc.c | 281 -- + fs/yaffs2/yaffs_ecc.h | 44 - + fs/yaffs2/yaffs_getblockinfo.h | 35 - + fs/yaffs2/yaffs_guts.c | 5059 -------------------- + fs/yaffs2/yaffs_guts.h | 990 ---- + fs/yaffs2/yaffs_linux.h | 48 - + fs/yaffs2/yaffs_mtdif.c | 294 -- + fs/yaffs2/yaffs_mtdif.h | 25 - + fs/yaffs2/yaffs_nameval.c | 208 - + fs/yaffs2/yaffs_nameval.h | 28 - + fs/yaffs2/yaffs_nand.c | 118 - + fs/yaffs2/yaffs_nand.h | 39 - + fs/yaffs2/yaffs_packedtags1.c | 56 - + fs/yaffs2/yaffs_packedtags1.h | 39 - + fs/yaffs2/yaffs_packedtags2.c | 197 - + fs/yaffs2/yaffs_packedtags2.h | 47 - + fs/yaffs2/yaffs_summary.c | 313 -- + fs/yaffs2/yaffs_summary.h | 37 - + fs/yaffs2/yaffs_tagscompat.c | 381 -- + fs/yaffs2/yaffs_tagscompat.h | 44 - + fs/yaffs2/yaffs_tagsmarshall.c | 199 - + fs/yaffs2/yaffs_tagsmarshall.h | 22 - + fs/yaffs2/yaffs_trace.h | 57 - + fs/yaffs2/yaffs_verify.c | 529 -- + fs/yaffs2/yaffs_verify.h | 43 - + fs/yaffs2/yaffs_vfs.c | 3354 ------------- + fs/yaffs2/yaffs_yaffs1.c | 422 -- + fs/yaffs2/yaffs_yaffs1.h | 22 - + fs/yaffs2/yaffs_yaffs2.c | 1532 ------ + fs/yaffs2/yaffs_yaffs2.h | 39 - + fs/yaffs2/yportenv.h | 82 - + include/asm-generic/pgtable.h | 10 - + include/drm/drmP.h | 5 +- + include/drm/drm_pciids.h | 5 - + include/linux/aufs_type.h | 19 - + include/linux/blkdev.h | 2 +- + include/linux/cgroup.h | 3 + + include/linux/clk-provider.h | 8 +- + include/linux/clk.h | 22 +- + include/linux/clk/zynq.h | 28 +- + include/linux/fs.h | 1 - + include/linux/hugetlb.h | 19 +- + include/linux/ipc_namespace.h | 2 +- + include/linux/jbd2.h | 2 - + include/linux/mm_types.h | 2 - + include/linux/nfs_fs_sb.h | 3 - + include/linux/nfs_xdr.h | 2 +- + include/linux/sched.h | 18 +- + include/linux/socket.h | 4 +- + include/linux/splice.h | 6 - + include/sound/emu10k1.h | 1 - + include/uapi/linux/Kbuild | 2 - + include/uapi/linux/aufs_type.h | 234 - + include/uapi/linux/msdos_fs.h | 1 - + include/uapi/linux/nfs_mount.h | 4 +- + init/Kconfig | 25 - + init/do_mounts.c | 8 +- + init/main.c | 7 - + ipc/shm.c | 8 +- + kernel/Makefile | 1 - + kernel/audit_tree.c | 2 +- + kernel/cgroup.c | 13 +- + kernel/fork.c | 2 - + kernel/hrtimer.c | 6 - + kernel/rcutree_trace.c | 8 +- + kernel/time/tick-broadcast.c | 4 - + kernel/time/tick-common.c | 1 - + kernel/trace/ftrace.c | 5 +- + kernel/trace/trace.c | 64 +- + kernel/trace/trace_selftest.c | 9 +- + kernel/trace/trace_stack.c | 76 +- + kernel/trace/trace_stat.c | 2 - + kernel/uptime_limit.c | 166 - + lib/oid_registry.c | 5 - + mm/memory.c | 2 - + mm/mmap.c | 21 +- + mm/nommu.c | 10 - + mm/page_io.c | 17 - + net/ipv4/arp.c | 9 +- + net/ipv4/netfilter/ipt_rpfilter.c | 8 +- + net/ipv6/netfilter/ip6t_NPT.c | 2 +- + net/ipv6/netfilter/ip6t_rpfilter.c | 8 +- + net/mac80211/pm.c | 4 +- + net/netfilter/ipset/ip_set_core.c | 3 +- + net/netfilter/ipset/ip_set_list_set.c | 10 +- + net/netfilter/ipvs/ip_vs_pe_sip.c | 6 +- + net/netfilter/nf_conntrack_helper.c | 4 +- + net/netfilter/nf_conntrack_netlink.c | 3 - + net/netfilter/nf_conntrack_sip.c | 2 +- + net/netfilter/nf_nat_core.c | 40 +- + net/wireless/reg.c | 2 +- + scripts/kconfig/streamline_config.pl | 17 +- + scripts/mod/modpost.c | 6 +- + security/commoncap.c | 2 - + security/device_cgroup.c | 2 - + security/security.c | 10 - + sound/pci/emu10k1/emu10k1_main.c | 39 +- + sound/pci/hda/patch_realtek.c | 6 - + sound/soc/codecs/max98088.c | 2 +- + sound/usb/6fire/pcm.c | 1 + + sound/usb/caiaq/audio.c | 3 + + sound/usb/card.c | 4 +- + sound/usb/card.h | 1 - + sound/usb/endpoint.c | 5 +- + sound/usb/midi.c | 13 +- + sound/usb/misc/ua101.c | 3 +- + sound/usb/pcm.c | 2 +- + sound/usb/quirks.c | 1 - + sound/usb/stream.c | 9 - + sound/usb/usx2y/usb_stream.c | 1 + + sound/usb/usx2y/usbusx2yaudio.c | 1 + + sound/usb/usx2y/usx2yhwdeppcm.c | 1 + + tools/lib/traceevent/Makefile | 2 +- + tools/perf/Makefile | 12 +- + tools/perf/perf.h | 2 - + .../perf/scripts/python/Perf-Trace-Util/Context.c | 4 - + tools/perf/util/annotate.c | 2 +- + tools/perf/util/include/linux/compiler.h | 1 - + .../util/scripting-engines/trace-event-python.c | 4 - + usr/Makefile | 2 +- + 533 files changed, 15818 insertions(+), 53168 deletions(-) + delete mode 100644 Documentation/ABI/testing/debugfs-aufs + delete mode 100644 Documentation/ABI/testing/sysfs-aufs + delete mode 100644 Documentation/filesystems/aufs/README + delete mode 100644 Documentation/filesystems/aufs/design/01intro.txt + delete mode 100644 Documentation/filesystems/aufs/design/02struct.txt + delete mode 100644 Documentation/filesystems/aufs/design/03lookup.txt + delete mode 100644 Documentation/filesystems/aufs/design/04branch.txt + delete mode 100644 Documentation/filesystems/aufs/design/05wbr_policy.txt + delete mode 100644 Documentation/filesystems/aufs/design/06mmap.txt + delete mode 100644 Documentation/filesystems/aufs/design/07export.txt + delete mode 100644 Documentation/filesystems/aufs/design/08shwh.txt + delete mode 100644 Documentation/filesystems/aufs/design/10dynop.txt + delete mode 100644 Documentation/filesystems/aufs/design/99plan.txt + create mode 100644 arch/arm/boot/dts/zynq-zc702-base-trd.dts + delete mode 100644 arch/arm/boot/dts/zynq-zc702-xylon-snippet.dts + create mode 100644 arch/arm/configs/xilinx_zynq_apf_defconfig + create mode 100644 arch/arm/configs/xilinx_zynq_base_trd_defconfig + create mode 100644 arch/arm/mach-zynq/headsmp.S + delete mode 100644 drivers/clk/zynq/clk.c + delete mode 100644 drivers/clk/zynq/clk621.c + create mode 100644 drivers/clk/zynq/clkc.c + delete mode 100644 drivers/clk/zynq/peripheral_clk.c + create mode 100644 drivers/clk/zynq/pll.c + create mode 100644 drivers/staging/apf/Kconfig + create mode 100644 drivers/staging/apf/Makefile + create mode 100644 drivers/staging/apf/xilinx-dma-apf.c + create mode 100644 drivers/staging/apf/xilinx-dma-apf.h + create mode 100644 drivers/staging/apf/xlnk-eng.c + create mode 100644 drivers/staging/apf/xlnk-eng.h + create mode 100644 drivers/staging/apf/xlnk-event-tracer-type.h + create mode 100644 drivers/staging/apf/xlnk-ioctl.h + create mode 100644 drivers/staging/apf/xlnk.c + create mode 100644 drivers/staging/apf/xlnk.h + create mode 100644 drivers/staging/video/axivdma/Kconfig + create mode 100644 drivers/staging/video/axivdma/Makefile + create mode 100644 drivers/staging/video/axivdma/xvdma.c + create mode 100644 drivers/staging/video/axivdma/xvdma.h + create mode 100644 drivers/staging/video/imageon/Kconfig + create mode 100644 drivers/staging/video/imageon/Makefile + create mode 100644 drivers/staging/video/imageon/imageon-rx-driver.c + create mode 100644 drivers/staging/video/imageon/imageon-rx-driver.h + delete mode 100644 fs/aufs/Kconfig + delete mode 100644 fs/aufs/Makefile + delete mode 100644 fs/aufs/aufs.h + delete mode 100644 fs/aufs/branch.c + delete mode 100644 fs/aufs/branch.h + delete mode 100644 fs/aufs/conf.mk + delete mode 100644 fs/aufs/cpup.c + delete mode 100644 fs/aufs/cpup.h + delete mode 100644 fs/aufs/dbgaufs.c + delete mode 100644 fs/aufs/dbgaufs.h + delete mode 100644 fs/aufs/dcsub.c + delete mode 100644 fs/aufs/dcsub.h + delete mode 100644 fs/aufs/debug.c + delete mode 100644 fs/aufs/debug.h + delete mode 100644 fs/aufs/dentry.c + delete mode 100644 fs/aufs/dentry.h + delete mode 100644 fs/aufs/dinfo.c + delete mode 100644 fs/aufs/dir.c + delete mode 100644 fs/aufs/dir.h + delete mode 100644 fs/aufs/dynop.c + delete mode 100644 fs/aufs/dynop.h + delete mode 100644 fs/aufs/export.c + delete mode 100644 fs/aufs/f_op.c + delete mode 100644 fs/aufs/f_op_sp.c + delete mode 100644 fs/aufs/file.c + delete mode 100644 fs/aufs/file.h + delete mode 100644 fs/aufs/finfo.c + delete mode 100644 fs/aufs/fstype.h + delete mode 100644 fs/aufs/hfsnotify.c + delete mode 100644 fs/aufs/hfsplus.c + delete mode 100644 fs/aufs/hnotify.c + delete mode 100644 fs/aufs/i_op.c + delete mode 100644 fs/aufs/i_op_add.c + delete mode 100644 fs/aufs/i_op_del.c + delete mode 100644 fs/aufs/i_op_ren.c + delete mode 100644 fs/aufs/iinfo.c + delete mode 100644 fs/aufs/inode.c + delete mode 100644 fs/aufs/inode.h + delete mode 100644 fs/aufs/ioctl.c + delete mode 100644 fs/aufs/loop.c + delete mode 100644 fs/aufs/loop.h + delete mode 100644 fs/aufs/magic.mk + delete mode 100644 fs/aufs/module.c + delete mode 100644 fs/aufs/module.h + delete mode 100644 fs/aufs/opts.c + delete mode 100644 fs/aufs/opts.h + delete mode 100644 fs/aufs/plink.c + delete mode 100644 fs/aufs/poll.c + delete mode 100644 fs/aufs/procfs.c + delete mode 100644 fs/aufs/rdu.c + delete mode 100644 fs/aufs/rwsem.h + delete mode 100644 fs/aufs/sbinfo.c + delete mode 100644 fs/aufs/spl.h + delete mode 100644 fs/aufs/super.c + delete mode 100644 fs/aufs/super.h + delete mode 100644 fs/aufs/sysaufs.c + delete mode 100644 fs/aufs/sysaufs.h + delete mode 100644 fs/aufs/sysfs.c + delete mode 100644 fs/aufs/sysrq.c + delete mode 100644 fs/aufs/vdir.c + delete mode 100644 fs/aufs/vfsub.c + delete mode 100644 fs/aufs/vfsub.h + delete mode 100644 fs/aufs/wbr_policy.c + delete mode 100644 fs/aufs/whout.c + delete mode 100644 fs/aufs/whout.h + delete mode 100644 fs/aufs/wkq.c + delete mode 100644 fs/aufs/wkq.h + delete mode 100644 fs/aufs/xino.c + delete mode 100644 fs/yaffs2/Kconfig + delete mode 100644 fs/yaffs2/Makefile + delete mode 100644 fs/yaffs2/yaffs_allocator.c + delete mode 100644 fs/yaffs2/yaffs_allocator.h + delete mode 100644 fs/yaffs2/yaffs_attribs.c + delete mode 100644 fs/yaffs2/yaffs_attribs.h + delete mode 100644 fs/yaffs2/yaffs_bitmap.c + delete mode 100644 fs/yaffs2/yaffs_bitmap.h + delete mode 100644 fs/yaffs2/yaffs_checkptrw.c + delete mode 100644 fs/yaffs2/yaffs_checkptrw.h + delete mode 100644 fs/yaffs2/yaffs_ecc.c + delete mode 100644 fs/yaffs2/yaffs_ecc.h + delete mode 100644 fs/yaffs2/yaffs_getblockinfo.h + delete mode 100644 fs/yaffs2/yaffs_guts.c + delete mode 100644 fs/yaffs2/yaffs_guts.h + delete mode 100644 fs/yaffs2/yaffs_linux.h + delete mode 100644 fs/yaffs2/yaffs_mtdif.c + delete mode 100644 fs/yaffs2/yaffs_mtdif.h + delete mode 100644 fs/yaffs2/yaffs_nameval.c + delete mode 100644 fs/yaffs2/yaffs_nameval.h + delete mode 100644 fs/yaffs2/yaffs_nand.c + delete mode 100644 fs/yaffs2/yaffs_nand.h + delete mode 100644 fs/yaffs2/yaffs_packedtags1.c + delete mode 100644 fs/yaffs2/yaffs_packedtags1.h + delete mode 100644 fs/yaffs2/yaffs_packedtags2.c + delete mode 100644 fs/yaffs2/yaffs_packedtags2.h + delete mode 100644 fs/yaffs2/yaffs_summary.c + delete mode 100644 fs/yaffs2/yaffs_summary.h + delete mode 100644 fs/yaffs2/yaffs_tagscompat.c + delete mode 100644 fs/yaffs2/yaffs_tagscompat.h + delete mode 100644 fs/yaffs2/yaffs_tagsmarshall.c + delete mode 100644 fs/yaffs2/yaffs_tagsmarshall.h + delete mode 100644 fs/yaffs2/yaffs_trace.h + delete mode 100644 fs/yaffs2/yaffs_verify.c + delete mode 100644 fs/yaffs2/yaffs_verify.h + delete mode 100644 fs/yaffs2/yaffs_vfs.c + delete mode 100644 fs/yaffs2/yaffs_yaffs1.c + delete mode 100644 fs/yaffs2/yaffs_yaffs1.h + delete mode 100644 fs/yaffs2/yaffs_yaffs2.c + delete mode 100644 fs/yaffs2/yaffs_yaffs2.h + delete mode 100644 fs/yaffs2/yportenv.h + delete mode 100644 include/linux/aufs_type.h + delete mode 100644 include/uapi/linux/aufs_type.h + delete mode 100644 kernel/uptime_limit.c + +diff --git a/Documentation/ABI/testing/debugfs-aufs b/Documentation/ABI/testing/debugfs-aufs +deleted file mode 100644 +index 7d2e65f..0000000 +--- a/Documentation/ABI/testing/debugfs-aufs ++++ /dev/null +@@ -1,37 +0,0 @@ +-What: /debug/aufs/si_/ +-Date: March 2009 +-Contact: J. R. Okajima +-Description: +- Under /debug/aufs, a directory named si_ is created +- per aufs mount, where is a unique id generated +- internally. +- +-What: /debug/aufs/si_/xib +-Date: March 2009 +-Contact: J. R. Okajima +-Description: +- It shows the consumed blocks by xib (External Inode Number +- Bitmap), its block size and file size. +- When the aufs mount option 'noxino' is specified, it +- will be empty. About XINO files, see the aufs manual. +- +-What: /debug/aufs/si_/xino0, xino1 ... xinoN +-Date: March 2009 +-Contact: J. R. Okajima +-Description: +- It shows the consumed blocks by xino (External Inode Number +- Translation Table), its link count, block size and file +- size. +- When the aufs mount option 'noxino' is specified, it +- will be empty. About XINO files, see the aufs manual. +- +-What: /debug/aufs/si_/xigen +-Date: March 2009 +-Contact: J. R. Okajima +-Description: +- It shows the consumed blocks by xigen (External Inode +- Generation Table), its block size and file size. +- If CONFIG_AUFS_EXPORT is disabled, this entry will not +- be created. +- When the aufs mount option 'noxino' is specified, it +- will be empty. About XINO files, see the aufs manual. +diff --git a/Documentation/ABI/testing/sysfs-aufs b/Documentation/ABI/testing/sysfs-aufs +deleted file mode 100644 +index 7af6dc0..0000000 +--- a/Documentation/ABI/testing/sysfs-aufs ++++ /dev/null +@@ -1,24 +0,0 @@ +-What: /sys/fs/aufs/si_/ +-Date: March 2009 +-Contact: J. R. Okajima +-Description: +- Under /sys/fs/aufs, a directory named si_ is created +- per aufs mount, where is a unique id generated +- internally. +- +-What: /sys/fs/aufs/si_/br0, br1 ... brN +-Date: March 2009 +-Contact: J. R. Okajima +-Description: +- It shows the abolute path of a member directory (which +- is called branch) in aufs, and its permission. +- +-What: /sys/fs/aufs/si_/xi_path +-Date: March 2009 +-Contact: J. R. Okajima +-Description: +- It shows the abolute path of XINO (External Inode Number +- Bitmap, Translation Table and Generation Table) file +- even if it is the default path. +- When the aufs mount option 'noxino' is specified, it +- will be empty. About XINO files, see the aufs manual. +diff --git a/Documentation/devicetree/bindings/clock/zynq-7000.txt b/Documentation/devicetree/bindings/clock/zynq-7000.txt +index c282375..7f686c8 100644 +--- a/Documentation/devicetree/bindings/clock/zynq-7000.txt ++++ b/Documentation/devicetree/bindings/clock/zynq-7000.txt +@@ -6,53 +6,91 @@ The purpose of this document is to document their usage. + See clock_bindings.txt for more information on the generic clock bindings. + See Chapter 25 of Zynq TRM for more information about Zynq clocks. + +-== PLLs == +- +-Used to describe the ARM_PLL, DDR_PLL, and IO_PLL. ++== Clock Controller == ++The clock controller is a logical abstration of Zynq's clock tree. It reads ++required input clock frequencies from the devictree and acts as clock provider ++for all clock consumers of PS clocks. + + Required properties: +-- #clock-cells : shall be 0 (only one clock is output from this node) +-- compatible : "xlnx,zynq-pll" +-- reg : set of u32 values, which are the address offsets within the SLCR +- of the relevant PLL_CTRL register, PLL_CFG and PLL_STATUS register +- respectively +-- lockbit : the index of the PLL_LOCKED bit in the PLL_STATUS register for this +- PLL +-- clocks : phandle for parent clock. should be the phandle for ps_clk ++ - #clock-cells : Must be 1 ++ - compatible : "xlnx,ps7-clkc" ++ - ps-clk-frequency : Frequency of the oscillator providing ps_clk in HZ ++ (usually 33 MHz oscillators are used for Zynq platforms) ++ - clock-output-names : List of strings used to name the clock outputs. Shall be ++ a list of the outputs given below. + + Optional properties: +-- clock-output-names : name of the output clock +- +-Example: +- armpll: armpll { +- #clock-cells = <0>; +- compatible = "xlnx,zynq-pll"; +- clocks = <&ps_clk>; +- reg = <0x100 0x110>; +- clock-output-names = "armpll"; +- }; ++ - clocks : as described in the clock bindings ++ - clock-names : as described in the clock bindings ++ - fclk-enable : Bit mask to enable FCLKs in cases no proper CCF compatible ++ driver is available. Bit [0..3] correspond to FCLK0..FCLK3. + +-== Peripheral clocks == ++Clock inputs: ++The following strings are optional parameters to the 'clock-names' property in ++order to provide an optional (E)MIO clock source. ++ - swdt_ext_clk ++ - gem0_emio_clk ++ - gem1_emio_clk ++ - mio_clk_XX # with XX = 00..53 ++... + +-Describes clock node for the SDIO, SMC, SPI, QSPI, and UART clocks. +- +-Required properties: +-- #clock-cells : shall be 1 +-- compatible : "xlnx,zynq-periph-clock" +-- reg : a single u32 value, describing the offset within the SLCR where +- the CLK_CTRL register is found for this peripheral +-- clocks : phandle for parent clocks. should hold phandles for +- the IO_PLL, ARM_PLL, and DDR_PLL in order +-- clock-output-names : names of the output clock(s). For peripherals that have +- two output clocks (for example, the UART), two clocks +- should be listed. ++Clock outputs: ++ 0: armpll ++ 1: ddrpll ++ 2: iopll ++ 3: cpu_6or4x ++ 4: cpu_3or2x ++ 5: cpu_2x ++ 6: cpu_1x ++ 7: ddr2x ++ 8: ddr3x ++ 9: dci ++ 10: lqspi ++ 11: smc ++ 12: pcap ++ 13: gem0 ++ 14: gem1 ++ 15: fclk0 ++ 16: fclk1 ++ 17: fclk2 ++ 18: fclk3 ++ 19: can0 ++ 20: can1 ++ 21: sdio0 ++ 22: sdio1 ++ 23: uart0 ++ 24: uart1 ++ 25: spi0 ++ 26: spi1 ++ 27: dma ++ 28: usb0_aper ++ 29: usb1_aper ++ 30: gem0_aper ++ 31: gem1_aper ++ 32: sdio0_aper ++ 33: sdio1_aper ++ 34: spi0_aper ++ 35: spi1_aper ++ 36: can0_aper ++ 37: can1_aper ++ 38: i2c0_aper ++ 39: i2c1_aper ++ 40: uart0_aper ++ 41: uart1_aper ++ 42: gpio_aper ++ 43: lqspi_aper ++ 44: smc_aper ++ 45: swdt ++ 46: dbg_trc ++ 47: dbg_apb + + Example: +- uart_clk: uart_clk { +- #clock-cells = <1>; +- compatible = "xlnx,zynq-periph-clock"; +- clocks = <&iopll &armpll &ddrpll>; +- reg = <0x154>; +- clock-output-names = "uart0_ref_clk", +- "uart1_ref_clk"; +- }; ++ clkc: clkc { ++ #clock-cells = <1>; ++ compatible = "xlnx,ps7-clkc"; ++ ps-clk-frequency = <33333333>; ++ clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x", "cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x", "dci", "lqspi", "smc", "pcap", "gem0", "gem1", "fclk0", "fclk1", "fclk2", "fclk3", "can0", "can1", "sdio0", "sdio1", "uart0", "uart1", "spi0", "spi1", "dma", "usb0_aper", "usb1_aper", "gem0_aper", "gem1_aper", "sdio0_aper", "sdio1_aper", "spi0_aper", "spi1_aper", "can0_aper", "can1_aper", "i2c0_aper", "i2c1_aper", "uart0_aper", "uart1_aper", "gpio_aper", "lqspi_aper", "smc_aper", "swdt", "dbg_trc", "dbg_apb"; ++ # optional props ++ clocks = <&clkc 16>, <&clk_foo>; ++ clock-names = "gem1_emio_clk", "can_mio_clk_23"; ++ }; +diff --git a/Documentation/filesystems/aufs/README b/Documentation/filesystems/aufs/README +deleted file mode 100644 +index 41bf3a7..0000000 +--- a/Documentation/filesystems/aufs/README ++++ /dev/null +@@ -1,333 +0,0 @@ +- +-Aufs3 -- advanced multi layered unification filesystem version 3.x +-http://aufs.sf.net +-Junjiro R. Okajima +- +- +-0. Introduction +----------------------------------------- +-In the early days, aufs was entirely re-designed and re-implemented +-Unionfs Version 1.x series. After many original ideas, approaches, +-improvements and implementations, it becomes totally different from +-Unionfs while keeping the basic features. +-Recently, Unionfs Version 2.x series begin taking some of the same +-approaches to aufs1's. +-Unionfs is being developed by Professor Erez Zadok at Stony Brook +-University and his team. +- +-Aufs3 supports linux-3.0 and later. +-If you want older kernel version support, try aufs2-2.6.git or +-aufs2-standalone.git repository, aufs1 from CVS on SourceForge. +- +-Note: it becomes clear that "Aufs was rejected. Let's give it up." +-According to Christoph Hellwig, linux rejects all union-type filesystems +-but UnionMount. +- +- +- +-1. Features +----------------------------------------- +-- unite several directories into a single virtual filesystem. The member +- directory is called as a branch. +-- you can specify the permission flags to the branch, which are 'readonly', +- 'readwrite' and 'whiteout-able.' +-- by upper writable branch, internal copyup and whiteout, files/dirs on +- readonly branch are modifiable logically. +-- dynamic branch manipulation, add, del. +-- etc... +- +-Also there are many enhancements in aufs1, such as: +-- readdir(3) in userspace. +-- keep inode number by external inode number table +-- keep the timestamps of file/dir in internal copyup operation +-- seekable directory, supporting NFS readdir. +-- whiteout is hardlinked in order to reduce the consumption of inodes +- on branch +-- do not copyup, nor create a whiteout when it is unnecessary +-- revert a single systemcall when an error occurs in aufs +-- remount interface instead of ioctl +-- maintain /etc/mtab by an external command, /sbin/mount.aufs. +-- loopback mounted filesystem as a branch +-- kernel thread for removing the dir who has a plenty of whiteouts +-- support copyup sparse file (a file which has a 'hole' in it) +-- default permission flags for branches +-- selectable permission flags for ro branch, whether whiteout can +- exist or not +-- export via NFS. +-- support /fs/aufs and /aufs. +-- support multiple writable branches, some policies to select one +- among multiple writable branches. +-- a new semantics for link(2) and rename(2) to support multiple +- writable branches. +-- no glibc changes are required. +-- pseudo hardlink (hardlink over branches) +-- allow a direct access manually to a file on branch, e.g. bypassing aufs. +- including NFS or remote filesystem branch. +-- userspace wrapper for pathconf(3)/fpathconf(3) with _PC_LINK_MAX. +-- and more... +- +-Currently these features are dropped temporary from aufs3. +-See design/08plan.txt in detail. +-- test only the highest one for the directory permission (dirperm1) +-- copyup on open (coo=) +-- nested mount, i.e. aufs as readonly no-whiteout branch of another aufs +- (robr) +-- statistics of aufs thread (/sys/fs/aufs/stat) +-- delegation mode (dlgt) +- a delegation of the internal branch access to support task I/O +- accounting, which also supports Linux Security Modules (LSM) mainly +- for Suse AppArmor. +-- intent.open/create (file open in a single lookup) +- +-Features or just an idea in the future (see also design/*.txt), +-- reorder the branch index without del/re-add. +-- permanent xino files for NFSD +-- an option for refreshing the opened files after add/del branches +-- 'move' policy for copy-up between two writable branches, after +- checking free space. +-- light version, without branch manipulation. (unnecessary?) +-- copyup in userspace +-- inotify in userspace +-- readv/writev +-- xattr, acl +- +- +-2. Download +----------------------------------------- +-There were three GIT trees for aufs3, aufs3-linux.git, +-aufs3-standalone.git, and aufs-util.git. Note that there is no "3" in +-"aufs-util.git." +-While the aufs-util is always necessary, you need either of aufs3-linux +-or aufs3-standalone. +- +-The aufs3-linux tree includes the whole linux mainline GIT tree, +-git://git.kernel.org/.../torvalds/linux.git. +-And you cannot select CONFIG_AUFS_FS=m for this version, eg. you cannot +-build aufs3 as an external kernel module. +- +-On the other hand, the aufs3-standalone tree has only aufs source files +-and necessary patches, and you can select CONFIG_AUFS_FS=m. +- +-You will find GIT branches whose name is in form of "aufs3.x" where "x" +-represents the linux kernel version, "linux-3.x". For instance, +-"aufs3.0" is for linux-3.0. For latest "linux-3.x-rcN", use +-"aufs3.x-rcN" branch. +- +-o aufs3-linux tree +-$ git clone --reference /your/linux/git/tree \ +- git://aufs.git.sourceforge.net/gitroot/aufs/aufs3-linux.git \ +- aufs3-linux.git +-- if you don't have linux GIT tree, then remove "--reference ..." +-$ cd aufs3-linux.git +-$ git checkout origin/aufs3.0 +- +-o aufs3-standalone tree +-$ git clone git://aufs.git.sourceforge.net/gitroot/aufs/aufs3-standalone.git \ +- aufs3-standalone.git +-$ cd aufs3-standalone.git +-$ git checkout origin/aufs3.0 +- +-o aufs-util tree +-$ git clone git://aufs.git.sourceforge.net/gitroot/aufs/aufs-util.git \ +- aufs-util.git +-$ cd aufs-util.git +-$ git checkout origin/aufs3.0 +- +-Note: The 3.x-rcN branch is to be used with `rc' kernel versions ONLY. +-The minor version number, 'x' in '3.x', of aufs may not always +-follow the minor version number of the kernel. +-Because changes in the kernel that cause the use of a new +-minor version number do not always require changes to aufs-util. +- +-Since aufs-util has its own minor version number, you may not be +-able to find a GIT branch in aufs-util for your kernel's +-exact minor version number. +-In this case, you should git-checkout the branch for the +-nearest lower number. +- +-For (an unreleased) example: +-If you are using "linux-3.10" and the "aufs3.10" branch +-does not exist in aufs-util repository, then "aufs3.9", "aufs3.8" +-or something numerically smaller is the branch for your kernel. +- +-Also you can view all branches by +- $ git branch -a +- +- +-3. Configuration and Compilation +----------------------------------------- +-Make sure you have git-checkout'ed the correct branch. +- +-For aufs3-linux tree, +-- enable CONFIG_EXPERIMENTAL and CONFIG_AUFS_FS. +-- set other aufs configurations if necessary. +- +-For aufs3-standalone tree, +-There are several ways to build. +- +-1. +-- apply ./aufs3-kbuild.patch to your kernel source files. +-- apply ./aufs3-base.patch too. +-- apply ./aufs3-proc_map.patch too, if you want to make /proc/PID/maps (and +- others including lsof(1)) show the file path on aufs instead of the +- path on the branch fs. +-- apply ./aufs3-standalone.patch too, if you have a plan to set +- CONFIG_AUFS_FS=m. otherwise you don't need ./aufs3-standalone.patch. +-- copy ./{Documentation,fs,include/uapi/linux/aufs_type.h} files to your +- kernel source tree. Never copy $PWD/include/uapi/linux/Kbuild. +-- enable CONFIG_EXPERIMENTAL and CONFIG_AUFS_FS, you can select either +- =m or =y. +-- and build your kernel as usual. +-- install the built kernel. +-- install the header files too by "make headers_install" to the +- directory where you specify. By default, it is $PWD/usr. +- "make help" shows a brief note for headers_install. +-- and reboot your system. +- +-2. +-- module only (CONFIG_AUFS_FS=m). +-- apply ./aufs3-base.patch to your kernel source files. +-- apply ./aufs3-proc_map.patch too to your kernel source files, +- if you want to make /proc/PID/maps (and others including lsof(1)) show +- the file path on aufs instead of the path on the branch fs. +-- apply ./aufs3-standalone.patch too. +-- build your kernel, don't forget "make headers_install", and reboot. +-- edit ./config.mk and set other aufs configurations if necessary. +- Note: You should read $PWD/fs/aufs/Kconfig carefully which describes +- every aufs configurations. +-- build the module by simple "make". +-- you can specify ${KDIR} make variable which points to your kernel +- source tree. +-- install the files +- + run "make install" to install the aufs module, or copy the built +- $PWD/aufs.ko to /lib/modules/... and run depmod -a (or reboot simply). +- + run "make install_headers" (instead of headers_install) to install +- the modified aufs header file (you can specify DESTDIR which is +- available in aufs standalone version's Makefile only), or copy +- $PWD/usr/include/linux/aufs_type.h to /usr/include/linux or wherever +- you like manually. By default, the target directory is $PWD/usr. +-- no need to apply aufs3-kbuild.patch, nor copying source files to your +- kernel source tree. +- +-Note: The header file aufs_type.h is necessary to build aufs-util +- as well as "make headers_install" in the kernel source tree. +- headers_install is subject to be forgotten, but it is essentially +- necessary, not only for building aufs-util. +- You may not meet problems without headers_install in some older +- version though. +- +-And then, +-- read README in aufs-util, build and install it +-- note that your distribution may contain an obsoleted version of +- aufs_type.h in /usr/include/linux or something. When you build aufs +- utilities, make sure that your compiler refers the correct aufs header +- file which is built by "make headers_install." +-- if you want to use readdir(3) in userspace or pathconf(3) wrapper, +- then run "make install_ulib" too. And refer to the aufs manual in +- detail. +- +- +-4. Usage +----------------------------------------- +-At first, make sure aufs-util are installed, and please read the aufs +-manual, aufs.5 in aufs-util.git tree. +-$ man -l aufs.5 +- +-And then, +-$ mkdir /tmp/rw /tmp/aufs +-# mount -t aufs -o br=/tmp/rw:${HOME} none /tmp/aufs +- +-Here is another example. The result is equivalent. +-# mount -t aufs -o br=/tmp/rw=rw:${HOME}=ro none /tmp/aufs +- Or +-# mount -t aufs -o br:/tmp/rw none /tmp/aufs +-# mount -o remount,append:${HOME} /tmp/aufs +- +-Then, you can see whole tree of your home dir through /tmp/aufs. If +-you modify a file under /tmp/aufs, the one on your home directory is +-not affected, instead the same named file will be newly created under +-/tmp/rw. And all of your modification to a file will be applied to +-the one under /tmp/rw. This is called the file based Copy on Write +-(COW) method. +-Aufs mount options are described in aufs.5. +-If you run chroot or something and make your aufs as a root directory, +-then you need to customize the shutdown script. See the aufs manual in +-detail. +- +-Additionally, there are some sample usages of aufs which are a +-diskless system with network booting, and LiveCD over NFS. +-See sample dir in CVS tree on SourceForge. +- +- +-5. Contact +----------------------------------------- +-When you have any problems or strange behaviour in aufs, please let me +-know with: +-- /proc/mounts (instead of the output of mount(8)) +-- /sys/module/aufs/* +-- /sys/fs/aufs/* (if you have them) +-- /debug/aufs/* (if you have them) +-- linux kernel version +- if your kernel is not plain, for example modified by distributor, +- the url where i can download its source is necessary too. +-- aufs version which was printed at loading the module or booting the +- system, instead of the date you downloaded. +-- configuration (define/undefine CONFIG_AUFS_xxx) +-- kernel configuration or /proc/config.gz (if you have it) +-- behaviour which you think to be incorrect +-- actual operation, reproducible one is better +-- mailto: aufs-users at lists.sourceforge.net +- +-Usually, I don't watch the Public Areas(Bugs, Support Requests, Patches, +-and Feature Requests) on SourceForge. Please join and write to +-aufs-users ML. +- +- +-6. Acknowledgements +----------------------------------------- +-Thanks to everyone who have tried and are using aufs, whoever +-have reported a bug or any feedback. +- +-Especially donators: +-Tomas Matejicek(slax.org) made a donation (much more than once). +- Since Apr 2010, Tomas M (the author of Slax and Linux Live +- scripts) is making "doubling" donations. +- Unfortunately I cannot list all of the donators, but I really +- appreciate. +- It ends Aug 2010, but the ordinary donation URL is still available. +- +-Dai Itasaka made a donation (2007/8). +-Chuck Smith made a donation (2008/4, 10 and 12). +-Henk Schoneveld made a donation (2008/9). +-Chih-Wei Huang, ASUS, CTC donated Eee PC 4G (2008/10). +-Francois Dupoux made a donation (2008/11). +-Bruno Cesar Ribas and Luis Carlos Erpen de Bona, C3SL serves public +- aufs2 GIT tree (2009/2). +-William Grant made a donation (2009/3). +-Patrick Lane made a donation (2009/4). +-The Mail Archive (mail-archive.com) made donations (2009/5). +-Nippy Networks (Ed Wildgoose) made a donation (2009/7). +-New Dream Network, LLC (www.dreamhost.com) made a donation (2009/11). +-Pavel Pronskiy made a donation (2011/2). +-Iridium and Inmarsat satellite phone retailer (www.mailasail.com), Nippy +- Networks (Ed Wildgoose) made a donation for hardware (2011/3). +-Max Lekomcev (DOM-TV project) made a donation (2011/7, 12, 2012/3, 6 and +-11). +-Sam Liddicott made a donation (2011/9). +- +-Thank you very much. +-Donations are always, including future donations, very important and +-helpful for me to keep on developing aufs. +- +- +-7. +----------------------------------------- +-If you are an experienced user, no explanation is needed. Aufs is +-just a linux filesystem. +- +- +-Enjoy! +- +-# Local variables: ; +-# mode: text; +-# End: ; +diff --git a/Documentation/filesystems/aufs/design/01intro.txt b/Documentation/filesystems/aufs/design/01intro.txt +deleted file mode 100644 +index e60f8c6..0000000 +--- a/Documentation/filesystems/aufs/design/01intro.txt ++++ /dev/null +@@ -1,162 +0,0 @@ +- +-# Copyright (C) 2005-2013 Junjiro R. Okajima +-# +-# This program is free software; you can redistribute it and/or modify +-# it under the terms of the GNU General Public License as published by +-# the Free Software Foundation; either version 2 of the License, or +-# (at your option) any later version. +-# +-# This program is distributed in the hope that it will be useful, +-# but WITHOUT ANY WARRANTY; without even the implied warranty of +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-# GNU General Public License for more details. +-# +-# You should have received a copy of the GNU General Public License +-# along with this program; if not, write to the Free Software +-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- +-Introduction +----------------------------------------- +- +-aufs [ei ju: ef es] | [a u f s] +-1. abbrev. for "advanced multi-layered unification filesystem". +-2. abbrev. for "another unionfs". +-3. abbrev. for "auf das" in German which means "on the" in English. +- Ex. "Butter aufs Brot"(G) means "butter onto bread"(E). +- But "Filesystem aufs Filesystem" is hard to understand. +- +-AUFS is a filesystem with features: +-- multi layered stackable unification filesystem, the member directory +- is called as a branch. +-- branch permission and attribute, 'readonly', 'real-readonly', +- 'readwrite', 'whiteout-able', 'link-able whiteout' and their +- combination. +-- internal "file copy-on-write". +-- logical deletion, whiteout. +-- dynamic branch manipulation, adding, deleting and changing permission. +-- allow bypassing aufs, user's direct branch access. +-- external inode number translation table and bitmap which maintains the +- persistent aufs inode number. +-- seekable directory, including NFS readdir. +-- file mapping, mmap and sharing pages. +-- pseudo-link, hardlink over branches. +-- loopback mounted filesystem as a branch. +-- several policies to select one among multiple writable branches. +-- revert a single systemcall when an error occurs in aufs. +-- and more... +- +- +-Multi Layered Stackable Unification Filesystem +----------------------------------------------------------------------- +-Most people already knows what it is. +-It is a filesystem which unifies several directories and provides a +-merged single directory. When users access a file, the access will be +-passed/re-directed/converted (sorry, I am not sure which English word is +-correct) to the real file on the member filesystem. The member +-filesystem is called 'lower filesystem' or 'branch' and has a mode +-'readonly' and 'readwrite.' And the deletion for a file on the lower +-readonly branch is handled by creating 'whiteout' on the upper writable +-branch. +- +-On LKML, there have been discussions about UnionMount (Jan Blunck, +-Bharata B Rao and Valerie Aurora) and Unionfs (Erez Zadok). They took +-different approaches to implement the merged-view. +-The former tries putting it into VFS, and the latter implements as a +-separate filesystem. +-(If I misunderstand about these implementations, please let me know and +-I shall correct it. Because it is a long time ago when I read their +-source files last time). +- +-UnionMount's approach will be able to small, but may be hard to share +-branches between several UnionMount since the whiteout in it is +-implemented in the inode on branch filesystem and always +-shared. According to Bharata's post, readdir does not seems to be +-finished yet. +-There are several missing features known in this implementations such as +-- for users, the inode number may change silently. eg. copy-up. +-- link(2) may break by copy-up. +-- read(2) may get an obsoleted filedata (fstat(2) too). +-- fcntl(F_SETLK) may be broken by copy-up. +-- unnecessary copy-up may happen, for example mmap(MAP_PRIVATE) after +- open(O_RDWR). +- +-Unionfs has a longer history. When I started implementing a stacking filesystem +-(Aug 2005), it already existed. It has virtual super_block, inode, +-dentry and file objects and they have an array pointing lower same kind +-objects. After contributing many patches for Unionfs, I re-started my +-project AUFS (Jun 2006). +- +-In AUFS, the structure of filesystem resembles to Unionfs, but I +-implemented my own ideas, approaches and enhancements and it became +-totally different one. +- +-Comparing DM snapshot and fs based implementation +-- the number of bytes to be copied between devices is much smaller. +-- the type of filesystem must be one and only. +-- the fs must be writable, no readonly fs, even for the lower original +- device. so the compression fs will not be usable. but if we use +- loopback mount, we may address this issue. +- for instance, +- mount /cdrom/squashfs.img /sq +- losetup /sq/ext2.img +- losetup /somewhere/cow +- dmsetup "snapshot /dev/loop0 /dev/loop1 ..." +-- it will be difficult (or needs more operations) to extract the +- difference between the original device and COW. +-- DM snapshot-merge may help a lot when users try merging. in the +- fs-layer union, users will use rsync(1). +- +- +-Several characters/aspects of aufs +----------------------------------------------------------------------- +- +-Aufs has several characters or aspects. +-1. a filesystem, callee of VFS helper +-2. sub-VFS, caller of VFS helper for branches +-3. a virtual filesystem which maintains persistent inode number +-4. reader/writer of files on branches such like an application +- +-1. Callee of VFS Helper +-As an ordinary linux filesystem, aufs is a callee of VFS. For instance, +-unlink(2) from an application reaches sys_unlink() kernel function and +-then vfs_unlink() is called. vfs_unlink() is one of VFS helper and it +-calls filesystem specific unlink operation. Actually aufs implements the +-unlink operation but it behaves like a redirector. +- +-2. Caller of VFS Helper for Branches +-aufs_unlink() passes the unlink request to the branch filesystem as if +-it were called from VFS. So the called unlink operation of the branch +-filesystem acts as usual. As a caller of VFS helper, aufs should handle +-every necessary pre/post operation for the branch filesystem. +-- acquire the lock for the parent dir on a branch +-- lookup in a branch +-- revalidate dentry on a branch +-- mnt_want_write() for a branch +-- vfs_unlink() for a branch +-- mnt_drop_write() for a branch +-- release the lock on a branch +- +-3. Persistent Inode Number +-One of the most important issue for a filesystem is to maintain inode +-numbers. This is particularly important to support exporting a +-filesystem via NFS. Aufs is a virtual filesystem which doesn't have a +-backend block device for its own. But some storage is necessary to +-maintain inode number. It may be a large space and may not suit to keep +-in memory. Aufs rents some space from its first writable branch +-filesystem (by default) and creates file(s) on it. These files are +-created by aufs internally and removed soon (currently) keeping opened. +-Note: Because these files are removed, they are totally gone after +- unmounting aufs. It means the inode numbers are not persistent +- across unmount or reboot. I have a plan to make them really +- persistent which will be important for aufs on NFS server. +- +-4. Read/Write Files Internally (copy-on-write) +-Because a branch can be readonly, when you write a file on it, aufs will +-"copy-up" it to the upper writable branch internally. And then write the +-originally requested thing to the file. Generally kernel doesn't +-open/read/write file actively. In aufs, even a single write may cause a +-internal "file copy". This behaviour is very similar to cp(1) command. +- +-Some people may think it is better to pass such work to user space +-helper, instead of doing in kernel space. Actually I am still thinking +-about it. But currently I have implemented it in kernel space. +diff --git a/Documentation/filesystems/aufs/design/02struct.txt b/Documentation/filesystems/aufs/design/02struct.txt +deleted file mode 100644 +index f54d654..0000000 +--- a/Documentation/filesystems/aufs/design/02struct.txt ++++ /dev/null +@@ -1,226 +0,0 @@ +- +-# Copyright (C) 2005-2013 Junjiro R. Okajima +-# +-# This program is free software; you can redistribute it and/or modify +-# it under the terms of the GNU General Public License as published by +-# the Free Software Foundation; either version 2 of the License, or +-# (at your option) any later version. +-# +-# This program is distributed in the hope that it will be useful, +-# but WITHOUT ANY WARRANTY; without even the implied warranty of +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-# GNU General Public License for more details. +-# +-# You should have received a copy of the GNU General Public License +-# along with this program; if not, write to the Free Software +-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- +-Basic Aufs Internal Structure +- +-Superblock/Inode/Dentry/File Objects +----------------------------------------------------------------------- +-As like an ordinary filesystem, aufs has its own +-superblock/inode/dentry/file objects. All these objects have a +-dynamically allocated array and store the same kind of pointers to the +-lower filesystem, branch. +-For example, when you build a union with one readwrite branch and one +-readonly, mounted /au, /rw and /ro respectively. +-- /au = /rw + /ro +-- /ro/fileA exists but /rw/fileA +- +-Aufs lookup operation finds /ro/fileA and gets dentry for that. These +-pointers are stored in a aufs dentry. The array in aufs dentry will be, +-- [0] = NULL +-- [1] = /ro/fileA +- +-This style of an array is essentially same to the aufs +-superblock/inode/dentry/file objects. +- +-Because aufs supports manipulating branches, ie. add/delete/change +-dynamically, these objects has its own generation. When branches are +-changed, the generation in aufs superblock is incremented. And a +-generation in other object are compared when it is accessed. +-When a generation in other objects are obsoleted, aufs refreshes the +-internal array. +- +- +-Superblock +----------------------------------------------------------------------- +-Additionally aufs superblock has some data for policies to select one +-among multiple writable branches, XIB files, pseudo-links and kobject. +-See below in detail. +-About the policies which supports copy-down a directory, see policy.txt +-too. +- +- +-Branch and XINO(External Inode Number Translation Table) +----------------------------------------------------------------------- +-Every branch has its own xino (external inode number translation table) +-file. The xino file is created and unlinked by aufs internally. When two +-members of a union exist on the same filesystem, they share the single +-xino file. +-The struct of a xino file is simple, just a sequence of aufs inode +-numbers which is indexed by the lower inode number. +-In the above sample, assume the inode number of /ro/fileA is i111 and +-aufs assigns the inode number i999 for fileA. Then aufs writes 999 as +-4(8) bytes at 111 * 4(8) bytes offset in the xino file. +- +-When the inode numbers are not contiguous, the xino file will be sparse +-which has a hole in it and doesn't consume as much disk space as it +-might appear. If your branch filesystem consumes disk space for such +-holes, then you should specify 'xino=' option at mounting aufs. +- +-Also a writable branch has three kinds of "whiteout bases". All these +-are existed when the branch is joined to aufs and the names are +-whiteout-ed doubly, so that users will never see their names in aufs +-hierarchy. +-1. a regular file which will be linked to all whiteouts. +-2. a directory to store a pseudo-link. +-3. a directory to store an "orphan-ed" file temporary. +- +-1. Whiteout Base +- When you remove a file on a readonly branch, aufs handles it as a +- logical deletion and creates a whiteout on the upper writable branch +- as a hardlink of this file in order not to consume inode on the +- writable branch. +-2. Pseudo-link Dir +- See below, Pseudo-link. +-3. Step-Parent Dir +- When "fileC" exists on the lower readonly branch only and it is +- opened and removed with its parent dir, and then user writes +- something into it, then aufs copies-up fileC to this +- directory. Because there is no other dir to store fileC. After +- creating a file under this dir, the file is unlinked. +- +-Because aufs supports manipulating branches, ie. add/delete/change +-dynamically, a branch has its own id. When the branch order changes, aufs +-finds the new index by searching the branch id. +- +- +-Pseudo-link +----------------------------------------------------------------------- +-Assume "fileA" exists on the lower readonly branch only and it is +-hardlinked to "fileB" on the branch. When you write something to fileA, +-aufs copies-up it to the upper writable branch. Additionally aufs +-creates a hardlink under the Pseudo-link Directory of the writable +-branch. The inode of a pseudo-link is kept in aufs super_block as a +-simple list. If fileB is read after unlinking fileA, aufs returns +-filedata from the pseudo-link instead of the lower readonly +-branch. Because the pseudo-link is based upon the inode, to keep the +-inode number by xino (see above) is important. +- +-All the hardlinks under the Pseudo-link Directory of the writable branch +-should be restored in a proper location later. Aufs provides a utility +-to do this. The userspace helpers executed at remounting and unmounting +-aufs by default. +-During this utility is running, it puts aufs into the pseudo-link +-maintenance mode. In this mode, only the process which began the +-maintenance mode (and its child processes) is allowed to operate in +-aufs. Some other processes which are not related to the pseudo-link will +-be allowed to run too, but the rest have to return an error or wait +-until the maintenance mode ends. If a process already acquires an inode +-mutex (in VFS), it has to return an error. +- +- +-XIB(external inode number bitmap) +----------------------------------------------------------------------- +-Addition to the xino file per a branch, aufs has an external inode number +-bitmap in a superblock object. It is also a file such like a xino file. +-It is a simple bitmap to mark whether the aufs inode number is in-use or +-not. +-To reduce the file I/O, aufs prepares a single memory page to cache xib. +- +-Aufs implements a feature to truncate/refresh both of xino and xib to +-reduce the number of consumed disk blocks for these files. +- +- +-Virtual or Vertical Dir, and Readdir in Userspace +----------------------------------------------------------------------- +-In order to support multiple layers (branches), aufs readdir operation +-constructs a virtual dir block on memory. For readdir, aufs calls +-vfs_readdir() internally for each dir on branches, merges their entries +-with eliminating the whiteout-ed ones, and sets it to file (dir) +-object. So the file object has its entry list until it is closed. The +-entry list will be updated when the file position is zero and becomes +-old. This decision is made in aufs automatically. +- +-The dynamically allocated memory block for the name of entries has a +-unit of 512 bytes (by default) and stores the names contiguously (no +-padding). Another block for each entry is handled by kmem_cache too. +-During building dir blocks, aufs creates hash list and judging whether +-the entry is whiteouted by its upper branch or already listed. +-The merged result is cached in the corresponding inode object and +-maintained by a customizable life-time option. +- +-Some people may call it can be a security hole or invite DoS attack +-since the opened and once readdir-ed dir (file object) holds its entry +-list and becomes a pressure for system memory. But I'd say it is similar +-to files under /proc or /sys. The virtual files in them also holds a +-memory page (generally) while they are opened. When an idea to reduce +-memory for them is introduced, it will be applied to aufs too. +-For those who really hate this situation, I've developed readdir(3) +-library which operates this merging in userspace. You just need to set +-LD_PRELOAD environment variable, and aufs will not consume no memory in +-kernel space for readdir(3). +- +- +-Workqueue +----------------------------------------------------------------------- +-Aufs sometimes requires privilege access to a branch. For instance, +-in copy-up/down operation. When a user process is going to make changes +-to a file which exists in the lower readonly branch only, and the mode +-of one of ancestor directories may not be writable by a user +-process. Here aufs copy-up the file with its ancestors and they may +-require privilege to set its owner/group/mode/etc. +-This is a typical case of a application character of aufs (see +-Introduction). +- +-Aufs uses workqueue synchronously for this case. It creates its own +-workqueue. The workqueue is a kernel thread and has privilege. Aufs +-passes the request to call mkdir or write (for example), and wait for +-its completion. This approach solves a problem of a signal handler +-simply. +-If aufs didn't adopt the workqueue and changed the privilege of the +-process, and if the mkdir/write call arises SIGXFSZ or other signal, +-then the user process might gain a privilege or the generated core file +-was owned by a superuser. +- +-Also aufs uses the system global workqueue ("events" kernel thread) too +-for asynchronous tasks, such like handling inotify/fsnotify, re-creating a +-whiteout base and etc. This is unrelated to a privilege. +-Most of aufs operation tries acquiring a rw_semaphore for aufs +-superblock at the beginning, at the same time waits for the completion +-of all queued asynchronous tasks. +- +- +-Whiteout +----------------------------------------------------------------------- +-The whiteout in aufs is very similar to Unionfs's. That is represented +-by its filename. UnionMount takes an approach of a file mode, but I am +-afraid several utilities (find(1) or something) will have to support it. +- +-Basically the whiteout represents "logical deletion" which stops aufs to +-lookup further, but also it represents "dir is opaque" which also stop +-lookup. +- +-In aufs, rmdir(2) and rename(2) for dir uses whiteout alternatively. +-In order to make several functions in a single systemcall to be +-revertible, aufs adopts an approach to rename a directory to a temporary +-unique whiteouted name. +-For example, in rename(2) dir where the target dir already existed, aufs +-renames the target dir to a temporary unique whiteouted name before the +-actual rename on a branch and then handles other actions (make it opaque, +-update the attributes, etc). If an error happens in these actions, aufs +-simply renames the whiteouted name back and returns an error. If all are +-succeeded, aufs registers a function to remove the whiteouted unique +-temporary name completely and asynchronously to the system global +-workqueue. +- +- +-Copy-up +----------------------------------------------------------------------- +-It is a well-known feature or concept. +-When user modifies a file on a readonly branch, aufs operate "copy-up" +-internally and makes change to the new file on the upper writable branch. +-When the trigger systemcall does not update the timestamps of the parent +-dir, aufs reverts it after copy-up. +diff --git a/Documentation/filesystems/aufs/design/03lookup.txt b/Documentation/filesystems/aufs/design/03lookup.txt +deleted file mode 100644 +index d3ca527..0000000 +--- a/Documentation/filesystems/aufs/design/03lookup.txt ++++ /dev/null +@@ -1,106 +0,0 @@ +- +-# Copyright (C) 2005-2013 Junjiro R. Okajima +-# +-# This program is free software; you can redistribute it and/or modify +-# it under the terms of the GNU General Public License as published by +-# the Free Software Foundation; either version 2 of the License, or +-# (at your option) any later version. +-# +-# This program is distributed in the hope that it will be useful, +-# but WITHOUT ANY WARRANTY; without even the implied warranty of +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-# GNU General Public License for more details. +-# +-# You should have received a copy of the GNU General Public License +-# along with this program; if not, write to the Free Software +-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- +-Lookup in a Branch +----------------------------------------------------------------------- +-Since aufs has a character of sub-VFS (see Introduction), it operates +-lookup for branches as VFS does. It may be a heavy work. Generally +-speaking struct nameidata is a bigger structure and includes many +-information. But almost all lookup operation in aufs is the simplest +-case, ie. lookup only an entry directly connected to its parent. Digging +-down the directory hierarchy is unnecessary. +- +-VFS has a function lookup_one_len() for that use, but it is not usable +-for a branch filesystem which requires struct nameidata. So aufs +-implements a simple lookup wrapper function. When a branch filesystem +-allows NULL as nameidata, it calls lookup_one_len(). Otherwise it builds +-a simplest nameidata and calls lookup_hash(). +-Here aufs applies "a principle in NFSD", ie. if the filesystem supports +-NFS-export, then it has to support NULL as a nameidata parameter for +-->create(), ->lookup() and ->d_revalidate(). So the lookup wrapper in +-aufs tests if ->s_export_op in the branch is NULL or not. +- +-When a branch is a remote filesystem, aufs basically trusts its +-->d_revalidate(), also aufs forces the hardest revalidate tests for +-them. +-For d_revalidate, aufs implements three levels of revalidate tests. See +-"Revalidate Dentry and UDBA" in detail. +- +- +-Loopback Mount +----------------------------------------------------------------------- +-Basically aufs supports any type of filesystem and block device for a +-branch (actually there are some exceptions). But it is prohibited to add +-a loopback mounted one whose backend file exists in a filesystem which is +-already added to aufs. The reason is to protect aufs from a recursive +-lookup. If it was allowed, the aufs lookup operation might re-enter a +-lookup for the loopback mounted branch in the same context, and will +-cause a deadlock. +- +- +-Revalidate Dentry and UDBA (User's Direct Branch Access) +----------------------------------------------------------------------- +-Generally VFS helpers re-validate a dentry as a part of lookup. +-0. digging down the directory hierarchy. +-1. lock the parent dir by its i_mutex. +-2. lookup the final (child) entry. +-3. revalidate it. +-4. call the actual operation (create, unlink, etc.) +-5. unlock the parent dir +- +-If the filesystem implements its ->d_revalidate() (step 3), then it is +-called. Actually aufs implements it and checks the dentry on a branch is +-still valid. +-But it is not enough. Because aufs has to release the lock for the +-parent dir on a branch at the end of ->lookup() (step 2) and +-->d_revalidate() (step 3) while the i_mutex of the aufs dir is still +-held by VFS. +-If the file on a branch is changed directly, eg. bypassing aufs, after +-aufs released the lock, then the subsequent operation may cause +-something unpleasant result. +- +-This situation is a result of VFS architecture, ->lookup() and +-->d_revalidate() is separated. But I never say it is wrong. It is a good +-design from VFS's point of view. It is just not suitable for sub-VFS +-character in aufs. +- +-Aufs supports such case by three level of revalidation which is +-selectable by user. +-1. Simple Revalidate +- Addition to the native flow in VFS's, confirm the child-parent +- relationship on the branch just after locking the parent dir on the +- branch in the "actual operation" (step 4). When this validation +- fails, aufs returns EBUSY. ->d_revalidate() (step 3) in aufs still +- checks the validation of the dentry on branches. +-2. Monitor Changes Internally by Inotify/Fsnotify +- Addition to above, in the "actual operation" (step 4) aufs re-lookup +- the dentry on the branch, and returns EBUSY if it finds different +- dentry. +- Additionally, aufs sets the inotify/fsnotify watch for every dir on branches +- during it is in cache. When the event is notified, aufs registers a +- function to kernel 'events' thread by schedule_work(). And the +- function sets some special status to the cached aufs dentry and inode +- private data. If they are not cached, then aufs has nothing to +- do. When the same file is accessed through aufs (step 0-3) later, +- aufs will detect the status and refresh all necessary data. +- In this mode, aufs has to ignore the event which is fired by aufs +- itself. +-3. No Extra Validation +- This is the simplest test and doesn't add any additional revalidation +- test, and skip therevalidatin in step 4. It is useful and improves +- aufs performance when system surely hide the aufs branches from user, +- by over-mounting something (or another method). +diff --git a/Documentation/filesystems/aufs/design/04branch.txt b/Documentation/filesystems/aufs/design/04branch.txt +deleted file mode 100644 +index f85f3a8..0000000 +--- a/Documentation/filesystems/aufs/design/04branch.txt ++++ /dev/null +@@ -1,76 +0,0 @@ +- +-# Copyright (C) 2005-2013 Junjiro R. Okajima +-# +-# This program is free software; you can redistribute it and/or modify +-# it under the terms of the GNU General Public License as published by +-# the Free Software Foundation; either version 2 of the License, or +-# (at your option) any later version. +-# +-# This program is distributed in the hope that it will be useful, +-# but WITHOUT ANY WARRANTY; without even the implied warranty of +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-# GNU General Public License for more details. +-# +-# You should have received a copy of the GNU General Public License +-# along with this program; if not, write to the Free Software +-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- +-Branch Manipulation +- +-Since aufs supports dynamic branch manipulation, ie. add/remove a branch +-and changing its permission/attribute, there are a lot of works to do. +- +- +-Add a Branch +----------------------------------------------------------------------- +-o Confirm the adding dir exists outside of aufs, including loopback +- mount. +-- and other various attributes... +-o Initialize the xino file and whiteout bases if necessary. +- See struct.txt. +- +-o Check the owner/group/mode of the directory +- When the owner/group/mode of the adding directory differs from the +- existing branch, aufs issues a warning because it may impose a +- security risk. +- For example, when a upper writable branch has a world writable empty +- top directory, a malicious user can create any files on the writable +- branch directly, like copy-up and modify manually. If something like +- /etc/{passwd,shadow} exists on the lower readonly branch but the upper +- writable branch, and the writable branch is world-writable, then a +- malicious guy may create /etc/passwd on the writable branch directly +- and the infected file will be valid in aufs. +- I am afraid it can be a security issue, but nothing to do except +- producing a warning. +- +- +-Delete a Branch +----------------------------------------------------------------------- +-o Confirm the deleting branch is not busy +- To be general, there is one merit to adopt "remount" interface to +- manipulate branches. It is to discard caches. At deleting a branch, +- aufs checks the still cached (and connected) dentries and inodes. If +- there are any, then they are all in-use. An inode without its +- corresponding dentry can be alive alone (for example, inotify/fsnotify case). +- +- For the cached one, aufs checks whether the same named entry exists on +- other branches. +- If the cached one is a directory, because aufs provides a merged view +- to users, as long as one dir is left on any branch aufs can show the +- dir to users. In this case, the branch can be removed from aufs. +- Otherwise aufs rejects deleting the branch. +- +- If any file on the deleting branch is opened by aufs, then aufs +- rejects deleting. +- +- +-Modify the Permission of a Branch +----------------------------------------------------------------------- +-o Re-initialize or remove the xino file and whiteout bases if necessary. +- See struct.txt. +- +-o rw --> ro: Confirm the modifying branch is not busy +- Aufs rejects the request if any of these conditions are true. +- - a file on the branch is mmap-ed. +- - a regular file on the branch is opened for write and there is no +- same named entry on the upper branch. +diff --git a/Documentation/filesystems/aufs/design/05wbr_policy.txt b/Documentation/filesystems/aufs/design/05wbr_policy.txt +deleted file mode 100644 +index 2bb8e58..0000000 +--- a/Documentation/filesystems/aufs/design/05wbr_policy.txt ++++ /dev/null +@@ -1,65 +0,0 @@ +- +-# Copyright (C) 2005-2013 Junjiro R. Okajima +-# +-# This program is free software; you can redistribute it and/or modify +-# it under the terms of the GNU General Public License as published by +-# the Free Software Foundation; either version 2 of the License, or +-# (at your option) any later version. +-# +-# This program is distributed in the hope that it will be useful, +-# but WITHOUT ANY WARRANTY; without even the implied warranty of +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-# GNU General Public License for more details. +-# +-# You should have received a copy of the GNU General Public License +-# along with this program; if not, write to the Free Software +-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- +-Policies to Select One among Multiple Writable Branches +----------------------------------------------------------------------- +-When the number of writable branch is more than one, aufs has to decide +-the target branch for file creation or copy-up. By default, the highest +-writable branch which has the parent (or ancestor) dir of the target +-file is chosen (top-down-parent policy). +-By user's request, aufs implements some other policies to select the +-writable branch, for file creation two policies, round-robin and +-most-free-space policies. For copy-up three policies, top-down-parent, +-bottom-up-parent and bottom-up policies. +- +-As expected, the round-robin policy selects the branch in circular. When +-you have two writable branches and creates 10 new files, 5 files will be +-created for each branch. mkdir(2) systemcall is an exception. When you +-create 10 new directories, all will be created on the same branch. +-And the most-free-space policy selects the one which has most free +-space among the writable branches. The amount of free space will be +-checked by aufs internally, and users can specify its time interval. +- +-The policies for copy-up is more simple, +-top-down-parent is equivalent to the same named on in create policy, +-bottom-up-parent selects the writable branch where the parent dir +-exists and the nearest upper one from the copyup-source, +-bottom-up selects the nearest upper writable branch from the +-copyup-source, regardless the existence of the parent dir. +- +-There are some rules or exceptions to apply these policies. +-- If there is a readonly branch above the policy-selected branch and +- the parent dir is marked as opaque (a variation of whiteout), or the +- target (creating) file is whiteout-ed on the upper readonly branch, +- then the result of the policy is ignored and the target file will be +- created on the nearest upper writable branch than the readonly branch. +-- If there is a writable branch above the policy-selected branch and +- the parent dir is marked as opaque or the target file is whiteouted +- on the branch, then the result of the policy is ignored and the target +- file will be created on the highest one among the upper writable +- branches who has diropq or whiteout. In case of whiteout, aufs removes +- it as usual. +-- link(2) and rename(2) systemcalls are exceptions in every policy. +- They try selecting the branch where the source exists as possible +- since copyup a large file will take long time. If it can't be, +- ie. the branch where the source exists is readonly, then they will +- follow the copyup policy. +-- There is an exception for rename(2) when the target exists. +- If the rename target exists, aufs compares the index of the branches +- where the source and the target exists and selects the higher +- one. If the selected branch is readonly, then aufs follows the +- copyup policy. +diff --git a/Documentation/filesystems/aufs/design/06mmap.txt b/Documentation/filesystems/aufs/design/06mmap.txt +deleted file mode 100644 +index 55524d6..0000000 +--- a/Documentation/filesystems/aufs/design/06mmap.txt ++++ /dev/null +@@ -1,47 +0,0 @@ +- +-# Copyright (C) 2005-2013 Junjiro R. Okajima +-# +-# This program is free software; you can redistribute it and/or modify +-# it under the terms of the GNU General Public License as published by +-# the Free Software Foundation; either version 2 of the License, or +-# (at your option) any later version. +-# +-# This program is distributed in the hope that it will be useful, +-# but WITHOUT ANY WARRANTY; without even the implied warranty of +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-# GNU General Public License for more details. +-# +-# You should have received a copy of the GNU General Public License +-# along with this program; if not, write to the Free Software +-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- +-mmap(2) -- File Memory Mapping +----------------------------------------------------------------------- +-In aufs, the file-mapped pages are handled by a branch fs directly, no +-interaction with aufs. It means aufs_mmap() calls the branch fs's +-->mmap(). +-This approach is simple and good, but there is one problem. +-Under /proc, several entries show the mmap-ped files by its path (with +-device and inode number), and the printed path will be the path on the +-branch fs's instead of virtual aufs's. +-This is not a problem in most cases, but some utilities lsof(1) (and its +-user) may expect the path on aufs. +- +-To address this issue, aufs adds a new member called vm_prfile in struct +-vm_area_struct (and struct vm_region). The original vm_file points to +-the file on the branch fs in order to handle everything correctly as +-usual. The new vm_prfile points to a virtual file in aufs, and the +-show-functions in procfs refers to vm_prfile if it is set. +-Also we need to maintain several other places where touching vm_file +-such like +-- fork()/clone() copies vma and the reference count of vm_file is +- incremented. +-- merging vma maintains the ref count too. +- +-This is not a good approach. It just faking the printed path. But it +-leaves all behaviour around f_mapping unchanged. This is surely an +-advantage. +-Actually aufs had adopted another complicated approach which calls +-generic_file_mmap() and handles struct vm_operations_struct. In this +-approach, aufs met a hard problem and I could not solve it without +-switching the approach. +diff --git a/Documentation/filesystems/aufs/design/07export.txt b/Documentation/filesystems/aufs/design/07export.txt +deleted file mode 100644 +index ecf42a4..0000000 +--- a/Documentation/filesystems/aufs/design/07export.txt ++++ /dev/null +@@ -1,59 +0,0 @@ +- +-# Copyright (C) 2005-2013 Junjiro R. Okajima +-# +-# This program is free software; you can redistribute it and/or modify +-# it under the terms of the GNU General Public License as published by +-# the Free Software Foundation; either version 2 of the License, or +-# (at your option) any later version. +-# +-# This program is distributed in the hope that it will be useful, +-# but WITHOUT ANY WARRANTY; without even the implied warranty of +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-# GNU General Public License for more details. +-# +-# You should have received a copy of the GNU General Public License +-# along with this program; if not, write to the Free Software +-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- +-Export Aufs via NFS +----------------------------------------------------------------------- +-Here is an approach. +-- like xino/xib, add a new file 'xigen' which stores aufs inode +- generation. +-- iget_locked(): initialize aufs inode generation for a new inode, and +- store it in xigen file. +-- destroy_inode(): increment aufs inode generation and store it in xigen +- file. it is necessary even if it is not unlinked, because any data of +- inode may be changed by UDBA. +-- encode_fh(): for a root dir, simply return FILEID_ROOT. otherwise +- build file handle by +- + branch id (4 bytes) +- + superblock generation (4 bytes) +- + inode number (4 or 8 bytes) +- + parent dir inode number (4 or 8 bytes) +- + inode generation (4 bytes)) +- + return value of exportfs_encode_fh() for the parent on a branch (4 +- bytes) +- + file handle for a branch (by exportfs_encode_fh()) +-- fh_to_dentry(): +- + find the index of a branch from its id in handle, and check it is +- still exist in aufs. +- + 1st level: get the inode number from handle and search it in cache. +- + 2nd level: if not found, get the parent inode number from handle and +- search it in cache. and then open the parent dir, find the matching +- inode number by vfs_readdir() and get its name, and call +- lookup_one_len() for the target dentry. +- + 3rd level: if the parent dir is not cached, call +- exportfs_decode_fh() for a branch and get the parent on a branch, +- build a pathname of it, convert it a pathname in aufs, call +- path_lookup(). now aufs gets a parent dir dentry, then handle it as +- the 2nd level. +- + to open the dir, aufs needs struct vfsmount. aufs keeps vfsmount +- for every branch, but not itself. to get this, (currently) aufs +- searches in current->nsproxy->mnt_ns list. it may not be a good +- idea, but I didn't get other approach. +- + test the generation of the gotten inode. +-- every inode operation: they may get EBUSY due to UDBA. in this case, +- convert it into ESTALE for NFSD. +-- readdir(): call lockdep_on/off() because filldir in NFSD calls +- lookup_one_len(), vfs_getattr(), encode_fh() and others. +diff --git a/Documentation/filesystems/aufs/design/08shwh.txt b/Documentation/filesystems/aufs/design/08shwh.txt +deleted file mode 100644 +index 18b889c..0000000 +--- a/Documentation/filesystems/aufs/design/08shwh.txt ++++ /dev/null +@@ -1,53 +0,0 @@ +- +-# Copyright (C) 2005-2013 Junjiro R. Okajima +-# +-# This program is free software; you can redistribute it and/or modify +-# it under the terms of the GNU General Public License as published by +-# the Free Software Foundation; either version 2 of the License, or +-# (at your option) any later version. +-# +-# This program is distributed in the hope that it will be useful, +-# but WITHOUT ANY WARRANTY; without even the implied warranty of +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-# GNU General Public License for more details. +-# +-# You should have received a copy of the GNU General Public License +-# along with this program; if not, write to the Free Software +-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- +-Show Whiteout Mode (shwh) +----------------------------------------------------------------------- +-Generally aufs hides the name of whiteouts. But in some cases, to show +-them is very useful for users. For instance, creating a new middle layer +-(branch) by merging existing layers. +- +-(borrowing aufs1 HOW-TO from a user, Michael Towers) +-When you have three branches, +-- Bottom: 'system', squashfs (underlying base system), read-only +-- Middle: 'mods', squashfs, read-only +-- Top: 'overlay', ram (tmpfs), read-write +- +-The top layer is loaded at boot time and saved at shutdown, to preserve +-the changes made to the system during the session. +-When larger changes have been made, or smaller changes have accumulated, +-the size of the saved top layer data grows. At this point, it would be +-nice to be able to merge the two overlay branches ('mods' and 'overlay') +-and rewrite the 'mods' squashfs, clearing the top layer and thus +-restoring save and load speed. +- +-This merging is simplified by the use of another aufs mount, of just the +-two overlay branches using the 'shwh' option. +-# mount -t aufs -o ro,shwh,br:/livesys/overlay=ro+wh:/livesys/mods=rr+wh \ +- aufs /livesys/merge_union +- +-A merged view of these two branches is then available at +-/livesys/merge_union, and the new feature is that the whiteouts are +-visible! +-Note that in 'shwh' mode the aufs mount must be 'ro', which will disable +-writing to all branches. Also the default mode for all branches is 'ro'. +-It is now possible to save the combined contents of the two overlay +-branches to a new squashfs, e.g.: +-# mksquashfs /livesys/merge_union /path/to/newmods.squash +- +-This new squashfs archive can be stored on the boot device and the +-initramfs will use it to replace the old one at the next boot. +diff --git a/Documentation/filesystems/aufs/design/10dynop.txt b/Documentation/filesystems/aufs/design/10dynop.txt +deleted file mode 100644 +index 49e9a53..0000000 +--- a/Documentation/filesystems/aufs/design/10dynop.txt ++++ /dev/null +@@ -1,47 +0,0 @@ +- +-# Copyright (C) 2010-2013 Junjiro R. Okajima +-# +-# This program is free software; you can redistribute it and/or modify +-# it under the terms of the GNU General Public License as published by +-# the Free Software Foundation; either version 2 of the License, or +-# (at your option) any later version. +-# +-# This program is distributed in the hope that it will be useful, +-# but WITHOUT ANY WARRANTY; without even the implied warranty of +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-# GNU General Public License for more details. +-# +-# You should have received a copy of the GNU General Public License +-# along with this program; if not, write to the Free Software +-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- +-Dynamically customizable FS operations +----------------------------------------------------------------------- +-Generally FS operations (struct inode_operations, struct +-address_space_operations, struct file_operations, etc.) are defined as +-"static const", but it never means that FS have only one set of +-operation. Some FS have multiple sets of them. For instance, ext2 has +-three sets, one for XIP, for NOBH, and for normal. +-Since aufs overrides and redirects these operations, sometimes aufs has +-to change its behaviour according to the branch FS type. More imporantly +-VFS acts differently if a function (member in the struct) is set or +-not. It means aufs should have several sets of operations and select one +-among them according to the branch FS definition. +- +-In order to solve this problem and not to affect the behavour of VFS, +-aufs defines these operations dynamically. For instance, aufs defines +-aio_read function for struct file_operations, but it may not be set to +-the file_operations. When the branch FS doesn't have it, aufs doesn't +-set it to its file_operations while the function definition itself is +-still alive. So the behaviour of io_submit(2) will not change, and it +-will return an error when aio_read is not defined. +- +-The lifetime of these dynamically generated operation object is +-maintained by aufs branch object. When the branch is removed from aufs, +-the reference counter of the object is decremented. When it reaches +-zero, the dynamically generated operation object will be freed. +- +-This approach is designed to support AIO (io_submit), Direcit I/O and +-XIP mainly. +-Currently this approach is applied to file_operations and +-vm_operations_struct for regular files only. +diff --git a/Documentation/filesystems/aufs/design/99plan.txt b/Documentation/filesystems/aufs/design/99plan.txt +deleted file mode 100644 +index a21f133..0000000 +--- a/Documentation/filesystems/aufs/design/99plan.txt ++++ /dev/null +@@ -1,96 +0,0 @@ +- +-# Copyright (C) 2005-2013 Junjiro R. Okajima +-# +-# This program is free software; you can redistribute it and/or modify +-# it under the terms of the GNU General Public License as published by +-# the Free Software Foundation; either version 2 of the License, or +-# (at your option) any later version. +-# +-# This program is distributed in the hope that it will be useful, +-# but WITHOUT ANY WARRANTY; without even the implied warranty of +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-# GNU General Public License for more details. +-# +-# You should have received a copy of the GNU General Public License +-# along with this program; if not, write to the Free Software +-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- +-Plan +- +-Restoring some features which was implemented in aufs1. +-They were dropped in aufs2 in order to make source files simpler and +-easier to be reviewed. +- +- +-Test Only the Highest One for the Directory Permission (dirperm1 option) +----------------------------------------------------------------------- +-Let's try case study. +-- aufs has two branches, upper readwrite and lower readonly. +- /au = /rw + /ro +-- "dirA" exists under /ro, but /rw. and its mode is 0700. +-- user invoked "chmod a+rx /au/dirA" +-- then "dirA" becomes world readable? +- +-In this case, /ro/dirA is still 0700 since it exists in readonly branch, +-or it may be a natively readonly filesystem. If aufs respects the lower +-branch, it should not respond readdir request from other users. But user +-allowed it by chmod. Should really aufs rejects showing the entries +-under /ro/dirA? +- +-To be honest, I don't have a best solution for this case. So I +-implemented 'dirperm1' and 'nodirperm1' option in aufs1, and leave it to +-users. +-When dirperm1 is specified, aufs checks only the highest one for the +-directory permission, and shows the entries. Otherwise, as usual, checks +-every dir existing on all branches and rejects the request. +- +-As a side effect, dirperm1 option improves the performance of aufs +-because the number of permission check is reduced. +- +- +-Being Another Aufs's Readonly Branch (robr) +----------------------------------------------------------------------- +-Aufs1 allows aufs to be another aufs's readonly branch. +-This feature was developed by a user's request. But it may not be used +-currecnly. +- +- +-Copy-up on Open (coo=) +----------------------------------------------------------------------- +-By default the internal copy-up is executed when it is really necessary. +-It is not done when a file is opened for writing, but when write(2) is +-done. Users who have many (over 100) branches want to know and analyse +-when and what file is copied-up. To insert a new upper branch which +-contains such files only may improve the performance of aufs. +- +-Aufs1 implemented "coo=none | leaf | all" option. +- +- +-Refresh the Opened File (refrof) +----------------------------------------------------------------------- +-This option is implemented in aufs1 but incomplete. +- +-When user reads from a file, he expects to get its latest filedata +-generally. If the file is removed and a new same named file is created, +-the content he gets is unchanged, ie. the unlinked filedata. +- +-Let's try case study again. +-- aufs has two branches. +- /au = /rw + /ro +-- "fileA" exists under /ro, but /rw. +-- user opened "/au/fileA". +-- he or someone else inserts a branch (/new) between /rw and /ro. +- /au = /rw + /new + /ro +-- the new branch has "fileA". +-- user reads from the opened "fileA" +-- which filedata should aufs return, from /ro or /new? +- +-Some people says it has to be "from /ro" and it is a semantics of Unix. +-The others say it should be "from /new" because the file is not removed +-and it is equivalent to the case of someone else modifies the file. +- +-Here again I don't have a best and final answer. I got an idea to +-implement 'refrof' and 'norefrof' option. When 'refrof' (REFResh the +-Opened File) is specified (by default), aufs returns the filedata from +-/new. +-Otherwise from /new. +diff --git a/Makefile b/Makefile +index 2b20682..7e4eee5 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,6 +1,6 @@ + VERSION = 3 + PATCHLEVEL = 8 +-SUBLEVEL = 13 ++SUBLEVEL = 11 + EXTRAVERSION = + NAME = Displaced Humerus Anterior + +@@ -406,7 +406,7 @@ export MODVERDIR := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_ve + # Files to ignore in find ... statements + + RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS \ +- -o -name .pc -o -name .hg -o -name .git -o -name meta \) -prune -o ++ -o -name .pc -o -name .hg -o -name .git \) -prune -o + export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn \ + --exclude CVS --exclude .pc --exclude .hg --exclude .git + +@@ -624,7 +624,7 @@ endif + + ifdef CONFIG_FUNCTION_TRACER + ifdef CONFIG_HAVE_FENTRY +-CC_USING_FENTRY := $(call cc-option, -mfentry -DCC_USING_FENTRY -grecord-gcc-switches) ++CC_USING_FENTRY := $(call cc-option, -mfentry -DCC_USING_FENTRY) + endif + KBUILD_CFLAGS += -pg $(CC_USING_FENTRY) + KBUILD_AFLAGS += $(CC_USING_FENTRY) +diff --git a/arch/arm/Makefile b/arch/arm/Makefile +index 621078ca..044aadb 100644 +--- a/arch/arm/Makefile ++++ b/arch/arm/Makefile +@@ -296,9 +296,6 @@ archprepare: + # Convert bzImage to zImage + bzImage: zImage + +-# These targets cannot be built in parallel +-.NOTPARALLEL: zImage Image xipImage bootpImage uImage +- + zImage Image xipImage bootpImage uImage: vmlinux + $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@ + +diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile +index 007829d..d810b01 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -153,6 +153,7 @@ dtb-$(CONFIG_ARCH_VT8500) += vt8500-bv07.dtb \ + wm8505-ref.dtb \ + wm8650-mid.dtb + dtb-$(CONFIG_ARCH_ZYNQ) += zynq-zc702.dtb \ ++ zynq-zc702-base-trd.dtb \ + zynq-afx-nand.dtb \ + zynq-afx-nor.dtb \ + zynq-zc706.dtb \ +diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi +index 02b70a4..cb7bcc5 100644 +--- a/arch/arm/boot/dts/at91sam9260.dtsi ++++ b/arch/arm/boot/dts/at91sam9260.dtsi +@@ -158,8 +158,8 @@ + usart1 { + pinctrl_usart1: usart1-0 { + atmel,pins = +- <1 6 0x1 0x1 /* PB6 periph A with pullup */ +- 1 7 0x1 0x0>; /* PB7 periph A */ ++ <2 6 0x1 0x1 /* PB6 periph A with pullup */ ++ 2 7 0x1 0x0>; /* PB7 periph A */ + }; + + pinctrl_usart1_rts: usart1_rts-0 { +@@ -194,18 +194,18 @@ + usart3 { + pinctrl_usart3: usart3-0 { + atmel,pins = +- <1 10 0x1 0x1 /* PB10 periph A with pullup */ +- 1 11 0x1 0x0>; /* PB11 periph A */ ++ <2 10 0x1 0x1 /* PB10 periph A with pullup */ ++ 2 11 0x1 0x0>; /* PB11 periph A */ + }; + + pinctrl_usart3_rts: usart3_rts-0 { + atmel,pins = +- <2 8 0x2 0x0>; /* PC8 periph B */ ++ <3 8 0x2 0x0>; /* PB8 periph B */ + }; + + pinctrl_usart3_cts: usart3_cts-0 { + atmel,pins = +- <2 10 0x2 0x0>; /* PC10 periph B */ ++ <3 10 0x2 0x0>; /* PB10 periph B */ + }; + }; + +@@ -220,8 +220,8 @@ + uart1 { + pinctrl_uart1: uart1-0 { + atmel,pins = +- <1 12 0x1 0x1 /* PB12 periph A with pullup */ +- 1 13 0x1 0x0>; /* PB13 periph A */ ++ <2 12 0x1 0x1 /* PB12 periph A with pullup */ ++ 2 13 0x1 0x0>; /* PB13 periph A */ + }; + }; + +diff --git a/arch/arm/boot/dts/at91sam9g15.dtsi b/arch/arm/boot/dts/at91sam9g15.dtsi +index 28467fd..fbe7a70 100644 +--- a/arch/arm/boot/dts/at91sam9g15.dtsi ++++ b/arch/arm/boot/dts/at91sam9g15.dtsi +@@ -10,7 +10,7 @@ + + / { + model = "Atmel AT91SAM9G15 SoC"; +- compatible = "atmel,at91sam9g15", "atmel,at91sam9x5"; ++ compatible = "atmel, at91sam9g15, atmel,at91sam9x5"; + + ahb { + apb { +diff --git a/arch/arm/boot/dts/at91sam9g15ek.dts b/arch/arm/boot/dts/at91sam9g15ek.dts +index 5427b2d..86dd3f6 100644 +--- a/arch/arm/boot/dts/at91sam9g15ek.dts ++++ b/arch/arm/boot/dts/at91sam9g15ek.dts +@@ -11,6 +11,6 @@ + /include/ "at91sam9x5ek.dtsi" + + / { +- model = "Atmel AT91SAM9G15-EK"; ++ model = "Atmel AT91SAM9G25-EK"; + compatible = "atmel,at91sam9g15ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9"; + }; +diff --git a/arch/arm/boot/dts/at91sam9g25.dtsi b/arch/arm/boot/dts/at91sam9g25.dtsi +index 5fd32df..05a718f 100644 +--- a/arch/arm/boot/dts/at91sam9g25.dtsi ++++ b/arch/arm/boot/dts/at91sam9g25.dtsi +@@ -10,7 +10,7 @@ + + / { + model = "Atmel AT91SAM9G25 SoC"; +- compatible = "atmel,at91sam9g25", "atmel,at91sam9x5"; ++ compatible = "atmel, at91sam9g25, atmel,at91sam9x5"; + + ahb { + apb { +diff --git a/arch/arm/boot/dts/at91sam9g35.dtsi b/arch/arm/boot/dts/at91sam9g35.dtsi +index d6fa8af..f9d14a7 100644 +--- a/arch/arm/boot/dts/at91sam9g35.dtsi ++++ b/arch/arm/boot/dts/at91sam9g35.dtsi +@@ -10,7 +10,7 @@ + + / { + model = "Atmel AT91SAM9G35 SoC"; +- compatible = "atmel,at91sam9g35", "atmel,at91sam9x5"; ++ compatible = "atmel, at91sam9g35, atmel,at91sam9x5"; + + ahb { + apb { +diff --git a/arch/arm/boot/dts/at91sam9x25.dtsi b/arch/arm/boot/dts/at91sam9x25.dtsi +index 9ac2bc2..54eb33b 100644 +--- a/arch/arm/boot/dts/at91sam9x25.dtsi ++++ b/arch/arm/boot/dts/at91sam9x25.dtsi +@@ -10,7 +10,7 @@ + + / { + model = "Atmel AT91SAM9X25 SoC"; +- compatible = "atmel,at91sam9x25", "atmel,at91sam9x5"; ++ compatible = "atmel, at91sam9x25, atmel,at91sam9x5"; + + ahb { + apb { +diff --git a/arch/arm/boot/dts/at91sam9x35.dtsi b/arch/arm/boot/dts/at91sam9x35.dtsi +index ba67d83..fb102d6 100644 +--- a/arch/arm/boot/dts/at91sam9x35.dtsi ++++ b/arch/arm/boot/dts/at91sam9x35.dtsi +@@ -10,7 +10,7 @@ + + / { + model = "Atmel AT91SAM9X35 SoC"; +- compatible = "atmel,at91sam9x35", "atmel,at91sam9x5"; ++ compatible = "atmel, at91sam9x35, atmel,at91sam9x5"; + + ahb { + apb { +diff --git a/arch/arm/boot/dts/at91sam9x5ek.dtsi b/arch/arm/boot/dts/at91sam9x5ek.dtsi +index ccab256..8a7cf1d 100644 +--- a/arch/arm/boot/dts/at91sam9x5ek.dtsi ++++ b/arch/arm/boot/dts/at91sam9x5ek.dtsi +@@ -13,7 +13,7 @@ + compatible = "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9"; + + chosen { +- bootargs = "console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:rootfs"; ++ bootargs = "128M console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:rootfs"; + }; + + ahb { +diff --git a/arch/arm/boot/dts/zynq-7000.dtsi b/arch/arm/boot/dts/zynq-7000.dtsi +index 401c126..14fb2e6 100644 +--- a/arch/arm/boot/dts/zynq-7000.dtsi ++++ b/arch/arm/boot/dts/zynq-7000.dtsi +@@ -15,6 +15,13 @@ + / { + compatible = "xlnx,zynq-7000"; + ++ pmu { ++ compatible = "arm,cortex-a9-pmu"; ++ interrupts = <0 5 4>, <0 6 4>; ++ interrupt-parent = <&intc>; ++ reg = < 0xf8891000 0x1000 0xf8893000 0x1000 >; ++ }; ++ + amba { + compatible = "simple-bus"; + #address-cells = <1>; +@@ -44,14 +51,14 @@ + compatible = "xlnx,xuartps"; + reg = <0xE0000000 0x1000>; + interrupts = <0 27 4>; +- clock = <50000000>; ++ clocks = <&uart_clk 0>; + }; + + uart1: uart@e0001000 { + compatible = "xlnx,xuartps"; + reg = <0xE0001000 0x1000>; + interrupts = <0 50 4>; +- clock = <50000000>; ++ clocks = <&uart_clk 1>; + }; + + slcr: slcr@f8000000 { +@@ -111,56 +118,30 @@ + }; + + ttc0: ttc0@f8001000 { +- #address-cells = <1>; +- #size-cells = <0>; +- compatible = "xlnx,ttc"; ++ interrupt-parent = <&intc>; ++ interrupts = < 0 10 4 0 11 4 0 12 4 >; ++ compatible = "cdns,ttc"; + reg = <0xF8001000 0x1000>; + clocks = <&cpu_clk 3>; + clock-names = "cpu_1x"; + clock-ranges; +- +- ttc0_0: ttc0.0 { +- status = "disabled"; +- reg = <0>; +- interrupts = <0 10 4>; +- }; +- ttc0_1: ttc0.1 { +- status = "disabled"; +- reg = <1>; +- interrupts = <0 11 4>; +- }; +- ttc0_2: ttc0.2 { +- status = "disabled"; +- reg = <2>; +- interrupts = <0 12 4>; +- }; + }; + + ttc1: ttc1@f8002000 { +- #interrupt-parent = <&intc>; +- #address-cells = <1>; +- #size-cells = <0>; +- compatible = "xlnx,ttc"; ++ interrupt-parent = <&intc>; ++ interrupts = < 0 37 4 0 38 4 0 39 4 >; ++ compatible = "cdns,ttc"; + reg = <0xF8002000 0x1000>; + clocks = <&cpu_clk 3>; + clock-names = "cpu_1x"; + clock-ranges; +- +- ttc1_0: ttc1.0 { +- status = "disabled"; +- reg = <0>; +- interrupts = <0 37 4>; +- }; +- ttc1_1: ttc1.1 { +- status = "disabled"; +- reg = <1>; +- interrupts = <0 38 4>; +- }; +- ttc1_2: ttc1.2 { +- status = "disabled"; +- reg = <2>; +- interrupts = <0 39 4>; +- }; + }; ++ scutimer: scutimer@f8f00600 { ++ interrupt-parent = <&intc>; ++ interrupts = < 1 13 0x301 >; ++ compatible = "arm,cortex-a9-twd-timer"; ++ reg = < 0xf8f00600 0x20 >; ++ clocks = <&cpu_clk 1>; ++ } ; + }; + }; +diff --git a/arch/arm/boot/dts/zynq-afx-nand.dts b/arch/arm/boot/dts/zynq-afx-nand.dts +index ab4b0b6..668a181 100644 +--- a/arch/arm/boot/dts/zynq-afx-nand.dts ++++ b/arch/arm/boot/dts/zynq-afx-nand.dts +@@ -1,127 +1,222 @@ +-/dts-v1/; ++/* ++ * Device Tree Generator version: 1.1 ++ * ++ * (C) Copyright 2007-2013 Xilinx, Inc. ++ * (C) Copyright 2007-2013 Michal Simek ++ * (C) Copyright 2007-2012 PetaLogix Qld Pty Ltd ++ * ++ * Michal SIMEK ++ * ++ * CAUTION: This file is automatically generated by libgen. ++ * Version: Xilinx EDK 14.5 EDK_P.58f ++ * ++ */ + ++/dts-v1/; + / { +- model = "Xilinx Zynq - AFX (NAND Module)"; +- compatible = "xlnx,zynq-zc770"; +- #address-cells = <0x1>; +- #size-cells = <0x1>; +- interrupt-parent = <0x1>; +- +- memory { +- device_type = "memory"; +- reg = <0x0 0x08000000>; +- }; +- ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "xlnx,zynq-7000"; ++ model = "Xilinx Zynq"; ++ aliases { ++ serial0 = &ps7_uart_1; ++ } ; + chosen { + bootargs = "console=ttyPS0,115200 root=/dev/ram rw earlyprintk"; +- linux,stdout-path = "/amba@0/uart@E0001000"; +- }; +- ++ linux,stdout-path = "/amba@0/serial@e0001000"; ++ } ; ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ps7_cortexa9_0: cpu@0 { ++ bus-handle = <&ps7_axi_interconnect_0>; ++ compatible = "arm,cortex-a9"; ++ d-cache-line-size = <0x20>; ++ d-cache-size = <0x8000>; ++ device_type = "cpu"; ++ i-cache-line-size = <0x20>; ++ i-cache-size = <0x8000>; ++ interrupt-handle = <&ps7_scugic_0>; ++ reg = <0x0>; ++ } ; ++ ps7_cortexa9_1: cpu@1 { ++ bus-handle = <&ps7_axi_interconnect_0>; ++ compatible = "arm,cortex-a9"; ++ d-cache-line-size = <0x20>; ++ d-cache-size = <0x8000>; ++ device_type = "cpu"; ++ i-cache-line-size = <0x20>; ++ i-cache-size = <0x8000>; ++ interrupt-handle = <&ps7_scugic_0>; ++ reg = <0x1>; ++ } ; ++ } ; + pmu { + compatible = "arm,cortex-a9-pmu"; ++ interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 5 4>, <0 6 4>; +- interrupt-parent = <&gic>; +- }; +- +- amba@0 { +- compatible = "simple-bus"; +- #address-cells = <0x1>; +- #size-cells = <0x1>; +- ranges; +- +- gic: intc@f8f01000 { +- interrupt-controller; +- compatible = "arm,cortex-a9-gic"; +- #interrupt-cells = <3>; +- reg = < 0xf8f01000 0x1000 >, +- < 0xf8f00100 0x0100 >; +- }; +- +- pl310@f8f02000 { +- compatible = "arm,pl310-cache"; +- cache-unified; +- cache-level = <2>; +- reg = <0xf8f02000 0x1000>; +- arm,data-latency = <3 2 2>; +- arm,tag-latency = <2 2 2>; +- }; +- ++ reg = <0xf8891000 0x1000>, <0xf8893000 0x1000>; ++ reg-names = "cpu0", "cpu1"; ++ } ; ++ ps7_ddr_0: memory@0 { ++ device_type = "memory"; ++ reg = <0x0 0x8000000>; ++ } ; ++ ps7_axi_interconnect_0: amba@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "xlnx,ps7-axi-interconnect-1.00.a", "simple-bus"; ++ ranges ; ++ ps7_afi_0: ps7-afi@f8008000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf8008000 0x1000>; ++ } ; ++ ps7_afi_1: ps7-afi@f8009000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf8009000 0x1000>; ++ } ; ++ ps7_afi_2: ps7-afi@f800a000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf800a000 0x1000>; ++ } ; ++ ps7_afi_3: ps7-afi@f800b000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf800b000 0x1000>; ++ } ; + ps7_ddrc_0: ps7-ddrc@f8006000 { + compatible = "xlnx,ps7-ddrc-1.00.a", "xlnx,ps7-ddrc"; +- reg = < 0xf8006000 0x1000 >; ++ reg = <0xf8006000 0x1000>; + xlnx,has-ecc = <0x0>; + } ; +- +- ps7_ocm_0: ps7-ocm@0xfffc0000 { +- compatible = "xlnx,ps7-ocm"; +- reg = <0xfffc0000 0x40000>; /* 256k */ +- }; +- +- uart@e0001000 { +- compatible = "xlnx,ps7-uart-1.00.a"; +- reg = <0xE0001000 0x1000>; +- interrupts = <0 50 0>; +- interrupt-parent = <&gic>; +- clock = <50000000>; +- }; +- +- slcr: slcr@f8000000 { +- compatible = "xlnx,zynq-slcr"; +- reg = <0xF8000000 0x1000>; ++ ps7_dev_cfg_0: ps7-dev-cfg@f8007000 { ++ clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3"; ++ clocks = <&clkc 12>, <&clkc 15>, <&clkc 16>, <&clkc 17>, <&clkc 18>; ++ compatible = "xlnx,ps7-dev-cfg-1.00.a"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 8 4>; ++ reg = <0xf8007000 0x100>; ++ } ; ++ ps7_dma_s: ps7-dma@f8003000 { ++ #dma-cells = <1>; ++ #dma-channels = <8>; ++ #dma-requests = <4>; ++ arm,primecell-periphid = <0x41330>; ++ clock-names = "apb_pclk"; ++ clocks = <&clkc 27>; ++ compatible = "xlnx,ps7-dma-1.00.a", "arm,primecell", "arm,pl330"; ++ interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3", ++ "dma4", "dma5", "dma6", "dma7"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 13 4>, <0 14 4>, <0 15 4>, <0 16 4>, <0 17 4>, <0 40 4>, <0 41 4>, <0 42 4>, <0 43 4>; ++ reg = <0xf8003000 0x1000>; ++ } ; ++ ps7_gpio_0: ps7-gpio@e000a000 { ++ #gpio-cells = <2>; ++ clocks = <&clkc 42>; ++ compatible = "xlnx,ps7-gpio-1.00.a"; ++ emio-gpio-width = <64>; ++ gpio-controller ; ++ gpio-mask-high = <0x3cffff>; ++ gpio-mask-low = <0xff008002>; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 20 4>; ++ reg = <0xe000a000 0x1000>; ++ } ; ++ ps7_iop_bus_config_0: ps7-iop-bus-config@e0200000 { ++ compatible = "xlnx,ps7-iop-bus-config-1.00.a"; ++ reg = <0xe0200000 0x1000>; ++ } ; ++ ps7_pl310_0: ps7-pl310@f8f02000 { ++ arm,data-latency = <3 2 2>; ++ arm,tag-latency = <2 2 2>; ++ cache-level = <2>; ++ cache-unified ; ++ compatible = "xlnx,ps7-pl310-1.00.a", "arm,pl310-cache"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 2 4>; ++ reg = <0xf8f02000 0x1000>; ++ } ; ++ ps7_ram_0: ps7-ram@0 { ++ compatible = "xlnx,ps7-ram-1.00.a", "xlnx,ps7-ocm"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 3 4>; ++ reg = <0xfffc0000 0x40000>; ++ } ; ++ ps7_scugic_0: ps7-scugic@f8f01000 { ++ #address-cells = <2>; ++ #interrupt-cells = <3>; ++ #size-cells = <1>; ++ compatible = "xlnx,ps7-scugic-1.00.a", "arm,cortex-a9-gic", "arm,gic"; ++ interrupt-controller ; ++ num_cpus = <2>; ++ num_interrupts = <96>; ++ reg = <0xf8f01000 0x1000>, <0xf8f00100 0x100>; ++ } ; ++ ps7_scutimer_0: ps7-scutimer@f8f00600 { ++ clocks = <&clkc 4>; ++ compatible = "xlnx,ps7-scutimer-1.00.a", "arm,cortex-a9-twd-timer"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <1 13 0x301>; ++ reg = <0xf8f00600 0x20>; ++ } ; ++ ps7_scuwdt_0: ps7-scuwdt@f8f00620 { ++ clocks = <&clkc 4>; ++ compatible = "xlnx,ps7-scuwdt-1.00.a"; ++ device_type = "watchdog"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <1 14 0x301>; ++ reg = <0xf8f00620 0xe0>; ++ } ; ++ ps7_slcr_0: ps7-slcr@f8000000 { ++ compatible = "xlnx,ps7-slcr-1.00.a", "xlnx,zynq-slcr"; ++ reg = <0xf8000000 0x1000>; + clocks { + #address-cells = <1>; + #size-cells = <0>; +- armpll: armpll { +- #clock-cells = <0>; +- clock-output-names = "armpll"; +- clocks = <&ps_clk>; +- compatible = "xlnx,zynq-pll"; +- lockbit = <0>; +- reg = < 0x100 0x110 0x10c >; +- } ; +- ddrpll: ddrpll { +- #clock-cells = <0>; +- clock-output-names = "ddrpll"; +- clocks = <&ps_clk>; +- compatible = "xlnx,zynq-pll"; +- lockbit = <1>; +- reg = < 0x104 0x114 0x10c >; +- } ; +- iopll: iopll { +- #clock-cells = <0>; +- clock-output-names = "iopll"; +- clocks = <&ps_clk>; +- compatible = "xlnx,zynq-pll"; +- lockbit = <2>; +- reg = < 0x108 0x118 0x10c >; +- } ; +- ps_clk: ps_clk { +- #clock-cells = <0>; +- clock-frequency = <33333333>; +- clock-output-names = "ps_clk"; +- compatible = "fixed-clock"; ++ clkc: clkc { ++ #clock-cells = <1>; ++ clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x", "cpu_3or2x", ++ "cpu_2x", "cpu_1x", "ddr2x", "ddr3x", "dci", ++ "lqspi", "smc", "pcap", "gem0", "gem1", ++ "fclk0", "fclk1", "fclk2", "fclk3", "can0", ++ "can1", "sdio0", "sdio1", "uart0", "uart1", ++ "spi0", "spi1", "dma", "usb0_aper", "usb1_aper", ++ "gem0_aper", "gem1_aper", "sdio0_aper", "sdio1_aper", "spi0_aper", ++ "spi1_aper", "can0_aper", "can1_aper", "i2c0_aper", "i2c1_aper", ++ "uart0_aper", "uart1_aper", "gpio_aper", "lqspi_aper", "smc_aper", ++ "swdt", "dbg_trc", "dbg_apb"; ++ compatible = "xlnx,ps7-clkc"; ++ fclk-enable = <0xf>; ++ ps-clk-frequency = <33333333>; + } ; + } ; +- }; +- +- timer@0xf8001000 { +- compatible = "xlnx,ps7-ttc-1.00.a"; +- reg = <0xf8001000 0x1000>; +- interrupts = <0 10 0>,<0 11 0>,<0 12 0>; +- interrupt-parent = <&gic>; +- }; +- +- smc@0xe000e000 { +- compatible = "xlnx,ps7-smc"; +- reg = <0xe000e000 0x1000>; ++ } ; ++ ps7_smcc_0: ps7-smcc@e000e000 { + #address-cells = <1>; + #size-cells = <1>; +- ranges; +- +- nand@e1000000 { ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 11>, <&clkc 44>; ++ compatible = "xlnx,ps7-smcc-1.00.a", "xlnx,ps7-smc"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 18 4>; ++ ranges ; ++ reg = <0xe000e000 0x1000>; ++ xlnx,addr25 = <0x0>; ++ xlnx,nor-chip-sel0 = <0x0>; ++ xlnx,nor-chip-sel1 = <0x0>; ++ xlnx,sram-chip-sel0 = <0x0>; ++ xlnx,sram-chip-sel1 = <0x0>; ++ ps7_nand_0: ps7-nand@e1000000 { + compatible = "xlnx,ps7-nand-1.00.a"; + reg = <0xe1000000 0x1000000>; +- xlnx,nand-width = <16>; ++ xlnx,nand-cycle-t0 = <0x4>; ++ xlnx,nand-cycle-t1 = <0x4>; ++ xlnx,nand-cycle-t2 = <0x1>; ++ xlnx,nand-cycle-t3 = <0x2>; ++ xlnx,nand-cycle-t4 = <0x2>; ++ xlnx,nand-cycle-t5 = <0x2>; ++ xlnx,nand-cycle-t6 = <0x4>; ++ xlnx,nand-width = <0x10>; + #address-cells = <0x1>; + #size-cells = <0x1>; + +@@ -146,8 +241,52 @@ + reg = <0xC00000 0x400000>; + + }; +- }; +- }; +- +- }; +-}; ++ } ; ++ } ; ++ ps7_ttc_0: ps7-ttc@f8001000 { ++ clocks = <&clkc 6>; ++ compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; ++ interrupt-names = "ttc0", "ttc1", "ttc2"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 10 4>, <0 11 4>, <0 12 4>; ++ reg = <0xf8001000 0x1000>; ++ } ; ++ ps7_ttc_1: ps7-ttc@f8002000 { ++ clocks = <&clkc 6>; ++ compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; ++ interrupt-names = "ttc0", "ttc1", "ttc2"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 37 4>, <0 38 4>, <0 39 4>; ++ reg = <0xf8002000 0x1000>; ++ } ; ++ ps7_uart_1: serial@e0001000 { ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 24>, <&clkc 41>; ++ compatible = "xlnx,ps7-uart-1.00.a", "xlnx,xuartps"; ++ current-speed = <115200>; ++ device_type = "serial"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 50 4>; ++ port-number = <0>; ++ reg = <0xe0001000 0x1000>; ++ xlnx,has-modem = <0x0>; ++ } ; ++ ps7_wdt_0: ps7-wdt@f8005000 { ++ clocks = <&clkc 45>; ++ compatible = "xlnx,ps7-wdt-1.00.a"; ++ device_type = "watchdog"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 9 1>; ++ reg = <0xf8005000 0x1000>; ++ reset = <0>; ++ timeout = <10>; ++ } ; ++ ps7_xadc: ps7-xadc@f8007100 { ++ clocks = <&clkc 12>; ++ compatible = "xlnx,ps7-xadc-1.00.a"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 7 4>; ++ reg = <0xf8007100 0x20>; ++ } ; ++ } ; ++} ; +diff --git a/arch/arm/boot/dts/zynq-afx-nor.dts b/arch/arm/boot/dts/zynq-afx-nor.dts +index a874ca9..cf8f8b1 100644 +--- a/arch/arm/boot/dts/zynq-afx-nor.dts ++++ b/arch/arm/boot/dts/zynq-afx-nor.dts +@@ -1,127 +1,210 @@ +-/dts-v1/; ++/* ++ * Device Tree Generator version: 1.1 ++ * ++ * (C) Copyright 2007-2013 Xilinx, Inc. ++ * (C) Copyright 2007-2013 Michal Simek ++ * (C) Copyright 2007-2012 PetaLogix Qld Pty Ltd ++ * ++ * Michal SIMEK ++ * ++ * CAUTION: This file is automatically generated by libgen. ++ * Version: Xilinx EDK 14.5 EDK_P.58f ++ * ++ */ + ++/dts-v1/; + / { +- model = "Xilinx Zynq AFX (NOR Module)"; +- compatible = "xlnx,zynq-zc770"; +- #address-cells = <0x1>; +- #size-cells = <0x1>; +- interrupt-parent = <0x1>; +- +- memory { +- device_type = "memory"; +- reg = <0x0 0x08000000>; +- }; +- ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "xlnx,zynq-7000"; ++ model = "Xilinx Zynq"; ++ aliases { ++ serial0 = &ps7_uart_1; ++ } ; + chosen { + bootargs = "console=ttyPS0,115200 root=/dev/ram rw earlyprintk"; +- linux,stdout-path = "/amba@0/uart@E0001000"; +- }; +- ++ linux,stdout-path = "/amba@0/serial@e0001000"; ++ } ; ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ps7_cortexa9_0: cpu@0 { ++ bus-handle = <&ps7_axi_interconnect_0>; ++ compatible = "arm,cortex-a9"; ++ d-cache-line-size = <0x20>; ++ d-cache-size = <0x8000>; ++ device_type = "cpu"; ++ i-cache-line-size = <0x20>; ++ i-cache-size = <0x8000>; ++ interrupt-handle = <&ps7_scugic_0>; ++ reg = <0x0>; ++ } ; ++ ps7_cortexa9_1: cpu@1 { ++ bus-handle = <&ps7_axi_interconnect_0>; ++ compatible = "arm,cortex-a9"; ++ d-cache-line-size = <0x20>; ++ d-cache-size = <0x8000>; ++ device_type = "cpu"; ++ i-cache-line-size = <0x20>; ++ i-cache-size = <0x8000>; ++ interrupt-handle = <&ps7_scugic_0>; ++ reg = <0x1>; ++ } ; ++ } ; + pmu { + compatible = "arm,cortex-a9-pmu"; ++ interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 5 4>, <0 6 4>; +- interrupt-parent = <&gic>; +- }; +- +- amba@0 { +- compatible = "simple-bus"; +- #address-cells = <0x1>; +- #size-cells = <0x1>; +- ranges; +- +- gic: intc@f8f01000 { +- interrupt-controller; +- compatible = "arm,cortex-a9-gic"; +- #interrupt-cells = <3>; +- reg = < 0xf8f01000 0x1000 >, +- < 0xf8f00100 0x0100 >; +- }; +- +- pl310@f8f02000 { +- compatible = "arm,pl310-cache"; +- cache-unified; +- cache-level = <2>; +- reg = <0xf8f02000 0x1000>; +- arm,data-latency = <3 2 2>; +- arm,tag-latency = <2 2 2>; +- }; +- ++ reg = <0xf8891000 0x1000>, <0xf8893000 0x1000>; ++ reg-names = "cpu0", "cpu1"; ++ } ; ++ ps7_ddr_0: memory@0 { ++ device_type = "memory"; ++ reg = <0x0 0x8000000>; ++ } ; ++ ps7_axi_interconnect_0: amba@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "xlnx,ps7-axi-interconnect-1.00.a", "simple-bus"; ++ ranges ; ++ ps7_afi_0: ps7-afi@f8008000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf8008000 0x1000>; ++ } ; ++ ps7_afi_1: ps7-afi@f8009000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf8009000 0x1000>; ++ } ; ++ ps7_afi_2: ps7-afi@f800a000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf800a000 0x1000>; ++ } ; ++ ps7_afi_3: ps7-afi@f800b000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf800b000 0x1000>; ++ } ; + ps7_ddrc_0: ps7-ddrc@f8006000 { + compatible = "xlnx,ps7-ddrc-1.00.a", "xlnx,ps7-ddrc"; +- reg = < 0xf8006000 0x1000 >; ++ reg = <0xf8006000 0x1000>; + xlnx,has-ecc = <0x0>; + } ; +- +- ps7_ocm_0: ps7-ocm@0xfffc0000 { +- compatible = "xlnx,ps7-ocm"; +- reg = <0xfffc0000 0x40000>; /* 256k */ +- }; +- +- uart@e0001000 { +- compatible = "xlnx,ps7-uart-1.00.a"; +- reg = <0xE0001000 0x1000>; +- interrupts = <0 50 0>; +- interrupt-parent = <&gic>; +- clock = <50000000>; +- }; +- +- slcr: slcr@f8000000 { +- compatible = "xlnx,zynq-slcr"; +- reg = <0xF8000000 0x1000>; ++ ps7_dev_cfg_0: ps7-dev-cfg@f8007000 { ++ clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3"; ++ clocks = <&clkc 12>, <&clkc 15>, <&clkc 16>, <&clkc 17>, <&clkc 18>; ++ compatible = "xlnx,ps7-dev-cfg-1.00.a"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 8 4>; ++ reg = <0xf8007000 0x100>; ++ } ; ++ ps7_dma_s: ps7-dma@f8003000 { ++ #dma-cells = <1>; ++ #dma-channels = <8>; ++ #dma-requests = <4>; ++ arm,primecell-periphid = <0x41330>; ++ clock-names = "apb_pclk"; ++ clocks = <&clkc 27>; ++ compatible = "xlnx,ps7-dma-1.00.a", "arm,primecell", "arm,pl330"; ++ interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3", ++ "dma4", "dma5", "dma6", "dma7"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 13 4>, <0 14 4>, <0 15 4>, <0 16 4>, <0 17 4>, <0 40 4>, <0 41 4>, <0 42 4>, <0 43 4>; ++ reg = <0xf8003000 0x1000>; ++ } ; ++ ps7_iop_bus_config_0: ps7-iop-bus-config@e0200000 { ++ compatible = "xlnx,ps7-iop-bus-config-1.00.a"; ++ reg = <0xe0200000 0x1000>; ++ } ; ++ ps7_pl310_0: ps7-pl310@f8f02000 { ++ arm,data-latency = <3 2 2>; ++ arm,tag-latency = <2 2 2>; ++ cache-level = <2>; ++ cache-unified ; ++ compatible = "xlnx,ps7-pl310-1.00.a", "arm,pl310-cache"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 2 4>; ++ reg = <0xf8f02000 0x1000>; ++ } ; ++ ps7_ram_0: ps7-ram@0 { ++ compatible = "xlnx,ps7-ram-1.00.a", "xlnx,ps7-ocm"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 3 4>; ++ reg = <0xfffc0000 0x40000>; ++ } ; ++ ps7_scugic_0: ps7-scugic@f8f01000 { ++ #address-cells = <2>; ++ #interrupt-cells = <3>; ++ #size-cells = <1>; ++ compatible = "xlnx,ps7-scugic-1.00.a", "arm,cortex-a9-gic", "arm,gic"; ++ interrupt-controller ; ++ num_cpus = <2>; ++ num_interrupts = <96>; ++ reg = <0xf8f01000 0x1000>, <0xf8f00100 0x100>; ++ } ; ++ ps7_scutimer_0: ps7-scutimer@f8f00600 { ++ clocks = <&clkc 4>; ++ compatible = "xlnx,ps7-scutimer-1.00.a", "arm,cortex-a9-twd-timer"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <1 13 0x301>; ++ reg = <0xf8f00600 0x20>; ++ } ; ++ ps7_scuwdt_0: ps7-scuwdt@f8f00620 { ++ clocks = <&clkc 4>; ++ compatible = "xlnx,ps7-scuwdt-1.00.a"; ++ device_type = "watchdog"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <1 14 0x301>; ++ reg = <0xf8f00620 0xe0>; ++ } ; ++ ps7_slcr_0: ps7-slcr@f8000000 { ++ compatible = "xlnx,ps7-slcr-1.00.a", "xlnx,zynq-slcr"; ++ reg = <0xf8000000 0x1000>; + clocks { + #address-cells = <1>; + #size-cells = <0>; +- armpll: armpll { +- #clock-cells = <0>; +- clock-output-names = "armpll"; +- clocks = <&ps_clk>; +- compatible = "xlnx,zynq-pll"; +- lockbit = <0>; +- reg = < 0x100 0x110 0x10c >; +- } ; +- ddrpll: ddrpll { +- #clock-cells = <0>; +- clock-output-names = "ddrpll"; +- clocks = <&ps_clk>; +- compatible = "xlnx,zynq-pll"; +- lockbit = <1>; +- reg = < 0x104 0x114 0x10c >; +- } ; +- iopll: iopll { +- #clock-cells = <0>; +- clock-output-names = "iopll"; +- clocks = <&ps_clk>; +- compatible = "xlnx,zynq-pll"; +- lockbit = <2>; +- reg = < 0x108 0x118 0x10c >; +- } ; +- ps_clk: ps_clk { +- #clock-cells = <0>; +- clock-frequency = <33333333>; +- clock-output-names = "ps_clk"; +- compatible = "fixed-clock"; ++ clkc: clkc { ++ #clock-cells = <1>; ++ clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x", "cpu_3or2x", ++ "cpu_2x", "cpu_1x", "ddr2x", "ddr3x", "dci", ++ "lqspi", "smc", "pcap", "gem0", "gem1", ++ "fclk0", "fclk1", "fclk2", "fclk3", "can0", ++ "can1", "sdio0", "sdio1", "uart0", "uart1", ++ "spi0", "spi1", "dma", "usb0_aper", "usb1_aper", ++ "gem0_aper", "gem1_aper", "sdio0_aper", "sdio1_aper", "spi0_aper", ++ "spi1_aper", "can0_aper", "can1_aper", "i2c0_aper", "i2c1_aper", ++ "uart0_aper", "uart1_aper", "gpio_aper", "lqspi_aper", "smc_aper", ++ "swdt", "dbg_trc", "dbg_apb"; ++ compatible = "xlnx,ps7-clkc"; ++ fclk-enable = <0xf>; ++ ps-clk-frequency = <33333333>; + } ; + } ; +- }; +- +- timer@0xf8001000 { +- compatible = "xlnx,ps7-ttc-1.00.a"; +- reg = <0xf8001000 0x1000>; +- interrupts = <0 10 0>,<0 11 0>,<0 12 0>; +- interrupt-parent = <&gic>; +- }; +- +- smc@0xe000e000 { +- compatible = "xlnx,ps7-smc"; +- reg = <0xe000e000 0x1000>; ++ } ; ++ ps7_smcc_0: ps7-smcc@e000e000 { + #address-cells = <1>; + #size-cells = <1>; +- ranges; +- +- nor: nor@e2000000 { +- compatible = "cfi-flash"; ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 11>, <&clkc 44>; ++ compatible = "xlnx,ps7-smcc-1.00.a", "xlnx,ps7-smc"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 18 4>; ++ ranges ; ++ reg = <0xe000e000 0x1000>; ++ xlnx,addr25 = <0x1>; ++ xlnx,nor-chip-sel0 = <0x1>; ++ xlnx,nor-chip-sel1 = <0x0>; ++ xlnx,sram-chip-sel0 = <0x0>; ++ xlnx,sram-chip-sel1 = <0x0>; ++ ps7_nor_0: ps7-nor@e2000000 { + bank-width = <1>; +- reg = <0xE2000000 0x2000000>; /* 32MB */ ++ compatible = "xlnx,ps7-nor-1.00.a", "cfi-flash"; ++ reg = <0xe2000000 0x1000>; ++ xlnx,sram-cycle-t0 = <0xb>; ++ xlnx,sram-cycle-t1 = <0xb>; ++ xlnx,sram-cycle-t2 = <0x5>; ++ xlnx,sram-cycle-t3 = <0x4>; ++ xlnx,sram-cycle-t4 = <0x3>; ++ xlnx,sram-cycle-t5 = <0x3>; ++ xlnx,sram-cycle-t6 = <0x2>; + #address-cells = <1>; + #size-cells = <1>; + +@@ -145,7 +228,43 @@ + label = "nor-bitstream"; + reg = <0xC00000 0x400000>; + }; +- }; +- }; +- }; +-}; ++ ++ } ; ++ } ; ++ ps7_ttc_0: ps7-ttc@f8001000 { ++ clocks = <&clkc 6>; ++ compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; ++ interrupt-names = "ttc0", "ttc1", "ttc2"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 10 4>, <0 11 4>, <0 12 4>; ++ reg = <0xf8001000 0x1000>; ++ } ; ++ ps7_ttc_1: ps7-ttc@f8002000 { ++ clocks = <&clkc 6>; ++ compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; ++ interrupt-names = "ttc0", "ttc1", "ttc2"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 37 4>, <0 38 4>, <0 39 4>; ++ reg = <0xf8002000 0x1000>; ++ } ; ++ ps7_uart_1: serial@e0001000 { ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 24>, <&clkc 41>; ++ compatible = "xlnx,ps7-uart-1.00.a", "xlnx,xuartps"; ++ current-speed = <115200>; ++ device_type = "serial"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 50 4>; ++ port-number = <0>; ++ reg = <0xe0001000 0x1000>; ++ xlnx,has-modem = <0x0>; ++ } ; ++ ps7_xadc: ps7-xadc@f8007100 { ++ clocks = <&clkc 12>; ++ compatible = "xlnx,ps7-xadc-1.00.a"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 7 4>; ++ reg = <0xf8007100 0x20>; ++ } ; ++ } ; ++} ; +diff --git a/arch/arm/boot/dts/zynq-zc702-base-trd.dts b/arch/arm/boot/dts/zynq-zc702-base-trd.dts +new file mode 100644 +index 0000000..56b0e0d +--- /dev/null ++++ b/arch/arm/boot/dts/zynq-zc702-base-trd.dts +@@ -0,0 +1,658 @@ ++/dts-v1/; ++ ++/ { ++ model = "Xilinx Zynq ZC702"; ++ compatible = "xlnx,zynq-zc702", "xlnx,zynq-7000"; ++ #address-cells = <0x1>; ++ #size-cells = <0x1>; ++ interrupt-parent = <0x1>; ++ aliases { ++ spi1 = &qspi0; ++ }; ++ memory { ++ device_type = "memory"; ++ reg = <0x00000000 0x40000000>; ++ }; ++ chosen { ++ bootargs = "console=tty0 console=ttyPS0,115200 root=/dev/ram rw ip=192.168.1.10:::255.255.255.0:ZC702:eth0 earlyprintk mem=768M"; ++ linux,stdout-path = "/amba@0/uart@E0001000"; ++ }; ++ ++ pmu { ++ compatible = "arm,cortex-a9-pmu"; ++ interrupts = <0 5 4>, <0 6 4>; ++ interrupt-parent = <&gic>; ++ }; ++ ++ amba@0 { ++ compatible = "simple-bus"; ++ #address-cells = <0x1>; ++ #size-cells = <0x1>; ++ ranges; ++ ++ gic: intc@f8f01000 { ++ interrupt-controller; ++ compatible = "arm,cortex-a9-gic"; ++ #interrupt-cells = <3>; ++ reg = <0xf8f01000 0x1000>, ++ <0xf8f00100 0x0100>; ++ }; ++ ++ pl310@f8f02000 { ++ compatible = "arm,pl310-cache"; ++ cache-unified; ++ cache-level = <2>; ++ reg = <0xf8f02000 0x1000>; ++ interrupts = <0 2 4>; ++ arm,data-latency = <3 2 2>; ++ arm,tag-latency = <2 2 2>; ++ }; ++ ++ ps7_ddrc_0: ps7-ddrc@f8006000 { ++ compatible = "xlnx,ps7-ddrc-1.00.a", "xlnx,ps7-ddrc"; ++ reg = <0xf8006000 0x1000>; ++ xlnx,has-ecc = <0x0>; ++ } ; ++ ++ ps7_ocm_0: ps7-ocm@0xfffc0000 { ++ compatible = "xlnx,ps7-ocm"; ++ reg = <0xfffc0000 0x40000>; /* 256k */ ++ }; ++ ++ uart@e0001000 { ++ compatible = "xlnx,ps7-uart-1.00.a", "xlnx,xuartps"; ++ clocks = <&clkc 24>, <&clkc 41>; ++ clock-names = "ref_clk", "aper_clk"; ++ reg = <0xe0001000 0x1000>; ++ interrupts = <0 50 4>; ++ interrupt-parent = <&gic>; ++ }; ++ ++ slcr: slcr@f8000000 { ++ compatible = "xlnx,zynq-slcr"; ++ reg = <0xF8000000 0x1000>; ++ clocks { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ clkc: clkc { ++ #clock-cells = <1>; ++ compatible = "xlnx,ps7-clkc"; ++ ps-clk-frequency = <33333333>; ++ clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x", ++ "cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x", ++ "dci", "lqspi", "smc", "pcap", "gem0", "gem1", ++ "fclk0", "fclk1", "fclk2", "fclk3", "can0", "can1", ++ "sdio0", "sdio1", "uart0", "uart1", "spi0", "spi1", ++ "dma", "usb0_aper", "usb1_aper", "gem0_aper", ++ "gem1_aper", "sdio0_aper", "sdio1_aper", ++ "spi0_aper", "spi1_aper", "can0_aper", "can1_aper", ++ "i2c0_aper", "i2c1_aper", "uart0_aper", "uart1_aper", ++ "gpio_aper", "lqspi_aper", "smc_aper", "swdt", ++ "dbg_trc", "dbg_apb"; ++ }; ++ } ; ++ }; ++ ++ timer@0xf8001000 { ++ compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; ++ clocks = <&clkc 6>; ++ reg = <0xf8001000 0x1000>; ++ interrupts = <0 10 4>,<0 11 4>,<0 12 4>; ++ interrupt-parent = <&gic>; ++ }; ++ ++ timer@f8f00600 { ++ compatible = "arm,cortex-a9-twd-timer"; ++ clocks = <&clkc 4>; ++ reg = <0xf8f00600 0x20>; ++ interrupts = <1 13 0x301>; ++ interrupt-parent = <&gic>; ++ }; ++ ++ swdt@f8005000 { ++ device_type = "watchdog"; ++ compatible = "xlnx,ps7-wdt-1.00.a"; ++ clocks = <&clkc 45>; ++ reg = <0xf8005000 0x100>; ++ interrupts = <0 9 4>; ++ interrupt-parent = <&gic>; ++ reset = <0>; ++ timeout = <10>; ++ }; ++ ++ scuwdt@f8f00620 { ++ device_type = "watchdog"; ++ compatible = "arm,mpcore_wdt"; ++ clocks = <&clkc 4>; ++ reg = <0xf8f00620 0x20>; ++ clock-frequency = <333333333>; ++ reset = <1>; ++ }; ++ ++ eth@e000b000 { ++ compatible = "xlnx,ps7-ethernet-1.00.a"; ++ clocks = <&clkc 13>, <&clkc 30>; ++ clock-names = "ref_clk", "aper_clk"; ++ reg = <0xe000b000 0x1000>; ++ interrupts = <0 22 4>; ++ interrupt-parent = <&gic>; ++ phy-handle = <&phy0>; ++ phy-mode = "rgmii-id"; ++ xlnx,ptp-enet-clock = <111111111>; ++ xlnx,slcr-div0-1000Mbps = <8>; ++ xlnx,slcr-div0-100Mbps = <8>; ++ xlnx,slcr-div0-10Mbps = <8>; ++ xlnx,slcr-div1-1000Mbps = <1>; ++ xlnx,slcr-div1-100Mbps = <5>; ++ xlnx,slcr-div1-10Mbps = <50>; ++ #address-cells = <0x1>; ++ #size-cells = <0x0>; ++ mdio { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ phy0: phy@7 { ++ compatible = "marvell,88e1116r"; ++ device_type = "ethernet-phy"; ++ reg = <7>; ++ }; ++ }; ++ }; ++ ++ i2c0: i2c@e0004000 { ++ compatible = "xlnx,ps7-i2c-1.00.a"; ++ clocks = <&clkc 38>; ++ reg = <0xE0004000 0x1000>; ++ interrupts = <0 25 4>; ++ interrupt-parent = <&gic>; ++ bus-id = <0>; ++ input-clk = <111111111>; ++ i2c-clk = <100000>; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ i2cswitch@74 { ++ compatible = "nxp,pca9548"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x74>; ++ ++ i2c@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ osc@5d { ++ compatible = "si570"; ++ reg = <0x5d>; ++ factory-fout = <156250000>; ++ initial-fout = <148500000>; ++ }; ++ }; ++ ++ i2c@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <1>; ++ hdmio@39 { ++ compatible = "adv7511"; ++ reg = <0x39>; ++ interrupts = <0 54 4>; ++ interrupt-parent = <&gic>; ++ dma-request = <&logicvc0>; ++ edid-addr = <0x50>; ++ video-input { ++ input-id = <1>; ++ input-style = <3>; ++ input-color-depth = <8>; ++ bit-justification = <1>; ++ hsync-polarity = <0>; ++ vsync-polarity = <0>; ++ clock-delay = <3>; ++ }; ++ video-output { ++ hdmi-mode = <0>; ++ output-format = <0>; ++ output-color-space = <0>; ++ up-conversion = <0>; ++ csc-enable = <1>; ++ csc-scaling-factor = <2>; ++ csc-coefficients { ++ a1 = <0x0B37>; ++ a2 = <0x0800>; ++ a3 = <0x0000>; ++ a4 = <0x1A86>; ++ b1 = <0x1A49>; ++ b2 = <0x0800>; ++ b3 = <0x1D3F>; ++ b4 = <0x0422>; ++ c1 = <0x0000>; ++ c2 = <0x0800>; ++ c3 = <0x0E2D>; ++ c4 = <0x1914>; ++ }; ++ }; ++ }; ++ }; ++ ++ i2c@2 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <2>; ++ eeprom@54 { ++ compatible = "at,24c08"; ++ reg = <0x54>; ++ }; ++ }; ++ ++ i2c@3 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <3>; ++ gpio@21 { ++ compatible = "ti,tca6416"; ++ reg = <0x21>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ }; ++ ++ i2c@4 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <4>; ++ rtc@54 { ++ compatible = "nxp,pcf8563"; ++ reg = <0x51>; ++ }; ++ }; ++ ++ i2c@5{ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <5>; ++ eeprom@50 { ++ compatible = "at,24c02"; ++ reg = <0x50>; ++ }; ++ }; ++ ++ i2c@6{ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <6>; ++ eeprom@50 { ++ compatible = "at,24c02"; ++ reg = <0x50>; ++ }; ++ }; ++ ++ i2c@7 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <7>; ++ hwmon@52 { ++ compatible = "pmbus,ucd9248"; ++ reg = <52>; ++ }; ++ hwmon@53 { ++ compatible = "pmbus,ucd9248"; ++ reg = <53>; ++ }; ++ hwmon@54 { ++ compatible = "pmbus,ucd9248"; ++ reg = <54>; ++ }; ++ }; ++ }; ++ }; ++ ++ i2c1: i2c@e0005000 { ++ compatible = "xlnx,ps7-i2c-1.00.a"; ++ clocks = <&clkc 39>; ++ reg = <0xE0005000 0x1000>; ++ interrupts = <0 48 4>; ++ interrupt-parent = <&gic>; ++ bus-id = <1>; ++ input-clk = <111111111>; ++ i2c-clk = <100000>; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ i2cswitch@70 { ++ compatible = "nxp,pca9546"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x70>; ++ ++ i2c_adv7611: i2c@2 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <2>; ++ }; ++ ++ i2c@3 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <3>; ++ ioexp: gpio@20 { ++ compatible = "nxp,pca9534"; ++ reg = <0x20>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ }; ++ }; ++ }; ++ ++ sdhci@e0100000 { ++ compatible = "xlnx,ps7-sdhci-1.00.a"; ++ clocks = <&clkc 21>, <&clkc 32>; ++ clock-names = "ref_clk", "aper_clk"; ++ reg = <0xe0100000 0x1000>; ++ xlnx,has-cd = <0x1>; ++ interrupts = <0 24 4>; ++ interrupt-parent = <&gic>; ++ clock-frequency = <33333000>; ++ }; ++ ++ usb@e0002000 { ++ compatible = "xlnx,ps7-usb-1.00.a"; ++ clocks = <&clkc 28>; ++ reg = <0xe0002000 0x1000>; ++ interrupts = <0 21 4>; ++ interrupt-parent = <&gic>; ++ dr_mode = "host"; ++ phy_type = "ulpi"; ++ }; ++ ++ gpio@e000a000 { ++ compatible = "xlnx,ps7-gpio-1.00.a"; ++ clocks = <&clkc 42>; ++ reg = <0xe000a000 0x1000>; ++ interrupts = <0 20 4>; ++ interrupt-parent = <&gic>; ++ }; ++ ++ qspi0: spi@e000d000 { ++ compatible = "xlnx,ps7-qspi-1.00.a"; ++ clocks = <&clkc 10>, <&clkc 43>; ++ clock-names = "ref_clk", "aper_clk"; ++ reg = <0xE000D000 0x1000>; ++ interrupts = <0 19 4>; ++ interrupt-parent = <&gic>; ++ speed-hz = <200000000>; ++ num-chip-select = <1>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ is-dual = <0>; ++ flash@0 { ++ compatible = "n25q128"; ++ reg = <0x0>; ++ spi-max-frequency = <50000000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ partition@qspi-fsbl-uboot { ++ label = "qspi-fsbl-uboot"; ++ reg = <0x0 0x100000>; ++ }; ++ partition@qspi-linux { ++ label = "qspi-linux"; ++ reg = <0x100000 0x500000>; ++ }; ++ partition@qspi-device-tree { ++ label = "qspi-device-tree"; ++ reg = <0x600000 0x20000>; ++ }; ++ partition@qspi-rootfs { ++ label = "qspi-rootfs"; ++ reg = <0x620000 0x5E0000>; ++ }; ++ partition@qspi-bitstream { ++ label = "qspi-bitstream"; ++ reg = <0xC00000 0x400000>; ++ }; ++ }; ++ }; ++ ++ devcfg@f8007000 { ++ compatible = "xlnx,ps7-dev-cfg-1.00.a"; ++ clocks = <&clkc 12>, <&clkc 15>, <&clkc 16>, <&clkc 17>, <&clkc 18>; ++ clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3"; ++ reg = <0xf8007000 0x100>; ++ interrupts = <0 8 4>; ++ interrupt-parent = <&gic>; ++ }; ++ ++ xadc@f8007100 { ++ compatible = "xlnx,ps7-xadc-1.00.a"; ++ clocks = <&clkc 12>; ++ reg = <0xf8007100 0x20>; ++ interrupts = <0 7 4>; ++ interrupt-parent = <&gic>; ++ }; ++ ++ ps7_dma_s: ps7-dma@f8003000 { ++ #dma-cells = <1>; ++ #dma-channels = <8>; ++ #dma-requests = <4>; ++ arm,primecell-periphid = <0x41330>; ++ compatible = "xlnx,ps7-dma-1.00.a", "arm,primecell", "arm,pl330"; ++ clocks = <&clkc 27>; ++ interrupt-parent = <&gic>; ++ interrupts = <0 13 4 0 14 4 0 15 4 0 16 4 0 17 4 0 40 4 0 41 4 0 42 4 0 43 4>; ++ reg = <0xf8003000 0x1000>; ++ }; ++ ++ axi_sobel_0: axi-sobel@0x400D0000 { ++ compatible = "generic-uio"; ++ reg = <0x400D0000 0x10000>; ++ interrupts = <0 55 4>; ++ interrupt-parent = <&gic>; ++ }; ++ ++ yuv2rgb_0: v-ycrcb2rgb@0x40050000 { ++ compatible = "generic-uio"; ++ reg = <0x40050000 0x10000>; ++ }; ++ ++ tpg_0: v-tpg@40080000 { ++ compatible = "generic-uio"; ++ reg = <0x40080000 0x10000>; ++ }; ++ ++ cresample_0: v-cresample@40040000 { ++ compatible = "generic-uio"; ++ reg = <0x40040000 0x10000>; ++ }; ++ ++ vtc_0: v-tc@40070000 { ++ compatible = "generic-uio"; ++ reg = <0x40070000 0x10000>; ++ }; ++ ++ perf_mon_hp0_hp2: axi-perf-mon@400f0000 { ++ compatible = "generic-uio"; ++ reg = <0x400f0000 0x10000>; ++ }; ++ ++ axi_vdma_0: axivdma@0x40090000 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "xlnx,axi-vdma"; ++ ranges = <0x40090000 0x40090000 0x10000>; ++ reg = <0x40090000 0x10000>; ++ xlnx,flush-fsync = <0x1>; ++ xlnx,include-sg = <0x0>; ++ xlnx,num-fstores = <0x3>; ++ xlnx,family = "zynq-770"; ++ dma-channel@0x40090000 { ++ compatible = "xlnx,axi-vdma-s2mm-channel"; ++ interrupt-parent = <&gic>; ++ interrupts = <0 58 4>; ++ xlnx,datawidth = <0x08>; ++ xlnx,genlock-mode = <0x1>; ++ xlnx,include-dre = <0x1>; ++ xlnx,device-id = <0x0>; ++ }; ++ }; ++ ++ axi_vdma_1: axivdma@0x400B0000 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "xlnx,axi-vdma"; ++ ranges = <0x400B0000 0x400B0000 0x10000>; ++ reg = <0x400B0000 0x10000>; ++ xlnx,flush-fsync = <0x1>; ++ xlnx,include-sg = <0x0>; ++ xlnx,num-fstores = <0x3>; ++ xlnx,family = "zynq-770"; ++ dma-s2mmchannel@0x400B0000 { ++ compatible = "xlnx,axi-vdma-s2mm-channel"; ++ interrupt-parent = <&gic>; ++ interrupts = <0 57 4>; ++ xlnx,datawidth = <0x08>; ++ xlnx,genlock-mode = <0x1>; ++ xlnx,include-dre = <0x1>; ++ xlnx,device-id = <0x1>; ++ }; ++ dma-mm2schannel@0x400B0000 { ++ compatible = "xlnx,axi-vdma-mm2s-channel"; ++ interrupt-parent = <&gic>; ++ interrupts = <0 56 4>; ++ xlnx,datawidth = <0x08>; ++ xlnx,genlock-mode = <0x1>; ++ xlnx,include-dre = <0x1>; ++ xlnx,device-id = <0x1>; ++ }; ++ }; ++ ++ imageon_rx { ++ compatible = "xlnx,imageon-rx"; ++ slave_adapter = <&i2c_adv7611>; ++ hpd-gpio = <&ioexp 2 0>; ++ }; ++ ++ logicvc0: logicvc@40030000 { ++ compatible = "xylon,logicvc-3.00.a"; ++ reg = <0x40030000 0x6000>; ++ interrupt-parent = <&gic>; ++ interrupts = <0 59 4>; ++ ++ xlnx,display-interface = <0>; ++ xlnx,display-color-space = <1>; ++ xlnx,ip-license-type = <0>; ++ xlnx,ip-major-revision = <3>; ++ xlnx,ip-minor-revision = <0>; ++ xlnx,ip-patch-level = <0>; ++ xlnx,num-of-layers = <3>; ++ xlnx,layer-0-type = <0>; ++ xlnx,layer-0-alpha-mode = <0>; ++ xlnx,layer-0-data-width = <16>; ++ xlnx,layer-0-offset = <0>; ++ xlnx,layer-1-type = <0>; ++ xlnx,layer-1-alpha-mode = <0>; ++ xlnx,layer-1-data-width = <24>; ++ xlnx,layer-1-offset = <1620>; ++ xlnx,layer-2-type = <0>; ++ xlnx,layer-2-alpha-mode = <0>; ++ xlnx,layer-2-data-width = <24>; ++ xlnx,layer-2-offset = <6480>; ++ xlnx,layer-3-type = <0>; ++ xlnx,layer-3-alpha-mode = <0>; ++ xlnx,layer-3-data-width = <24>; ++ xlnx,layer-3-offset = <9720>; ++ xlnx,layer-4-type = <0>; ++ xlnx,layer-4-alpha-mode = <0>; ++ xlnx,layer-4-data-width = <24>; ++ xlnx,layer-4-offset = <12960>; ++ xlnx,buffer-0-offset = <1080>; ++ xlnx,buffer-1-offset = <1080>; ++ xlnx,buffer-2-offset = <1080>; ++ xlnx,buffer-3-offset = <1080>; ++ xlnx,buffer-4-offset = <1080>; ++ xlnx,little-endian = <1>; ++ xlnx,readable-regs = <1>; ++ xlnx,row-stride = <2048>; ++ xlnx,use-background = <1>; ++ xlnx,use-size-position = <1>; ++ xlnx,vmem-baseaddr = <0x30000000>; ++ xlnx,vmem-highaddr = <0x3FFFFFFF>; ++ ++ //0-EXT; 1-ZynqPS; 2-logiCLK; 3-SI570 ++ pixel-clock-source = <3>; ++ pixel-data-invert = <0>; ++ pixel-clock-active-high = <1>; ++ pixel-component-format = "ARGB"; ++ pixel-component-layer = <0>,<1>,<2>; ++ active-layer = <0>; ++ videomode = "1920x1080"; ++ edid { ++ preffered-videomode = <1>; ++ display-data = <0>; ++ }; ++ }; ++ ++ xylon-video-params { ++ 800x480_TM050RBH01 { ++ name = "800x480_TM050RBH01"; ++ refresh = <60>; ++ xres = <800>; ++ yres = <480>; ++ pixclock-khz = <30000>; ++ left-margin = <40>; ++ right-margin = <40>; ++ upper-margin = <29>; ++ lower-margin = <13>; ++ hsync-len = <48>; ++ vsync-len = <3>; ++ sync = <0>; ++ vmode = <0>; ++ }; ++ 1280x720 { ++ name = "1280x720"; ++ refresh = <60>; ++ xres = <1280>; ++ yres = <720>; ++ pixclock-khz = <74250>; ++ left-margin = <220>; ++ right-margin = <110>; ++ upper-margin = <20>; ++ lower-margin = <5>; ++ hsync-len = <40>; ++ vsync-len = <5>; ++ sync = <0>; ++ vmode = <0>; ++ }; ++ 1680x1050 { ++ name = "1680x1050"; ++ refresh = <60>; ++ xres = <1680>; ++ yres = <1050>; ++ pixclock-khz = <119000>; ++ left-margin = <80>; ++ right-margin = <48>; ++ upper-margin = <21>; ++ lower-margin = <3>; ++ hsync-len = <32>; ++ vsync-len = <6>; ++ sync = <0>; ++ vmode = <0>; ++ }; ++ 1920x1080 { ++ name = "1920x1080"; ++ refresh = <60>; ++ xres = <1920>; ++ yres = <1080>; ++ pixclock-khz = <148500>; ++ left-margin = <148>; ++ right-margin = <88>; ++ upper-margin = <36>; ++ lower-margin = <4>; ++ hsync-len = <44>; ++ vsync-len = <5>; ++ sync = <0>; ++ vmode = <0>; ++ }; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/zynq-zc702-xylon-snippet.dts b/arch/arm/boot/dts/zynq-zc702-xylon-snippet.dts +deleted file mode 100644 +index 84cf9ca..0000000 +--- a/arch/arm/boot/dts/zynq-zc702-xylon-snippet.dts ++++ /dev/null +@@ -1,164 +0,0 @@ +-/* The following kernel command line can be used to boot Ubuntu from an SD card, the same +- * kernel command line with a ramdisk for the root device is used for the Sobel filter TPD +- */ +- +-bootargs = "console=ttyPS0,115200 console=tty0 root=/dev/mmcblk0p2 rw rootwait ip=:::::eth0:dhcp, earlyprintk mem=768M memmap=128M$0x30000000 vmalloc=256M"; +- +-/* +- * This is an instance of the device tree entry for +- * xylon's logicvc. User must take care to edit this +- * snippet to match the configuration of their hardware +- * as found in the corresponding mhs file. +- * +- * The snippet below is configured specifically for the +- * Zynq Sobel filter TPD for the zc702 board or for booting +- * Ubuntu at 1080p. +- */ +- +-logicvc0: logicvc@40030000 { +- compatible = "xylon,logicvc-2.05.b", "xylon,logicvc-2.05.c"; +- reg = <0x40030000 0x6000>; +- interrupt-parent = <&gic>; +- interrupts = < 0 59 0 >; +- buffer-0-offset = <1080>; +- buffer-1-offset = <1080>; +- buffer-2-offset = <1080>; +- buffer-3-offset = <1080>; +- buffer-4-offset = <1080>; +- display-interface = <0>; +- e-data-width = <24>; +- e-layer = <0>; +- interconnect-m-axi-arb-priority = <0xf>; +- ip-license-type = <0>; +- ip-major-revision = <2>; +- ip-minor-revision = <5>; +- ip-patch-level = <0>; +- layer-0-alpha-mode = <0>; +- layer-0-data-width = <16>; +- layer-0-offset = <0x0>; +- layer-1-alpha-mode = <0>; +- layer-1-data-width = <24>; +- layer-1-offset = <3240>; +- layer-2-alpha-mode = <0>; +- layer-2-data-width = <24>; +- layer-2-offset = <6480>; +- layer-3-alpha-mode = <0>; +- layer-3-data-width = <24>; +- layer-3-offset = <9720>; +- layer-4-alpha-mode = <0>; +- layer-4-data-width = <24>; +- layer-4-offset = <12960>; +- little-endian = <1>; +- lvds-data-width = <4>; +- mem-burst = <4>; +- mplb-awidth = <32>; +- mplb-dwidth = <64>; +- mplb-native-dwidth = <32>; +- mplb-num-masters = <8>; +- mplb-p2p = <0>; +- mplb-priority = <3>; +- mplb-smallest-slave = <32>; +- mplb-support-bursts = <1>; +- num-of-layers = <3>; +- pixel-data-width = <24>; +- readable-regs = <1>; +- regs-interface = <2>; +- regs-little-endian = <1>; +- row-stride = < 2048 >; +- use-background = <0>; +- use-e-rgb-input = <0>; +- use-e-vclk-bufgmux = <1>; +- use-io-hw-serializer = <0>; +- use-multiplier = <2>; +- use-serialized-blender = <0>; +- use-size-position = < 1 >; +- use-xtreme-dsp = <2>; +- vmem-baseaddr = <0x30000000>; +- vmem-highaddr = <0x37ffffff>; +- vmem-data-bus-width = <64>; +- vmem-interface = <2>; +-}; +- +-xylon-video-params { +- pixel-data-invert = <0>; +- pixel-clock-active-high = <1>; +- pixel-component-format = "ARGB"; +- pixel-component-layer = <0>,<1>; +- active-layer = <1>; +- videomode = "1920x1080"; +- 640x480 { +- name = "640x480"; +- refresh = <60>; +- xres = <640>; +- yres = <480>; +- pixclock-khz = <25152>; +- left-margin = <48>; +- right-margin = <16>; +- upper-margin = <31>; +- lower-margin = <11>; +- hsync-len = <96>; +- vsync-len = <2>; +- sync = <0>; +- vmode = <0>; +- }; +- 800x480 { +- name = "800x480"; +- refresh = <60>; +- xres = <800>; +- yres = <480>; +- pixclock-khz = <30000>; +- left-margin = <40>; +- right-margin = <40>; +- upper-margin = <29>; +- lower-margin = <13>; +- hsync-len = <48>; +- vsync-len = <3>; +- sync = <0>; +- vmode = <0>; +- }; +- 1280x720 { +- name = "1280x720"; +- refresh = <60>; +- xres = <1280>; +- yres = <720>; +- pixclock-khz = <74250>; +- left-margin = <220>; +- right-margin = <110>; +- upper-margin = <20>; +- lower-margin = <5>; +- hsync-len = <40>; +- vsync-len = <5>; +- sync = <0>; +- vmode = <0>; +- }; +- 1680x1050 { +- name = "1680x1050"; +- refresh = <60>; +- xres = <1680>; +- yres = <1050>; +- pixclock-khz = <119000>; +- left-margin = <80>; +- right-margin = <48>; +- upper-margin = <21>; +- lower-margin = <3>; +- hsync-len = <32>; +- vsync-len = <6>; +- sync = <0>; +- vmode = <0>; +- }; +- 1920x1080 { +- name = "1920x1080"; +- refresh = <60>; +- xres = <1920>; +- yres = <1080>; +- pixclock-khz = <148500>; +- left-margin = <148>; +- right-margin = <88>; +- upper-margin = <36>; +- lower-margin = <4>; +- hsync-len = <44>; +- vsync-len = <5>; +- sync = <0>; +- vmode = <0>; +- }; +-}; +diff --git a/arch/arm/boot/dts/zynq-zc702.dts b/arch/arm/boot/dts/zynq-zc702.dts +index 19e2780..9e79a4f 100644 +--- a/arch/arm/boot/dts/zynq-zc702.dts ++++ b/arch/arm/boot/dts/zynq-zc702.dts +@@ -1,156 +1,142 @@ +-/dts-v1/; ++/* ++ * Device Tree Generator version: 1.1 ++ * ++ * (C) Copyright 2007-2013 Xilinx, Inc. ++ * (C) Copyright 2007-2013 Michal Simek ++ * (C) Copyright 2007-2012 PetaLogix Qld Pty Ltd ++ * ++ * Michal SIMEK ++ * ++ * CAUTION: This file is automatically generated by libgen. ++ * Version: Xilinx EDK 14.5 EDK_P.58f ++ * ++ */ + ++/dts-v1/; + / { +- model = "Xilinx Zynq ZC702"; +- compatible = "xlnx,zynq-zc702"; +- #address-cells = <0x1>; +- #size-cells = <0x1>; +- interrupt-parent = <0x1>; +- +- memory { +- device_type = "memory"; +- reg = <0x00000000 0x40000000>; +- }; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "xlnx,zynq-7000"; ++ model = "Xilinx Zynq"; ++ aliases { ++ ethernet0 = &ps7_ethernet_0; ++ i2c0 = &ps7_i2c_0; ++ serial0 = &ps7_uart_1; ++ spi0 = &ps7_qspi_0; ++ } ; + chosen { +- bootargs = "console=ttyPS0,115200 root=/dev/ram rw ip=:::::eth0:dhcp earlyprintk"; +- linux,stdout-path = "/amba@0/uart@E0001000"; +- }; +- ++ bootargs = "console=ttyPS0,115200 root=/dev/ram rw earlyprintk"; ++ linux,stdout-path = "/amba@0/serial@e0001000"; ++ } ; ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ps7_cortexa9_0: cpu@0 { ++ bus-handle = <&ps7_axi_interconnect_0>; ++ compatible = "arm,cortex-a9"; ++ d-cache-line-size = <0x20>; ++ d-cache-size = <0x8000>; ++ device_type = "cpu"; ++ i-cache-line-size = <0x20>; ++ i-cache-size = <0x8000>; ++ interrupt-handle = <&ps7_scugic_0>; ++ reg = <0x0>; ++ } ; ++ ps7_cortexa9_1: cpu@1 { ++ bus-handle = <&ps7_axi_interconnect_0>; ++ compatible = "arm,cortex-a9"; ++ d-cache-line-size = <0x20>; ++ d-cache-size = <0x8000>; ++ device_type = "cpu"; ++ i-cache-line-size = <0x20>; ++ i-cache-size = <0x8000>; ++ interrupt-handle = <&ps7_scugic_0>; ++ reg = <0x1>; ++ } ; ++ } ; + pmu { + compatible = "arm,cortex-a9-pmu"; ++ interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 5 4>, <0 6 4>; +- interrupt-parent = <&gic>; +- }; +- +- amba@0 { +- compatible = "simple-bus"; +- #address-cells = <0x1>; +- #size-cells = <0x1>; +- ranges; +- +- gic: intc@f8f01000 { +- interrupt-controller; +- compatible = "arm,cortex-a9-gic"; +- #interrupt-cells = <3>; +- reg = <0xf8f01000 0x1000>, +- <0xf8f00100 0x0100>; +- }; +- +- pl310@f8f02000 { +- compatible = "arm,pl310-cache"; +- cache-unified; +- cache-level = <2>; +- reg = <0xf8f02000 0x1000>; +- arm,data-latency = <3 2 2>; +- arm,tag-latency = <2 2 2>; +- }; +- ++ reg = <0xf8891000 0x1000>, <0xf8893000 0x1000>; ++ reg-names = "cpu0", "cpu1"; ++ } ; ++ ps7_ddr_0: memory@0 { ++ device_type = "memory"; ++ reg = <0x0 0x40000000>; ++ } ; ++ ps7_axi_interconnect_0: amba@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "xlnx,ps7-axi-interconnect-1.00.a", "simple-bus"; ++ ranges ; ++ ps7_afi_0: ps7-afi@f8008000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf8008000 0x1000>; ++ } ; ++ ps7_afi_1: ps7-afi@f8009000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf8009000 0x1000>; ++ } ; ++ ps7_afi_2: ps7-afi@f800a000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf800a000 0x1000>; ++ } ; ++ ps7_afi_3: ps7-afi@f800b000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf800b000 0x1000>; ++ } ; ++ ps7_can_0: ps7-can@e0008000 { ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 19>, <&clkc 36>; ++ compatible = "xlnx,ps7-can-1.00.a", "xlnx,ps7-can"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 28 4>; ++ reg = <0xe0008000 0x1000>; ++ } ; + ps7_ddrc_0: ps7-ddrc@f8006000 { + compatible = "xlnx,ps7-ddrc-1.00.a", "xlnx,ps7-ddrc"; + reg = <0xf8006000 0x1000>; + xlnx,has-ecc = <0x0>; + } ; +- +- ps7_ocm_0: ps7-ocm@0xfffc0000 { +- compatible = "xlnx,ps7-ocm"; +- reg = <0xfffc0000 0x40000>; /* 256k */ +- }; +- +- uart@e0001000 { +- compatible = "xlnx,ps7-uart-1.00.a"; +- reg = <0xe0001000 0x1000>; +- interrupts = <0 50 4>; +- interrupt-parent = <&gic>; +- clock = <50000000>; +- }; +- +- slcr: slcr@f8000000 { +- compatible = "xlnx,zynq-slcr"; +- reg = <0xF8000000 0x1000>; +- clocks { +- #address-cells = <1>; +- #size-cells = <0>; +- armpll: armpll { +- #clock-cells = <0>; +- clock-output-names = "armpll"; +- clocks = <&ps_clk>; +- compatible = "xlnx,zynq-pll"; +- lockbit = <0>; +- reg = < 0x100 0x110 0x10c >; +- } ; +- ddrpll: ddrpll { +- #clock-cells = <0>; +- clock-output-names = "ddrpll"; +- clocks = <&ps_clk>; +- compatible = "xlnx,zynq-pll"; +- lockbit = <1>; +- reg = < 0x104 0x114 0x10c >; +- } ; +- iopll: iopll { +- #clock-cells = <0>; +- clock-output-names = "iopll"; +- clocks = <&ps_clk>; +- compatible = "xlnx,zynq-pll"; +- lockbit = <2>; +- reg = < 0x108 0x118 0x10c >; +- } ; +- ps_clk: ps_clk { +- #clock-cells = <0>; +- clock-frequency = <33333333>; +- clock-output-names = "ps_clk"; +- compatible = "fixed-clock"; +- } ; +- } ; +- }; +- +- timer@0xf8001000 { +- compatible = "xlnx,ps7-ttc-1.00.a"; +- reg = <0xf8001000 0x1000>; +- interrupts = <0 10 4>,<0 11 4>,<0 12 4>; +- interrupt-parent = <&gic>; +- }; +- +- timer@f8f00600 { +- compatible = "arm,cortex-a9-twd-timer"; +- reg = <0xf8f00600 0x20>; +- interrupts = <1 13 0x301>; +- interrupt-parent = <&gic>; +- }; +- +- swdt@f8005000 { +- device_type = "watchdog"; +- compatible = "xlnx,ps7-wdt-1.00.a"; +- reg = <0xf8005000 0x100>; +- interrupts = <0 9 4>; +- interrupt-parent = <&gic>; +- reset = <0>; +- timeout = <10>; +- }; +- +- scuwdt@f8f00620 { +- device_type = "watchdog"; +- compatible = "arm,mpcore_wdt"; +- reg = <0xf8f00620 0x20>; +- clock-frequency = <333333333>; +- reset = <1>; +- }; +- +- eth@e000b000 { ++ ps7_dev_cfg_0: ps7-dev-cfg@f8007000 { ++ clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3"; ++ clocks = <&clkc 12>, <&clkc 15>, <&clkc 16>, <&clkc 17>, <&clkc 18>; ++ compatible = "xlnx,ps7-dev-cfg-1.00.a"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 8 4>; ++ reg = <0xf8007000 0x100>; ++ } ; ++ ps7_dma_s: ps7-dma@f8003000 { ++ #dma-cells = <1>; ++ #dma-channels = <8>; ++ #dma-requests = <4>; ++ arm,primecell-periphid = <0x41330>; ++ clock-names = "apb_pclk"; ++ clocks = <&clkc 27>; ++ compatible = "xlnx,ps7-dma-1.00.a", "arm,primecell", "arm,pl330"; ++ interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3", ++ "dma4", "dma5", "dma6", "dma7"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 13 4>, <0 14 4>, <0 15 4>, <0 16 4>, <0 17 4>, <0 40 4>, <0 41 4>, <0 42 4>, <0 43 4>; ++ reg = <0xf8003000 0x1000>; ++ } ; ++ ps7_ethernet_0: ps7-ethernet@e000b000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 13>, <&clkc 30>; + compatible = "xlnx,ps7-ethernet-1.00.a"; +- reg = <0xe000b000 0x1000>; ++ interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 22 4>; +- interrupt-parent = <&gic>; ++ local-mac-address = [00 0a 35 00 00 00]; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; +- xlnx,ptp-enet-clock = <111111111>; +- xlnx,slcr-div0-1000Mbps = <8>; +- xlnx,slcr-div0-100Mbps = <8>; +- xlnx,slcr-div0-10Mbps = <8>; +- xlnx,slcr-div1-1000Mbps = <1>; +- xlnx,slcr-div1-100Mbps = <5>; +- xlnx,slcr-div1-10Mbps = <50>; +- #address-cells = <0x1>; +- #size-cells = <0x0>; ++ reg = <0xe000b000 0x1000>; ++ xlnx,enet-reset = "MIO 11"; ++ xlnx,eth-mode = <0x1>; ++ xlnx,has-mdio = <0x1>; ++ xlnx,ptp-enet-clock = <111111115>; + mdio { + #address-cells = <1>; + #size-cells = <0>; +@@ -158,19 +144,31 @@ + compatible = "marvell,88e1116r"; + device_type = "ethernet-phy"; + reg = <7>; +- }; +- }; +- }; +- +- i2c0: i2c@e0004000 { ++ } ; ++ } ; ++ } ; ++ ps7_gpio_0: ps7-gpio@e000a000 { ++ #gpio-cells = <2>; ++ clocks = <&clkc 42>; ++ compatible = "xlnx,ps7-gpio-1.00.a"; ++ emio-gpio-width = <64>; ++ gpio-controller ; ++ gpio-mask-high = <0x0>; ++ gpio-mask-low = <0x5600>; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 20 4>; ++ reg = <0xe000a000 0x1000>; ++ } ; ++ ps7_i2c_0: ps7-i2c@e0004000 { ++ bus-id = <0>; ++ clocks = <&clkc 38>; + compatible = "xlnx,ps7-i2c-1.00.a"; +- reg = <0xE0004000 0x1000>; ++ i2c-clk = <400000>; ++ interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 25 4>; +- interrupt-parent = <&gic>; +- bus-id = <0>; +- input-clk = <111111111>; +- i2c-clk = <100000>; +- ++ reg = <0xe0004000 0x1000>; ++ xlnx,has-interrupt = <0x0>; ++ xlnx,i2c-reset = "MIO 13"; + #address-cells = <1>; + #size-cells = <0>; + i2cswitch@74 { +@@ -241,44 +239,35 @@ + }; + }; + }; +- }; +- +- sdhci@e0100000 { +- compatible = "xlnx,ps7-sdhci-1.00.a"; +- reg = <0xe0100000 0x1000>; +- xlnx,has-cd = <0x1>; +- interrupts = <0 24 4>; +- interrupt-parent = <&gic>; +- clock-frequency = <33333000>; +- }; + +- usb@e0002000 { +- compatible = "xlnx,ps7-usb-1.00.a"; +- reg = <0xe0002000 0x1000>; +- interrupts = <0 21 4>; +- interrupt-parent = <&gic>; +- dr_mode = "host"; +- phy_type = "ulpi"; +- }; +- +- gpio@e000a000 { +- compatible = "xlnx,ps7-gpio-1.00.a"; +- reg = <0xe000a000 0x1000>; +- interrupts = <0 20 4>; +- interrupt-parent = <&gic>; +- }; +- +- qspi0: spi@e000d000 { ++ } ; ++ ps7_iop_bus_config_0: ps7-iop-bus-config@e0200000 { ++ compatible = "xlnx,ps7-iop-bus-config-1.00.a"; ++ reg = <0xe0200000 0x1000>; ++ } ; ++ ps7_pl310_0: ps7-pl310@f8f02000 { ++ arm,data-latency = <3 2 2>; ++ arm,tag-latency = <2 2 2>; ++ cache-level = <2>; ++ cache-unified ; ++ compatible = "xlnx,ps7-pl310-1.00.a", "arm,pl310-cache"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 2 4>; ++ reg = <0xf8f02000 0x1000>; ++ } ; ++ ps7_qspi_0: ps7-qspi@e000d000 { ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 10>, <&clkc 43>; + compatible = "xlnx,ps7-qspi-1.00.a"; +- reg = <0xE000D000 0x1000>; ++ interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 19 4>; +- interrupt-parent = <&gic>; +- speed-hz = <200000000>; +- bus-num = <1>; ++ is-dual = <0>; + num-chip-select = <1>; ++ reg = <0xe000d000 0x1000>; ++ xlnx,fb-clk = <0x1>; ++ xlnx,qspi-mode = <0x0>; + #address-cells = <1>; + #size-cells = <0>; +- is-dual = <0>; + flash@0 { + compatible = "n25q128"; + reg = <0x0>; +@@ -306,30 +295,127 @@ + reg = <0xC00000 0x400000>; + }; + }; +- }; +- +- devcfg@f8007000 { +- compatible = "xlnx,ps7-dev-cfg-1.00.a"; +- reg = <0xf8007000 0x100>; +- interrupts = <0 8 4>; +- interrupt-parent = <&gic>; +- }; + +- xadc@f8007100 { ++ } ; ++ ps7_qspi_linear_0: ps7-qspi-linear@fc000000 { ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 10>, <&clkc 43>; ++ compatible = "xlnx,ps7-qspi-linear-1.00.a"; ++ reg = <0xfc000000 0x1000000>; ++ } ; ++ ps7_ram_0: ps7-ram@0 { ++ compatible = "xlnx,ps7-ram-1.00.a", "xlnx,ps7-ocm"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 3 4>; ++ reg = <0xfffc0000 0x40000>; ++ } ; ++ ps7_scugic_0: ps7-scugic@f8f01000 { ++ #address-cells = <2>; ++ #interrupt-cells = <3>; ++ #size-cells = <1>; ++ compatible = "xlnx,ps7-scugic-1.00.a", "arm,cortex-a9-gic", "arm,gic"; ++ interrupt-controller ; ++ num_cpus = <2>; ++ num_interrupts = <96>; ++ reg = <0xf8f01000 0x1000>, <0xf8f00100 0x100>; ++ } ; ++ ps7_scutimer_0: ps7-scutimer@f8f00600 { ++ clocks = <&clkc 4>; ++ compatible = "xlnx,ps7-scutimer-1.00.a", "arm,cortex-a9-twd-timer"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <1 13 0x301>; ++ reg = <0xf8f00600 0x20>; ++ } ; ++ ps7_scuwdt_0: ps7-scuwdt@f8f00620 { ++ clocks = <&clkc 4>; ++ compatible = "xlnx,ps7-scuwdt-1.00.a"; ++ device_type = "watchdog"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <1 14 0x301>; ++ reg = <0xf8f00620 0xe0>; ++ } ; ++ ps7_sd_0: ps7-sdio@e0100000 { ++ clock-frequency = <50000000>; ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 21>, <&clkc 32>; ++ compatible = "xlnx,ps7-sdio-1.00.a", "generic-sdhci", "arasan,sdhci"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 24 4>; ++ reg = <0xe0100000 0x1000>; ++ xlnx,has-cd = <0x1>; ++ xlnx,has-power = <0x0>; ++ xlnx,has-wp = <0x1>; ++ } ; ++ ps7_slcr_0: ps7-slcr@f8000000 { ++ compatible = "xlnx,ps7-slcr-1.00.a", "xlnx,zynq-slcr"; ++ reg = <0xf8000000 0x1000>; ++ clocks { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clkc: clkc { ++ #clock-cells = <1>; ++ clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x", "cpu_3or2x", ++ "cpu_2x", "cpu_1x", "ddr2x", "ddr3x", "dci", ++ "lqspi", "smc", "pcap", "gem0", "gem1", ++ "fclk0", "fclk1", "fclk2", "fclk3", "can0", ++ "can1", "sdio0", "sdio1", "uart0", "uart1", ++ "spi0", "spi1", "dma", "usb0_aper", "usb1_aper", ++ "gem0_aper", "gem1_aper", "sdio0_aper", "sdio1_aper", "spi0_aper", ++ "spi1_aper", "can0_aper", "can1_aper", "i2c0_aper", "i2c1_aper", ++ "uart0_aper", "uart1_aper", "gpio_aper", "lqspi_aper", "smc_aper", ++ "swdt", "dbg_trc", "dbg_apb"; ++ compatible = "xlnx,ps7-clkc"; ++ fclk-enable = <0xf>; ++ ps-clk-frequency = <33333333>; ++ } ; ++ } ; ++ } ; ++ ps7_ttc_0: ps7-ttc@f8001000 { ++ clocks = <&clkc 6>; ++ compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; ++ interrupt-names = "ttc0", "ttc1", "ttc2"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 10 4>, <0 11 4>, <0 12 4>; ++ reg = <0xf8001000 0x1000>; ++ } ; ++ ps7_uart_1: serial@e0001000 { ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 24>, <&clkc 41>; ++ compatible = "xlnx,ps7-uart-1.00.a", "xlnx,xuartps"; ++ current-speed = <115200>; ++ device_type = "serial"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 50 4>; ++ port-number = <0>; ++ reg = <0xe0001000 0x1000>; ++ xlnx,has-modem = <0x0>; ++ } ; ++ ps7_usb_0: ps7-usb@e0002000 { ++ clocks = <&clkc 28>; ++ compatible = "xlnx,ps7-usb-1.00.a"; ++ dr_mode = "host"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 21 4>; ++ phy_type = "ulpi"; ++ reg = <0xe0002000 0x1000>; ++ usb-reset = <&ps7_gpio_0 7 0>; ++ } ; ++ ps7_wdt_0: ps7-wdt@f8005000 { ++ clocks = <&clkc 45>; ++ compatible = "xlnx,ps7-wdt-1.00.a"; ++ device_type = "watchdog"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 9 1>; ++ reg = <0xf8005000 0x1000>; ++ reset = <0>; ++ timeout = <10>; ++ } ; ++ ps7_xadc: ps7-xadc@f8007100 { ++ clocks = <&clkc 12>; + compatible = "xlnx,ps7-xadc-1.00.a"; +- reg = <0xf8007100 0x20>; ++ interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 7 4>; +- interrupt-parent = <&gic>; +- }; +- ps7_dma_s: ps7-dma@f8003000 { +- #dma-cells = <1>; +- #dma-channels = <8>; +- #dma-requests = <4>; +- arm,primecell-periphid = <0x41330>; +- compatible = "xlnx,ps7-dma-1.00.a", "arm,primecell", "arm,pl330"; +- interrupt-parent = <&gic>; +- interrupts = < 0 13 4 0 14 4 0 15 4 0 16 4 0 17 4 0 40 4 0 41 4 0 42 4 0 43 4 >; +- reg = < 0xf8003000 0x1000 >; ++ reg = <0xf8007100 0x20>; + } ; +- }; +-}; ++ } ; ++} ; +diff --git a/arch/arm/boot/dts/zynq-zc706.dts b/arch/arm/boot/dts/zynq-zc706.dts +index 4708c86..496e673 100644 +--- a/arch/arm/boot/dts/zynq-zc706.dts ++++ b/arch/arm/boot/dts/zynq-zc706.dts +@@ -1,155 +1,134 @@ +-/dts-v1/; ++/* ++ * Device Tree Generator version: 1.1 ++ * ++ * (C) Copyright 2007-2013 Xilinx, Inc. ++ * (C) Copyright 2007-2013 Michal Simek ++ * (C) Copyright 2007-2012 PetaLogix Qld Pty Ltd ++ * ++ * Michal SIMEK ++ * ++ * CAUTION: This file is automatically generated by libgen. ++ * Version: Xilinx EDK 14.5 EDK_P.58f ++ * ++ */ + ++/dts-v1/; + / { +- model = "Xilinx Zynq ZC706"; +- compatible = "xlnx,zynq-zc706"; +- #address-cells = <0x1>; +- #size-cells = <0x1>; +- interrupt-parent = <0x1>; +- +- memory { +- device_type = "memory"; +- reg = <0x00000000 0x40000000>; +- }; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "xlnx,zynq-7000"; ++ model = "Xilinx Zynq"; ++ aliases { ++ ethernet0 = &ps7_ethernet_0; ++ i2c0 = &ps7_i2c_0; ++ serial0 = &ps7_uart_1; ++ spi0 = &ps7_qspi_0; ++ } ; + chosen { +- bootargs = "console=ttyPS0,115200 root=/dev/ram rw ip=:::::eth0:dhcp earlyprintk"; +- linux,stdout-path = "/amba@0/uart@E0001000"; +- }; +- ++ bootargs = "console=ttyPS0,115200 root=/dev/ram rw earlyprintk"; ++ linux,stdout-path = "/amba@0/serial@e0001000"; ++ } ; ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ps7_cortexa9_0: cpu@0 { ++ bus-handle = <&ps7_axi_interconnect_0>; ++ compatible = "arm,cortex-a9"; ++ d-cache-line-size = <0x20>; ++ d-cache-size = <0x8000>; ++ device_type = "cpu"; ++ i-cache-line-size = <0x20>; ++ i-cache-size = <0x8000>; ++ interrupt-handle = <&ps7_scugic_0>; ++ reg = <0x0>; ++ } ; ++ ps7_cortexa9_1: cpu@1 { ++ bus-handle = <&ps7_axi_interconnect_0>; ++ compatible = "arm,cortex-a9"; ++ d-cache-line-size = <0x20>; ++ d-cache-size = <0x8000>; ++ device_type = "cpu"; ++ i-cache-line-size = <0x20>; ++ i-cache-size = <0x8000>; ++ interrupt-handle = <&ps7_scugic_0>; ++ reg = <0x1>; ++ } ; ++ } ; + pmu { + compatible = "arm,cortex-a9-pmu"; ++ interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 5 4>, <0 6 4>; +- interrupt-parent = <&gic>; +- }; +- +- amba@0 { +- compatible = "simple-bus"; +- #address-cells = <0x1>; +- #size-cells = <0x1>; +- ranges; +- +- gic: intc@f8f01000 { +- interrupt-controller; +- compatible = "arm,cortex-a9-gic"; +- #interrupt-cells = <3>; +- reg = <0xf8f01000 0x1000>, +- <0xf8f00100 0x0100>; +- }; +- +- pl310@f8f02000 { +- compatible = "arm,pl310-cache"; +- cache-unified; +- cache-level = <2>; +- reg = <0xf8f02000 0x1000>; +- arm,data-latency = <3 2 2>; +- arm,tag-latency = <2 2 2>; +- }; +- ++ reg = <0xf8891000 0x1000>, <0xf8893000 0x1000>; ++ reg-names = "cpu0", "cpu1"; ++ } ; ++ ps7_ddr_0: memory@0 { ++ device_type = "memory"; ++ reg = <0x0 0x40000000>; ++ } ; ++ ps7_axi_interconnect_0: amba@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "xlnx,ps7-axi-interconnect-1.00.a", "simple-bus"; ++ ranges ; ++ ps7_afi_0: ps7-afi@f8008000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf8008000 0x1000>; ++ } ; ++ ps7_afi_1: ps7-afi@f8009000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf8009000 0x1000>; ++ } ; ++ ps7_afi_2: ps7-afi@f800a000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf800a000 0x1000>; ++ } ; ++ ps7_afi_3: ps7-afi@f800b000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf800b000 0x1000>; ++ } ; + ps7_ddrc_0: ps7-ddrc@f8006000 { + compatible = "xlnx,ps7-ddrc-1.00.a", "xlnx,ps7-ddrc"; +- reg = < 0xf8006000 0x1000 >; ++ reg = <0xf8006000 0x1000>; + xlnx,has-ecc = <0x0>; + } ; +- +- ps7_ocm_0: ps7-ocm@0xfffc0000 { +- compatible = "xlnx,ps7-ocm"; +- reg = <0xfffc0000 0x40000>; /* 256k */ +- }; +- +- uart@e0001000 { +- compatible = "xlnx,ps7-uart-1.00.a"; +- reg = <0xe0001000 0x1000>; +- interrupts = <0 50 4>; +- interrupt-parent = <&gic>; +- clock = <50000000>; +- }; +- +- slcr: slcr@f8000000 { +- compatible = "xlnx,zynq-slcr"; +- reg = <0xF8000000 0x1000>; +- +- clocks { +- #address-cells = <1>; +- #size-cells = <0>; +- armpll: armpll { +- #clock-cells = <0>; +- clock-output-names = "armpll"; +- clocks = <&ps_clk>; +- compatible = "xlnx,zynq-pll"; +- lockbit = <0>; +- reg = < 0x100 0x110 0x10c >; +- } ; +- ddrpll: ddrpll { +- #clock-cells = <0>; +- clock-output-names = "ddrpll"; +- clocks = <&ps_clk>; +- compatible = "xlnx,zynq-pll"; +- lockbit = <1>; +- reg = < 0x104 0x114 0x10c >; +- } ; +- iopll: iopll { +- #clock-cells = <0>; +- clock-output-names = "iopll"; +- clocks = <&ps_clk>; +- compatible = "xlnx,zynq-pll"; +- lockbit = <2>; +- reg = < 0x108 0x118 0x10c >; +- } ; +- ps_clk: ps_clk { +- #clock-cells = <0>; +- compatible = "fixed-clock"; +- clock-frequency = <33333333>; +- clock-output-names = "ps_clk"; +- }; +- }; +- }; +- +- timer@0xf8001000 { +- compatible = "xlnx,ps7-ttc-1.00.a"; +- reg = <0xf8001000 0x1000>; +- interrupts = <0 10 4>,<0 11 4>,<0 12 4>; +- interrupt-parent = <&gic>; +- }; +- +- timer@f8f00600 { +- compatible = "arm,cortex-a9-twd-timer"; +- reg = <0xf8f00600 0x20>; +- interrupts = <1 13 0x301>; +- interrupt-parent = <&gic>; +- }; +- +- swdt@f8005000 { +- device_type = "watchdog"; +- compatible = "xlnx,ps7-wdt-1.00.a"; +- reg = <0xf8005000 0x100>; +- reset = <0>; +- timeout = <10>; +- }; +- +- scuwdt@f8f00620 { +- device_type = "watchdog"; +- compatible = "arm,mpcore_wdt"; +- reg = <0xf8f00620 0x20>; +- clock-frequency = <333333333>; +- reset = <1>; +- }; +- +- eth@e000b000 { ++ ps7_dev_cfg_0: ps7-dev-cfg@f8007000 { ++ clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3"; ++ clocks = <&clkc 12>, <&clkc 15>, <&clkc 16>, <&clkc 17>, <&clkc 18>; ++ compatible = "xlnx,ps7-dev-cfg-1.00.a"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 8 4>; ++ reg = <0xf8007000 0x100>; ++ } ; ++ ps7_dma_s: ps7-dma@f8003000 { ++ #dma-cells = <1>; ++ #dma-channels = <8>; ++ #dma-requests = <4>; ++ arm,primecell-periphid = <0x41330>; ++ clock-names = "apb_pclk"; ++ clocks = <&clkc 27>; ++ compatible = "xlnx,ps7-dma-1.00.a", "arm,primecell", "arm,pl330"; ++ interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3", ++ "dma4", "dma5", "dma6", "dma7"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 13 4>, <0 14 4>, <0 15 4>, <0 16 4>, <0 17 4>, <0 40 4>, <0 41 4>, <0 42 4>, <0 43 4>; ++ reg = <0xf8003000 0x1000>; ++ } ; ++ ps7_ethernet_0: ps7-ethernet@e000b000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 13>, <&clkc 30>; + compatible = "xlnx,ps7-ethernet-1.00.a"; +- reg = <0xe000b000 0x1000>; ++ interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 22 4>; +- interrupt-parent = <&gic>; ++ local-mac-address = [00 0a 35 00 00 00]; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; +- xlnx,ptp-enet-clock = <111111111>; +- xlnx,slcr-div0-1000Mbps = <8>; +- xlnx,slcr-div0-100Mbps = <8>; +- xlnx,slcr-div0-10Mbps = <8>; +- xlnx,slcr-div1-1000Mbps = <1>; +- xlnx,slcr-div1-100Mbps = <5>; +- xlnx,slcr-div1-10Mbps = <50>; +- #address-cells = <0x1>; +- #size-cells = <0x0>; ++ reg = <0xe000b000 0x1000>; ++ xlnx,enet-reset = "MIO 47"; ++ xlnx,eth-mode = <0x1>; ++ xlnx,has-mdio = <0x1>; ++ xlnx,ptp-enet-clock = <111111115>; + mdio { + #address-cells = <1>; + #size-cells = <0>; +@@ -157,113 +136,127 @@ + compatible = "marvell,88e1116r"; + device_type = "ethernet-phy"; + reg = <7>; +- }; +- }; +- }; +- +- i2c0: i2c@e0004000 { ++ } ; ++ } ; ++ } ; ++ ps7_gpio_0: ps7-gpio@e000a000 { ++ #gpio-cells = <2>; ++ clocks = <&clkc 42>; ++ compatible = "xlnx,ps7-gpio-1.00.a"; ++ emio-gpio-width = <64>; ++ gpio-controller ; ++ gpio-mask-high = <0x0>; ++ gpio-mask-low = <0x0>; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 20 4>; ++ reg = <0xe000a000 0x1000>; ++ } ; ++ ps7_i2c_0: ps7-i2c@e0004000 { ++ bus-id = <0>; ++ clocks = <&clkc 38>; + compatible = "xlnx,ps7-i2c-1.00.a"; +- reg = <0xE0004000 0x1000>; ++ i2c-clk = <400000>; ++ interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 25 4>; +- interrupt-parent = <&gic>; +- bus-id = <0>; +- input-clk = <111111111>; +- i2c-clk = <100000>; +- ++ reg = <0xe0004000 0x1000>; ++ xlnx,has-interrupt = <0x0>; ++ xlnx,i2c-reset = "MIO 46"; + #address-cells = <1>; + #size-cells = <0>; +- i2cswitch@74 { +- compatible = "nxp,pca9548"; +- #address-cells = <1>; +- #size-cells = <0>; +- reg = <0x74>; ++ i2cswitch@74 { ++ compatible = "nxp,pca9548"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x74>; + + i2c@0 { +- #address-cells = <1>; +- #size-cells = <0>; +- reg = <0>; +- osc@5d { +- compatible = "si570"; +- reg = <0x5d>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ osc@5d { ++ compatible = "si570"; ++ reg = <0x5d>; + factory-fout = <156250000>; + initial-fout = <148500000>; +- }; ++ }; + }; + + i2c@2 { +- #address-cells = <1>; +- #size-cells = <0>; +- reg = <2>; +- eeprom@54 { +- compatible = "at,24c08"; +- reg = <0x54>; +- }; +- }; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <2>; ++ eeprom@54 { ++ compatible = "at,24c08"; ++ reg = <0x54>; ++ }; ++ }; + + i2c@3 { +- #address-cells = <1>; +- #size-cells = <0>; +- reg = <3>; +- gpio@21 { +- compatible = "ti,tca6416"; +- reg = <0x21>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <3>; ++ gpio@21 { ++ compatible = "ti,tca6416"; ++ reg = <0x21>; + gpio-controller; + #gpio-cells = <2>; +- }; ++ }; + }; + + i2c@4 { +- #address-cells = <1>; +- #size-cells = <0>; +- reg = <4>; +- rtc@54 { +- compatible = "nxp,pcf8563"; +- reg = <0x51>; +- }; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <4>; ++ rtc@51 { ++ compatible = "nxp,pcf8563"; ++ reg = <0x51>; ++ }; + }; +- }; +- }; + +- sdhci@e0100000 { +- compatible = "xlnx,ps7-sdhci-1.00.a"; +- reg = <0xe0100000 0x1000>; +- xlnx,has-cd = <0x1>; +- interrupts = <0 24 4>; +- interrupt-parent = <&gic>; +- clock-frequency = <33333000>; +- }; + +- usb@e0002000 { +- compatible = "xlnx,ps7-usb-1.00.a"; +- reg = <0xe0002000 0x1000>; +- interrupts = <0 21 4>; +- interrupt-parent = <&gic>; +- dr_mode = "host"; +- phy_type = "ulpi"; +- }; +- +- gpio@e000a000 { +- compatible = "xlnx,ps7-gpio-1.00.a"; +- reg = <0xe000a000 0x1000>; +- interrupts = <0 20 4>; +- interrupt-parent = <&gic>; +- }; ++ i2c@7 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <7>; ++ ucd90120@65 { ++ compatible = "pmbus,ucd90120"; ++ reg = <0x65>; ++ }; ++ }; ++ }; + +- qspi0: spi@e000d000 { ++ } ; ++ ps7_iop_bus_config_0: ps7-iop-bus-config@e0200000 { ++ compatible = "xlnx,ps7-iop-bus-config-1.00.a"; ++ reg = <0xe0200000 0x1000>; ++ } ; ++ ps7_pl310_0: ps7-pl310@f8f02000 { ++ arm,data-latency = <3 2 2>; ++ arm,tag-latency = <2 2 2>; ++ cache-level = <2>; ++ cache-unified ; ++ compatible = "xlnx,ps7-pl310-1.00.a", "arm,pl310-cache"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 2 4>; ++ reg = <0xf8f02000 0x1000>; ++ } ; ++ ps7_qspi_0: ps7-qspi@e000d000 { ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 10>, <&clkc 43>; + compatible = "xlnx,ps7-qspi-1.00.a"; +- reg = <0xE000D000 0x1000>; ++ interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 19 4>; +- interrupt-parent = <&gic>; +- speed-hz = <200000000>; +- bus-num = <1>; ++ is-dual = <1>; + num-chip-select = <1>; ++ reg = <0xe000d000 0x1000>; ++ xlnx,fb-clk = <0x1>; ++ xlnx,qspi-mode = <0x2>; + #address-cells = <1>; + #size-cells = <0>; +- is-dual = <1>; + flash@0 { + compatible = "n25q128"; + reg = <0x0>; +- spi-max-frequency = <30000000>; ++ spi-max-frequency = <50000000>; + #address-cells = <1>; + #size-cells = <1>; + partition@qspi-fsbl-uboot { +@@ -284,33 +277,138 @@ + }; + partition@qspi-bitstream { + label = "qspi-bitstream"; +- reg = <0xC00000 0x1400000>; ++ reg = <0xC00000 0x400000>; + }; + }; +- }; + +- devcfg@f8007000 { +- compatible = "xlnx,ps7-dev-cfg-1.00.a"; +- reg = <0xf8007000 0x100>; +- interrupts = <0 8 4>; +- interrupt-parent = <&gic>; +- }; +- +- xadc@f8007100 { ++ } ; ++ ps7_qspi_linear_0: ps7-qspi-linear@fc000000 { ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 10>, <&clkc 43>; ++ compatible = "xlnx,ps7-qspi-linear-1.00.a"; ++ reg = <0xfc000000 0x2000000>; ++ } ; ++ ps7_ram_0: ps7-ram@0 { ++ compatible = "xlnx,ps7-ram-1.00.a", "xlnx,ps7-ocm"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 3 4>; ++ reg = <0xfffc0000 0x40000>; ++ } ; ++ ps7_scugic_0: ps7-scugic@f8f01000 { ++ #address-cells = <2>; ++ #interrupt-cells = <3>; ++ #size-cells = <1>; ++ compatible = "xlnx,ps7-scugic-1.00.a", "arm,cortex-a9-gic", "arm,gic"; ++ interrupt-controller ; ++ num_cpus = <2>; ++ num_interrupts = <96>; ++ reg = <0xf8f01000 0x1000>, <0xf8f00100 0x100>; ++ } ; ++ ps7_scutimer_0: ps7-scutimer@f8f00600 { ++ clocks = <&clkc 4>; ++ compatible = "xlnx,ps7-scutimer-1.00.a", "arm,cortex-a9-twd-timer"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <1 13 0x301>; ++ reg = <0xf8f00600 0x20>; ++ } ; ++ ps7_scuwdt_0: ps7-scuwdt@f8f00620 { ++ clocks = <&clkc 4>; ++ compatible = "xlnx,ps7-scuwdt-1.00.a"; ++ device_type = "watchdog"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <1 14 0x301>; ++ reg = <0xf8f00620 0xe0>; ++ } ; ++ ps7_sd_0: ps7-sdio@e0100000 { ++ clock-frequency = <50000000>; ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 21>, <&clkc 32>; ++ compatible = "xlnx,ps7-sdio-1.00.a", "generic-sdhci", "arasan,sdhci"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 24 4>; ++ reg = <0xe0100000 0x1000>; ++ xlnx,has-cd = <0x1>; ++ xlnx,has-power = <0x0>; ++ xlnx,has-wp = <0x1>; ++ } ; ++ ps7_slcr_0: ps7-slcr@f8000000 { ++ compatible = "xlnx,ps7-slcr-1.00.a", "xlnx,zynq-slcr"; ++ reg = <0xf8000000 0x1000>; ++ clocks { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clkc: clkc { ++ #clock-cells = <1>; ++ clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x", "cpu_3or2x", ++ "cpu_2x", "cpu_1x", "ddr2x", "ddr3x", "dci", ++ "lqspi", "smc", "pcap", "gem0", "gem1", ++ "fclk0", "fclk1", "fclk2", "fclk3", "can0", ++ "can1", "sdio0", "sdio1", "uart0", "uart1", ++ "spi0", "spi1", "dma", "usb0_aper", "usb1_aper", ++ "gem0_aper", "gem1_aper", "sdio0_aper", "sdio1_aper", "spi0_aper", ++ "spi1_aper", "can0_aper", "can1_aper", "i2c0_aper", "i2c1_aper", ++ "uart0_aper", "uart1_aper", "gpio_aper", "lqspi_aper", "smc_aper", ++ "swdt", "dbg_trc", "dbg_apb"; ++ compatible = "xlnx,ps7-clkc"; ++ fclk-enable = <0xf>; ++ ps-clk-frequency = <33333333>; ++ } ; ++ } ; ++ } ; ++ ps7_ttc_0: ps7-ttc@f8001000 { ++ clocks = <&clkc 6>; ++ compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; ++ interrupt-names = "ttc0", "ttc1", "ttc2"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 10 4>, <0 11 4>, <0 12 4>; ++ reg = <0xf8001000 0x1000>; ++ } ; ++ ps7_ttc_1: ps7-ttc@f8002000 { ++ clocks = <&clkc 6>; ++ compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; ++ interrupt-names = "ttc0", "ttc1", "ttc2"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 37 4>, <0 38 4>, <0 39 4>; ++ reg = <0xf8002000 0x1000>; ++ } ; ++ ps7_uart_1: serial@e0001000 { ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 24>, <&clkc 41>; ++ compatible = "xlnx,ps7-uart-1.00.a", "xlnx,xuartps"; ++ current-speed = <115200>; ++ device_type = "serial"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 50 4>; ++ port-number = <0>; ++ reg = <0xe0001000 0x1000>; ++ xlnx,has-modem = <0x0>; ++ } ; ++ ps7_usb_0: ps7-usb@e0002000 { ++ clocks = <&clkc 28>; ++ compatible = "xlnx,ps7-usb-1.00.a"; ++ dr_mode = "host"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 21 4>; ++ phy_type = "ulpi"; ++ reg = <0xe0002000 0x1000>; ++ usb-reset = <&ps7_gpio_0 7 0>; ++ } ; ++ ps7_wdt_0: ps7-wdt@f8005000 { ++ clocks = <&clkc 45>; ++ compatible = "xlnx,ps7-wdt-1.00.a"; ++ device_type = "watchdog"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 9 1>; ++ reg = <0xf8005000 0x1000>; ++ reset = <0>; ++ timeout = <10>; ++ } ; ++ ps7_xadc: ps7-xadc@f8007100 { ++ clocks = <&clkc 12>; + compatible = "xlnx,ps7-xadc-1.00.a"; +- reg = <0xf8007100 0x20>; ++ interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 7 4>; +- interrupt-parent = <&gic>; +- }; +- ps7_dma_s: ps7-dma@f8003000 { +- #dma-cells = <1>; +- #dma-channels = <8>; +- #dma-requests = <4>; +- arm,primecell-periphid = <0x41330>; +- compatible = "xlnx,ps7-dma-1.00.a", "arm,primecell", "arm,pl330"; +- interrupt-parent = <&gic>; +- interrupts = < 0 13 4 0 14 4 0 15 4 0 16 4 0 17 4 0 40 4 0 41 4 0 42 4 0 43 4 >; +- reg = < 0xf8003000 0x1000 >; ++ reg = <0xf8007100 0x20>; + } ; +- }; +-}; ++ } ; ++} ; +diff --git a/arch/arm/boot/dts/zynq-zc770-xm010.dts b/arch/arm/boot/dts/zynq-zc770-xm010.dts +index 61f4e76..c467c0e 100644 +--- a/arch/arm/boot/dts/zynq-zc770-xm010.dts ++++ b/arch/arm/boot/dts/zynq-zc770-xm010.dts +@@ -1,156 +1,143 @@ +-/dts-v1/; ++/* ++ * Device Tree Generator version: 1.1 ++ * ++ * (C) Copyright 2007-2013 Xilinx, Inc. ++ * (C) Copyright 2007-2013 Michal Simek ++ * (C) Copyright 2007-2012 PetaLogix Qld Pty Ltd ++ * ++ * Michal SIMEK ++ * ++ * CAUTION: This file is automatically generated by libgen. ++ * Version: Xilinx EDK 14.5 EDK_P.58f ++ * ++ */ + ++/dts-v1/; + / { +- model = "Xilinx Zynq ZC770 - V&C dt1 - minimum)"; +- compatible = "xlnx,zynq-zc770"; +- #address-cells = <0x1>; +- #size-cells = <0x1>; +- interrupt-parent = <0x1>; +- +- memory { +- device_type = "memory"; +- reg = <0x00000000 0x40000000>; +- }; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "xlnx,zynq-7000"; ++ model = "Xilinx Zynq"; ++ aliases { ++ ethernet0 = &ps7_ethernet_0; ++ i2c0 = &ps7_i2c_0; ++ serial0 = &ps7_uart_1; ++ spi0 = &ps7_spi_1; ++ spi1 = &ps7_qspi_0; ++ } ; + chosen { +- bootargs = "console=ttyPS0,115200 root=/dev/ram rw ip=:::::eth0:dhcp earlyprintk"; +- linux,stdout-path = "/amba@0/uart@E0001000"; +- }; +- ++ bootargs = "console=ttyPS0,115200 root=/dev/ram rw earlyprintk"; ++ linux,stdout-path = "/amba@0/serial@e0001000"; ++ } ; ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ps7_cortexa9_0: cpu@0 { ++ bus-handle = <&ps7_axi_interconnect_0>; ++ compatible = "arm,cortex-a9"; ++ d-cache-line-size = <0x20>; ++ d-cache-size = <0x8000>; ++ device_type = "cpu"; ++ i-cache-line-size = <0x20>; ++ i-cache-size = <0x8000>; ++ interrupt-handle = <&ps7_scugic_0>; ++ reg = <0x0>; ++ } ; ++ ps7_cortexa9_1: cpu@1 { ++ bus-handle = <&ps7_axi_interconnect_0>; ++ compatible = "arm,cortex-a9"; ++ d-cache-line-size = <0x20>; ++ d-cache-size = <0x8000>; ++ device_type = "cpu"; ++ i-cache-line-size = <0x20>; ++ i-cache-size = <0x8000>; ++ interrupt-handle = <&ps7_scugic_0>; ++ reg = <0x1>; ++ } ; ++ } ; + pmu { + compatible = "arm,cortex-a9-pmu"; ++ interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 5 4>, <0 6 4>; +- interrupt-parent = <&gic>; +- }; +- +- amba@0 { +- compatible = "simple-bus"; +- #address-cells = <0x1>; +- #size-cells = <0x1>; +- ranges; +- +- gic: intc@f8f01000 { +- interrupt-controller; +- compatible = "arm,cortex-a9-gic"; +- #interrupt-cells = <3>; +- reg = < 0xf8f01000 0x1000 >, +- < 0xf8f00100 0x0100 >; +- }; +- +- pl310@f8f02000 { +- compatible = "arm,pl310-cache"; +- cache-unified; +- cache-level = <2>; +- reg = <0xf8f02000 0x1000>; +- arm,data-latency = <3 2 2>; +- arm,tag-latency = <2 2 2>; +- }; +- ++ reg = <0xf8891000 0x1000>, <0xf8893000 0x1000>; ++ reg-names = "cpu0", "cpu1"; ++ } ; ++ ps7_ddr_0: memory@0 { ++ device_type = "memory"; ++ reg = <0x0 0x40000000>; ++ } ; ++ ps7_axi_interconnect_0: amba@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "xlnx,ps7-axi-interconnect-1.00.a", "simple-bus"; ++ ranges ; ++ ps7_afi_0: ps7-afi@f8008000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf8008000 0x1000>; ++ } ; ++ ps7_afi_1: ps7-afi@f8009000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf8009000 0x1000>; ++ } ; ++ ps7_afi_2: ps7-afi@f800a000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf800a000 0x1000>; ++ } ; ++ ps7_afi_3: ps7-afi@f800b000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf800b000 0x1000>; ++ } ; ++ ps7_can_0: ps7-can@e0008000 { ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 19>, <&clkc 36>; ++ compatible = "xlnx,ps7-can-1.00.a", "xlnx,ps7-can"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 28 4>; ++ reg = <0xe0008000 0x1000>; ++ } ; + ps7_ddrc_0: ps7-ddrc@f8006000 { + compatible = "xlnx,ps7-ddrc-1.00.a", "xlnx,ps7-ddrc"; +- reg = < 0xf8006000 0x1000 >; ++ reg = <0xf8006000 0x1000>; + xlnx,has-ecc = <0x0>; + } ; +- +- ps7_ocm_0: ps7-ocm@0xfffc0000 { +- compatible = "xlnx,ps7-ocm"; +- reg = <0xfffc0000 0x40000>; /* 256k */ +- }; +- +- uart@e0001000 { +- compatible = "xlnx,ps7-uart-1.00.a"; +- reg = <0xe0001000 0x1000>; +- interrupts = < 0 50 4 >; +- interrupt-parent = <&gic>; +- clock = <50000000>; +- }; +- +- slcr: slcr@f8000000 { +- compatible = "xlnx,zynq-slcr"; +- reg = <0xF8000000 0x1000>; +- clocks { +- #address-cells = <1>; +- #size-cells = <0>; +- armpll: armpll { +- #clock-cells = <0>; +- clock-output-names = "armpll"; +- clocks = <&ps_clk>; +- compatible = "xlnx,zynq-pll"; +- lockbit = <0>; +- reg = < 0x100 0x110 0x10c >; +- } ; +- ddrpll: ddrpll { +- #clock-cells = <0>; +- clock-output-names = "ddrpll"; +- clocks = <&ps_clk>; +- compatible = "xlnx,zynq-pll"; +- lockbit = <1>; +- reg = < 0x104 0x114 0x10c >; +- } ; +- iopll: iopll { +- #clock-cells = <0>; +- clock-output-names = "iopll"; +- clocks = <&ps_clk>; +- compatible = "xlnx,zynq-pll"; +- lockbit = <2>; +- reg = < 0x108 0x118 0x10c >; +- } ; +- ps_clk: ps_clk { +- #clock-cells = <0>; +- clock-frequency = <33333333>; +- clock-output-names = "ps_clk"; +- compatible = "fixed-clock"; +- } ; +- } ; +- }; +- +- timer@0xf8001000 { +- compatible = "xlnx,ps7-ttc-1.00.a"; +- reg = <0xf8001000 0x1000>; +- interrupts = <0 10 4>,<0 11 4>,<0 12 4>; +- interrupt-parent = <&gic>; +- }; +- +- timer@f8f00600 { +- compatible = "arm,cortex-a9-twd-timer"; +- reg = <0xf8f00600 0x20>; +- interrupts = <1 13 0x0301>; +- interrupt-parent = <&gic>; +- }; +- +- swdt@f8005000 { +- device_type = "watchdog"; +- compatible = "xlnx,ps7-wdt-1.00.a"; +- interrupts = <0 9 4>; +- interrupt-parent = <&gic>; +- reg = <0xf8005000 0x100>; +- reset = <0>; +- timeout = <10>; +- }; +- +- scuwdt@f8f00620 { +- device_type = "watchdog"; +- compatible = "arm,mpcore_wdt"; +- reg = <0xf8f00620 0x20>; +- clock-frequency = <400000000>; +- reset = <1>; +- }; +- +- eth@e000b000 { ++ ps7_dev_cfg_0: ps7-dev-cfg@f8007000 { ++ clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3"; ++ clocks = <&clkc 12>, <&clkc 15>, <&clkc 16>, <&clkc 17>, <&clkc 18>; ++ compatible = "xlnx,ps7-dev-cfg-1.00.a"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 8 4>; ++ reg = <0xf8007000 0x100>; ++ } ; ++ ps7_dma_s: ps7-dma@f8003000 { ++ #dma-cells = <1>; ++ #dma-channels = <8>; ++ #dma-requests = <4>; ++ arm,primecell-periphid = <0x41330>; ++ clock-names = "apb_pclk"; ++ clocks = <&clkc 27>; ++ compatible = "xlnx,ps7-dma-1.00.a", "arm,primecell", "arm,pl330"; ++ interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3", ++ "dma4", "dma5", "dma6", "dma7"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 13 4>, <0 14 4>, <0 15 4>, <0 16 4>, <0 17 4>, <0 40 4>, <0 41 4>, <0 42 4>, <0 43 4>; ++ reg = <0xf8003000 0x1000>; ++ } ; ++ ps7_ethernet_0: ps7-ethernet@e000b000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 13>, <&clkc 30>; + compatible = "xlnx,ps7-ethernet-1.00.a"; +- reg = <0xe000b000 0x1000>; ++ interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 22 4>; +- interrupt-parent = <&gic>; ++ local-mac-address = [00 0a 35 00 00 00]; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; +- xlnx,ptp-enet-clock = <133000000>; +- xlnx,slcr-div0-1000Mbps = <8>; +- xlnx,slcr-div0-100Mbps = <8>; +- xlnx,slcr-div0-10Mbps = <8>; +- xlnx,slcr-div1-1000Mbps = <1>; +- xlnx,slcr-div1-100Mbps = <5>; +- xlnx,slcr-div1-10Mbps = <50>; +- #address-cells = <0x1>; +- #size-cells = <0x0>; ++ reg = <0xe000b000 0x1000>; ++ xlnx,enet-reset = <0xffffffff>; ++ xlnx,eth-mode = <0x1>; ++ xlnx,has-mdio = <0x1>; ++ xlnx,ptp-enet-clock = <111111115>; + mdio { + #address-cells = <1>; + #size-cells = <0>; +@@ -158,84 +145,64 @@ + compatible = "marvell,88e1116r"; + device_type = "ethernet-phy"; + reg = <7>; +- }; +- }; +- }; +- +- sdhci@e0100000 { +- compatible = "xlnx,ps7-sdhci-1.00.a"; +- reg = <0xe0100000 0x1000>; +- interrupts = <0 24 4>; +- interrupt-parent = <&gic>; +- clock-frequency = <33333000>; +- }; +- +- usb@e0002000 { +- compatible = "xlnx,ps7-usb-1.00.a"; +- reg = <0xe0002000 0x1000>; +- interrupts = <0 21 4>; +- interrupt-parent = <&gic>; +- dr_mode = "host"; +- phy_type = "ulpi"; +- }; +- +- gpio@e000a000 { ++ } ; ++ } ; ++ } ; ++ ps7_gpio_0: ps7-gpio@e000a000 { ++ #gpio-cells = <2>; ++ clocks = <&clkc 42>; + compatible = "xlnx,ps7-gpio-1.00.a"; +- reg = <0xe000a000 0x1000>; ++ emio-gpio-width = <64>; ++ gpio-controller ; ++ gpio-mask-high = <0x0>; ++ gpio-mask-low = <0x200>; ++ interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 20 4>; +- interrupt-parent = <&gic>; +- }; +- i2c0: i2c@e0004000 { +- compatible = "xlnx,ps7-i2c-1.00.a"; +- reg = <0xE0004000 0x1000>; +- interrupts = <0 25 4>; +- interrupt-parent = <&gic>; ++ reg = <0xe000a000 0x1000>; ++ } ; ++ ps7_i2c_0: ps7-i2c@e0004000 { + bus-id = <0>; +- input-clk = <133000000>; ++ clocks = <&clkc 38>; ++ compatible = "xlnx,ps7-i2c-1.00.a"; + i2c-clk = <400000>; +- ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 25 4>; ++ reg = <0xe0004000 0x1000>; ++ xlnx,has-interrupt = <0x0>; ++ xlnx,i2c-reset = <0xffffffff>; + #address-cells = <1>; + #size-cells = <0>; + m24c02_eeprom@52 { + compatible = "at,24c02"; + reg = <0x52>; + }; +- }; + +- spi1: spi@e0007000 { +- compatible = "xlnx,ps7-spi-1.00.a"; +- reg = <0xE0007000 0x1000>; +- interrupts = <0 49 4>; +- interrupt-parent = <&gic>; +- speed-hz = <166666700>; +- bus-num = <0>; +- num-chip-select = <4>; +- +- #address-cells = <1>; +- #size-cells = <0>; +- flash@0 { +- compatible = "sst25wf080"; +- reg = <1>; +- spi-max-frequency = <1000000>; +- #address-cells = <1>; +- #size-cells = <1>; +- partition@test { +- label = "spi-flash"; +- reg = <0x0 0x100000>; +- }; +- }; +- +- +- }; +- qspi0: spi@e000d000 { ++ } ; ++ ps7_iop_bus_config_0: ps7-iop-bus-config@e0200000 { ++ compatible = "xlnx,ps7-iop-bus-config-1.00.a"; ++ reg = <0xe0200000 0x1000>; ++ } ; ++ ps7_pl310_0: ps7-pl310@f8f02000 { ++ arm,data-latency = <3 2 2>; ++ arm,tag-latency = <2 2 2>; ++ cache-level = <2>; ++ cache-unified ; ++ compatible = "xlnx,ps7-pl310-1.00.a", "arm,pl310-cache"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 2 4>; ++ reg = <0xf8f02000 0x1000>; ++ } ; ++ ps7_qspi_0: ps7-qspi@e000d000 { ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 10>, <&clkc 43>; + compatible = "xlnx,ps7-qspi-1.00.a"; +- reg = <0xE000D000 0x1000>; ++ interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 19 4>; +- interrupt-parent = <&gic>; +- speed-hz = <200000000>; +- bus-num = <1>; +- num-chip-select = <1>; + is-dual = <0>; ++ num-chip-select = <1>; ++ reg = <0xe000d000 0x1000>; ++ xlnx,fb-clk = <0x1>; ++ xlnx,qspi-mode = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + flash@0 { +@@ -265,22 +232,150 @@ + reg = <0xC00000 0x400000>; + }; + }; +- }; +- devcfg@f8007000 { +- compatible = "xlnx,ps7-dev-cfg-1.00.a"; +- reg = <0xf8007000 0x1000>; +- interrupts = <0 8 4>; +- interrupt-parent = <&gic>; +- }; +- ps7_dma_s: ps7-dma@f8003000 { +- #dma-cells = <1>; +- #dma-channels = <8>; +- #dma-requests = <4>; +- arm,primecell-periphid = <0x41330>; +- compatible = "xlnx,ps7-dma-1.00.a", "arm,primecell", "arm,pl330"; +- interrupt-parent = <&gic>; +- interrupts = < 0 13 4 0 14 4 0 15 4 0 16 4 0 17 4 0 40 4 0 41 4 0 42 4 0 43 4 >; +- reg = < 0xf8003000 0x1000 >; ++ ++ } ; ++ ps7_qspi_linear_0: ps7-qspi-linear@fc000000 { ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 10>, <&clkc 43>; ++ compatible = "xlnx,ps7-qspi-linear-1.00.a"; ++ reg = <0xfc000000 0x1000000>; ++ } ; ++ ps7_ram_0: ps7-ram@0 { ++ compatible = "xlnx,ps7-ram-1.00.a", "xlnx,ps7-ocm"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 3 4>; ++ reg = <0xfffc0000 0x40000>; ++ } ; ++ ps7_scugic_0: ps7-scugic@f8f01000 { ++ #address-cells = <2>; ++ #interrupt-cells = <3>; ++ #size-cells = <1>; ++ compatible = "xlnx,ps7-scugic-1.00.a", "arm,cortex-a9-gic", "arm,gic"; ++ interrupt-controller ; ++ num_cpus = <2>; ++ num_interrupts = <96>; ++ reg = <0xf8f01000 0x1000>, <0xf8f00100 0x100>; ++ } ; ++ ps7_scutimer_0: ps7-scutimer@f8f00600 { ++ clocks = <&clkc 4>; ++ compatible = "xlnx,ps7-scutimer-1.00.a", "arm,cortex-a9-twd-timer"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <1 13 0x301>; ++ reg = <0xf8f00600 0x20>; ++ } ; ++ ps7_scuwdt_0: ps7-scuwdt@f8f00620 { ++ clocks = <&clkc 4>; ++ compatible = "xlnx,ps7-scuwdt-1.00.a"; ++ device_type = "watchdog"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <1 14 0x301>; ++ reg = <0xf8f00620 0xe0>; ++ } ; ++ ps7_sd_0: ps7-sdio@e0100000 { ++ clock-frequency = <50000000>; ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 21>, <&clkc 32>; ++ compatible = "xlnx,ps7-sdio-1.00.a", "generic-sdhci", "arasan,sdhci"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 24 4>; ++ reg = <0xe0100000 0x1000>; ++ xlnx,has-cd = <0x1>; ++ xlnx,has-power = <0x0>; ++ xlnx,has-wp = <0x1>; ++ } ; ++ ps7_slcr_0: ps7-slcr@f8000000 { ++ compatible = "xlnx,ps7-slcr-1.00.a", "xlnx,zynq-slcr"; ++ reg = <0xf8000000 0x1000>; ++ clocks { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clkc: clkc { ++ #clock-cells = <1>; ++ clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x", "cpu_3or2x", ++ "cpu_2x", "cpu_1x", "ddr2x", "ddr3x", "dci", ++ "lqspi", "smc", "pcap", "gem0", "gem1", ++ "fclk0", "fclk1", "fclk2", "fclk3", "can0", ++ "can1", "sdio0", "sdio1", "uart0", "uart1", ++ "spi0", "spi1", "dma", "usb0_aper", "usb1_aper", ++ "gem0_aper", "gem1_aper", "sdio0_aper", "sdio1_aper", "spi0_aper", ++ "spi1_aper", "can0_aper", "can1_aper", "i2c0_aper", "i2c1_aper", ++ "uart0_aper", "uart1_aper", "gpio_aper", "lqspi_aper", "smc_aper", ++ "swdt", "dbg_trc", "dbg_apb"; ++ compatible = "xlnx,ps7-clkc"; ++ fclk-enable = <0xf>; ++ ps-clk-frequency = <33333333>; ++ } ; ++ } ; ++ } ; ++ ps7_spi_1: ps7-spi@e0007000 { ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 26>, <&clkc 35>; ++ compatible = "xlnx,ps7-spi-1.00.a"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 49 4>; ++ num-chip-select = <4>; ++ reg = <0xe0007000 0x1000>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ flash@0 { ++ compatible = "sst25wf080"; ++ reg = <1>; ++ spi-max-frequency = <1000000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ partition@test { ++ label = "spi-flash"; ++ reg = <0x0 0x100000>; ++ }; ++ }; ++ ++ } ; ++ ps7_ttc_0: ps7-ttc@f8001000 { ++ clocks = <&clkc 6>; ++ compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; ++ interrupt-names = "ttc0", "ttc1", "ttc2"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 10 4>, <0 11 4>, <0 12 4>; ++ reg = <0xf8001000 0x1000>; ++ } ; ++ ps7_uart_1: serial@e0001000 { ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 24>, <&clkc 41>; ++ compatible = "xlnx,ps7-uart-1.00.a", "xlnx,xuartps"; ++ current-speed = <115200>; ++ device_type = "serial"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 50 4>; ++ port-number = <0>; ++ reg = <0xe0001000 0x1000>; ++ xlnx,has-modem = <0x0>; ++ } ; ++ ps7_usb_0: ps7-usb@e0002000 { ++ clocks = <&clkc 28>; ++ compatible = "xlnx,ps7-usb-1.00.a"; ++ dr_mode = "host"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 21 4>; ++ phy_type = "ulpi"; ++ reg = <0xe0002000 0x1000>; ++ usb-reset = <&ps7_gpio_0 7 0>; ++ } ; ++ ps7_wdt_0: ps7-wdt@f8005000 { ++ clocks = <&clkc 45>; ++ compatible = "xlnx,ps7-wdt-1.00.a"; ++ device_type = "watchdog"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 9 1>; ++ reg = <0xf8005000 0x1000>; ++ reset = <0>; ++ timeout = <10>; ++ } ; ++ ps7_xadc: ps7-xadc@f8007100 { ++ clocks = <&clkc 12>; ++ compatible = "xlnx,ps7-xadc-1.00.a"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 7 4>; ++ reg = <0xf8007100 0x20>; + } ; +- }; +-}; ++ } ; ++} ; +diff --git a/arch/arm/boot/dts/zynq-zc770-xm011.dts b/arch/arm/boot/dts/zynq-zc770-xm011.dts +index 137eea6..7121a84 100644 +--- a/arch/arm/boot/dts/zynq-zc770-xm011.dts ++++ b/arch/arm/boot/dts/zynq-zc770-xm011.dts +@@ -1,162 +1,249 @@ +-/dts-v1/; ++/* ++ * Device Tree Generator version: 1.1 ++ * ++ * (C) Copyright 2007-2013 Xilinx, Inc. ++ * (C) Copyright 2007-2013 Michal Simek ++ * (C) Copyright 2007-2012 PetaLogix Qld Pty Ltd ++ * ++ * Michal SIMEK ++ * ++ * CAUTION: This file is automatically generated by libgen. ++ * Version: Xilinx EDK 14.5 EDK_P.58f ++ * ++ */ + ++/dts-v1/; + / { +- model = "Xilinx Zynq ZC770 - V&C dt1 - minimum)"; +- compatible = "xlnx,zynq-zc770"; +- #address-cells = <0x1>; +- #size-cells = <0x1>; +- interrupt-parent = <0x1>; +- +- memory { +- device_type = "memory"; +- reg = <0x0 0x40000000>; +- }; +- ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "xlnx,zynq-7000"; ++ model = "Xilinx Zynq"; ++ aliases { ++ i2c0 = &ps7_i2c_1; ++ serial0 = &ps7_uart_1; ++ spi0 = &ps7_spi_0; ++ } ; + chosen { + bootargs = "console=ttyPS0,115200 root=/dev/ram rw earlyprintk"; +- linux,stdout-path = "/amba@0/uart@E0001000"; +- }; +- ++ linux,stdout-path = "/amba@0/serial@e0001000"; ++ } ; ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ps7_cortexa9_0: cpu@0 { ++ bus-handle = <&ps7_axi_interconnect_0>; ++ compatible = "arm,cortex-a9"; ++ d-cache-line-size = <0x20>; ++ d-cache-size = <0x8000>; ++ device_type = "cpu"; ++ i-cache-line-size = <0x20>; ++ i-cache-size = <0x8000>; ++ interrupt-handle = <&ps7_scugic_0>; ++ reg = <0x0>; ++ } ; ++ ps7_cortexa9_1: cpu@1 { ++ bus-handle = <&ps7_axi_interconnect_0>; ++ compatible = "arm,cortex-a9"; ++ d-cache-line-size = <0x20>; ++ d-cache-size = <0x8000>; ++ device_type = "cpu"; ++ i-cache-line-size = <0x20>; ++ i-cache-size = <0x8000>; ++ interrupt-handle = <&ps7_scugic_0>; ++ reg = <0x1>; ++ } ; ++ } ; + pmu { + compatible = "arm,cortex-a9-pmu"; ++ interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 5 4>, <0 6 4>; +- interrupt-parent = <&gic>; +- }; +- +- amba@0 { +- compatible = "simple-bus"; +- #address-cells = <0x1>; +- #size-cells = <0x1>; +- ranges; +- +- gic: intc@f8f01000 { +- interrupt-controller; +- compatible = "arm,cortex-a9-gic"; +- #interrupt-cells = <3>; +- reg = < 0xf8f01000 0x1000 >, +- < 0xf8f00100 0x0100 >; +- }; +- +- pl310@f8f02000 { +- compatible = "arm,pl310-cache"; +- cache-unified; +- cache-level = <2>; +- reg = <0xf8f02000 0x1000>; +- arm,data-latency = <3 2 2>; +- arm,tag-latency = <2 2 2>; +- }; +- ++ reg = <0xf8891000 0x1000>, <0xf8893000 0x1000>; ++ reg-names = "cpu0", "cpu1"; ++ } ; ++ ps7_ddr_0: memory@0 { ++ device_type = "memory"; ++ reg = <0x0 0x40000000>; ++ } ; ++ ps7_axi_interconnect_0: amba@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "xlnx,ps7-axi-interconnect-1.00.a", "simple-bus"; ++ ranges ; ++ ps7_afi_0: ps7-afi@f8008000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf8008000 0x1000>; ++ } ; ++ ps7_afi_1: ps7-afi@f8009000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf8009000 0x1000>; ++ } ; ++ ps7_afi_2: ps7-afi@f800a000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf800a000 0x1000>; ++ } ; ++ ps7_afi_3: ps7-afi@f800b000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf800b000 0x1000>; ++ } ; ++ ps7_can_0: ps7-can@e0008000 { ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 19>, <&clkc 36>; ++ compatible = "xlnx,ps7-can-1.00.a", "xlnx,ps7-can"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 28 4>; ++ reg = <0xe0008000 0x1000>; ++ } ; + ps7_ddrc_0: ps7-ddrc@f8006000 { + compatible = "xlnx,ps7-ddrc-1.00.a", "xlnx,ps7-ddrc"; +- reg = < 0xf8006000 0x1000 >; ++ reg = <0xf8006000 0x1000>; + xlnx,has-ecc = <0x0>; + } ; ++ ps7_dev_cfg_0: ps7-dev-cfg@f8007000 { ++ clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3"; ++ clocks = <&clkc 12>, <&clkc 15>, <&clkc 16>, <&clkc 17>, <&clkc 18>; ++ compatible = "xlnx,ps7-dev-cfg-1.00.a"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 8 4>; ++ reg = <0xf8007000 0x100>; ++ } ; ++ ps7_dma_s: ps7-dma@f8003000 { ++ #dma-cells = <1>; ++ #dma-channels = <8>; ++ #dma-requests = <4>; ++ arm,primecell-periphid = <0x41330>; ++ clock-names = "apb_pclk"; ++ clocks = <&clkc 27>; ++ compatible = "xlnx,ps7-dma-1.00.a", "arm,primecell", "arm,pl330"; ++ interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3", ++ "dma4", "dma5", "dma6", "dma7"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 13 4>, <0 14 4>, <0 15 4>, <0 16 4>, <0 17 4>, <0 40 4>, <0 41 4>, <0 42 4>, <0 43 4>; ++ reg = <0xf8003000 0x1000>; ++ } ; ++ ps7_gpio_0: ps7-gpio@e000a000 { ++ #gpio-cells = <2>; ++ clocks = <&clkc 42>; ++ compatible = "xlnx,ps7-gpio-1.00.a"; ++ emio-gpio-width = <64>; ++ gpio-controller ; ++ gpio-mask-high = <0xfc>; ++ gpio-mask-low = <0xff8002>; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 20 4>; ++ reg = <0xe000a000 0x1000>; ++ } ; ++ ps7_i2c_1: ps7-i2c@e0005000 { ++ bus-id = <0>; ++ clocks = <&clkc 39>; ++ compatible = "xlnx,ps7-i2c-1.00.a"; ++ i2c-clk = <400000>; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 48 4>; ++ reg = <0xe0005000 0x1000>; ++ xlnx,has-interrupt = <0x0>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ m24c02_eeprom@52 { ++ compatible = "at,24c02"; ++ reg = <0x52>; ++ }; + +- ps7_ocm_0: ps7-ocm@0xfffc0000 { +- compatible = "xlnx,ps7-ocm"; +- reg = <0xfffc0000 0x40000>; /* 256k */ +- }; +- +- uart@e0001000 { +- compatible = "xlnx,ps7-uart-1.00.a"; +- reg = <0xe0001000 0x1000>; +- interrupts = < 0 50 4 >; +- interrupt-parent = <&gic>; +- clock = <0x2faf080>; +- }; +- +- slcr: slcr@f8000000 { +- compatible = "xlnx,zynq-slcr"; +- reg = <0xF8000000 0x1000>; ++ } ; ++ ps7_iop_bus_config_0: ps7-iop-bus-config@e0200000 { ++ compatible = "xlnx,ps7-iop-bus-config-1.00.a"; ++ reg = <0xe0200000 0x1000>; ++ } ; ++ ps7_pl310_0: ps7-pl310@f8f02000 { ++ arm,data-latency = <3 2 2>; ++ arm,tag-latency = <2 2 2>; ++ cache-level = <2>; ++ cache-unified ; ++ compatible = "xlnx,ps7-pl310-1.00.a", "arm,pl310-cache"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 2 4>; ++ reg = <0xf8f02000 0x1000>; ++ } ; ++ ps7_ram_0: ps7-ram@0 { ++ compatible = "xlnx,ps7-ram-1.00.a", "xlnx,ps7-ocm"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 3 4>; ++ reg = <0xfffc0000 0x40000>; ++ } ; ++ ps7_scugic_0: ps7-scugic@f8f01000 { ++ #address-cells = <2>; ++ #interrupt-cells = <3>; ++ #size-cells = <1>; ++ compatible = "xlnx,ps7-scugic-1.00.a", "arm,cortex-a9-gic", "arm,gic"; ++ interrupt-controller ; ++ num_cpus = <2>; ++ num_interrupts = <96>; ++ reg = <0xf8f01000 0x1000>, <0xf8f00100 0x100>; ++ } ; ++ ps7_scutimer_0: ps7-scutimer@f8f00600 { ++ clocks = <&clkc 4>; ++ compatible = "xlnx,ps7-scutimer-1.00.a", "arm,cortex-a9-twd-timer"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <1 13 0x301>; ++ reg = <0xf8f00600 0x20>; ++ } ; ++ ps7_scuwdt_0: ps7-scuwdt@f8f00620 { ++ clocks = <&clkc 4>; ++ compatible = "xlnx,ps7-scuwdt-1.00.a"; ++ device_type = "watchdog"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <1 14 0x301>; ++ reg = <0xf8f00620 0xe0>; ++ } ; ++ ps7_slcr_0: ps7-slcr@f8000000 { ++ compatible = "xlnx,ps7-slcr-1.00.a", "xlnx,zynq-slcr"; ++ reg = <0xf8000000 0x1000>; + clocks { + #address-cells = <1>; + #size-cells = <0>; +- armpll: armpll { +- #clock-cells = <0>; +- clock-output-names = "armpll"; +- clocks = <&ps_clk>; +- compatible = "xlnx,zynq-pll"; +- lockbit = <0>; +- reg = < 0x100 0x110 0x10c >; +- } ; +- ddrpll: ddrpll { +- #clock-cells = <0>; +- clock-output-names = "ddrpll"; +- clocks = <&ps_clk>; +- compatible = "xlnx,zynq-pll"; +- lockbit = <1>; +- reg = < 0x104 0x114 0x10c >; +- } ; +- iopll: iopll { +- #clock-cells = <0>; +- clock-output-names = "iopll"; +- clocks = <&ps_clk>; +- compatible = "xlnx,zynq-pll"; +- lockbit = <2>; +- reg = < 0x108 0x118 0x10c >; +- } ; +- ps_clk: ps_clk { +- #clock-cells = <0>; +- clock-frequency = <33333333>; +- clock-output-names = "ps_clk"; +- compatible = "fixed-clock"; ++ clkc: clkc { ++ #clock-cells = <1>; ++ clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x", "cpu_3or2x", ++ "cpu_2x", "cpu_1x", "ddr2x", "ddr3x", "dci", ++ "lqspi", "smc", "pcap", "gem0", "gem1", ++ "fclk0", "fclk1", "fclk2", "fclk3", "can0", ++ "can1", "sdio0", "sdio1", "uart0", "uart1", ++ "spi0", "spi1", "dma", "usb0_aper", "usb1_aper", ++ "gem0_aper", "gem1_aper", "sdio0_aper", "sdio1_aper", "spi0_aper", ++ "spi1_aper", "can0_aper", "can1_aper", "i2c0_aper", "i2c1_aper", ++ "uart0_aper", "uart1_aper", "gpio_aper", "lqspi_aper", "smc_aper", ++ "swdt", "dbg_trc", "dbg_apb"; ++ compatible = "xlnx,ps7-clkc"; ++ fclk-enable = <0xf>; ++ ps-clk-frequency = <33333333>; + } ; + } ; +- }; +- +- timer@0xf8001000 { +- compatible = "xlnx,ps7-ttc-1.00.a"; +- reg = <0xf8001000 0x1000>; +- interrupts = <0 10 4>,<0 11 4>,<0 12 4>; +- interrupt-parent = <&gic>; +- }; +- +- timer@f8f00600 { +- compatible = "arm,cortex-a9-twd-timer"; +- reg = <0xf8f00600 0x20>; +- interrupts = <1 13 0x301>; +- interrupt-parent = <&gic>; +- }; +- +- swdt@f8005000 { +- device_type = "watchdog"; +- compatible = "xlnx,ps7-wdt-1.00.a"; +- interrupts = <0 9 4>; +- interrupt-parent = <&gic>; +- reg = <0xf8005000 0x100>; +- reset = <0>; +- timeout = <10>; +- }; +- +- scuwdt@f8f00620 { +- device_type = "watchdog"; +- compatible = "arm,mpcore_wdt"; +- reg = <0xf8f00620 0x20>; +- clock-frequency = <400000000>; +- reset = <1>; +- }; +- +- spi: spi@e0006000 { +- compatible = "xlnx,ps7-spi-1.00.a"; +- reg = <0xe0006000 0x1000>; +- interrupts = <0 26 4>; +- interrupt-parent = <&gic>; +- speed-hz = <50000000>; +- bus-num = <0>; +- num-chip-select = <4>; +- }; +- +- smc@0xe000e000 { +- compatible = "xlnx,ps7-smc"; +- reg = <0xe000e000 0x1000>; ++ } ; ++ ps7_smcc_0: ps7-smcc@e000e000 { + #address-cells = <1>; + #size-cells = <1>; +- ranges; +- +- nand@e1000000 { ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 11>, <&clkc 44>; ++ compatible = "xlnx,ps7-smcc-1.00.a", "xlnx,ps7-smc"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 18 4>; ++ ranges ; ++ reg = <0xe000e000 0x1000>; ++ xlnx,addr25 = <0x0>; ++ xlnx,nor-chip-sel0 = <0x0>; ++ xlnx,nor-chip-sel1 = <0x0>; ++ xlnx,sram-chip-sel0 = <0x0>; ++ xlnx,sram-chip-sel1 = <0x0>; ++ ps7_nand_0: ps7-nand@e1000000 { + compatible = "xlnx,ps7-nand-1.00.a"; + reg = <0xe1000000 0x1000000>; +- xlnx,nand-width = <8>; ++ xlnx,nand-cycle-t0 = <0x4>; ++ xlnx,nand-cycle-t1 = <0x4>; ++ xlnx,nand-cycle-t2 = <0x1>; ++ xlnx,nand-cycle-t3 = <0x2>; ++ xlnx,nand-cycle-t4 = <0x2>; ++ xlnx,nand-cycle-t5 = <0x2>; ++ xlnx,nand-cycle-t6 = <0x4>; ++ xlnx,nand-width = <0x8>; + #address-cells = <1>; + #size-cells = <1>; + +@@ -181,57 +268,63 @@ + reg = <0xC00000 0x400000>; + + }; +- }; +- }; +- +- i2c: i2c@e0005000 { +- compatible = "xlnx,ps7-i2c-1.00.a"; +- reg = <0xe0005000 0x1000>; +- interrupts = <0 48 4>; +- interrupt-parent = <&gic>; +- bus-id = <1>; +- input-clk = <50000000>; +- i2c-clk = <100000>; +- +- #address-cells = <1>; +- #size-cells = <0>; +- m24c02_eeprom@52 { +- compatible = "at,24c02"; +- reg = <0x52>; +- }; +- }; + +- usb@e0003000 { ++ } ; ++ } ; ++ ps7_spi_0: ps7-spi@e0006000 { ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 25>, <&clkc 34>; ++ compatible = "xlnx,ps7-spi-1.00.a"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 26 4>; ++ num-chip-select = <4>; ++ reg = <0xe0006000 0x1000>; ++ } ; ++ ps7_ttc_0: ps7-ttc@f8001000 { ++ clocks = <&clkc 6>; ++ compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; ++ interrupt-names = "ttc0", "ttc1", "ttc2"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 10 4>, <0 11 4>, <0 12 4>; ++ reg = <0xf8001000 0x1000>; ++ } ; ++ ps7_uart_1: serial@e0001000 { ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 24>, <&clkc 41>; ++ compatible = "xlnx,ps7-uart-1.00.a", "xlnx,xuartps"; ++ current-speed = <115200>; ++ device_type = "serial"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 50 4>; ++ port-number = <0>; ++ reg = <0xe0001000 0x1000>; ++ xlnx,has-modem = <0x0>; ++ } ; ++ ps7_usb_1: ps7-usb@e0003000 { ++ clocks = <&clkc 29>; + compatible = "xlnx,ps7-usb-1.00.a"; +- reg = <0xe0003000 0x1000>; +- interrupts = <0 44 4>; +- interrupt-parent = <&gic>; + dr_mode = "host"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 44 4>; + phy_type = "ulpi"; +- }; +- +- devcfg@f8007000 { +- compatible = "xlnx,ps7-dev-cfg-1.00.a"; +- reg = <0xf8007000 0x1000>; +- interrupts = <0 8 4>; +- interrupt-parent = <&gic>; +- }; +- +- gpio@e000a000 { +- compatible = "xlnx,ps7-gpio-1.00.a"; +- reg = <0xe000a000 0x1000>; +- interrupts = <0 20 4>; +- interrupt-parent = <&gic>; +- }; +- ps7_dma_s: ps7-dma@f8003000 { +- #dma-cells = <1>; +- #dma-channels = <8>; +- #dma-requests = <4>; +- arm,primecell-periphid = <0x41330>; +- compatible = "xlnx,ps7-dma-1.00.a", "arm,primecell", "arm,pl330"; +- interrupt-parent = <&gic>; +- interrupts = < 0 13 4 0 14 4 0 15 4 0 16 4 0 17 4 0 40 4 0 41 4 0 42 4 0 43 4 >; +- reg = < 0xf8003000 0x1000 >; ++ reg = <0xe0003000 0x1000>; ++ } ; ++ ps7_wdt_0: ps7-wdt@f8005000 { ++ clocks = <&clkc 45>; ++ compatible = "xlnx,ps7-wdt-1.00.a"; ++ device_type = "watchdog"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 9 1>; ++ reg = <0xf8005000 0x1000>; ++ reset = <0>; ++ timeout = <10>; ++ } ; ++ ps7_xadc: ps7-xadc@f8007100 { ++ clocks = <&clkc 12>; ++ compatible = "xlnx,ps7-xadc-1.00.a"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 7 4>; ++ reg = <0xf8007100 0x20>; + } ; +- }; +-}; ++ } ; ++} ; +diff --git a/arch/arm/boot/dts/zynq-zc770-xm012.dts b/arch/arm/boot/dts/zynq-zc770-xm012.dts +index f6d1f74..dc88e7d 100644 +--- a/arch/arm/boot/dts/zynq-zc770-xm012.dts ++++ b/arch/arm/boot/dts/zynq-zc770-xm012.dts +@@ -1,174 +1,268 @@ +-/dts-v1/; ++/* ++ * Device Tree Generator version: 1.1 ++ * ++ * (C) Copyright 2007-2013 Xilinx, Inc. ++ * (C) Copyright 2007-2013 Michal Simek ++ * (C) Copyright 2007-2012 PetaLogix Qld Pty Ltd ++ * ++ * Michal SIMEK ++ * ++ * CAUTION: This file is automatically generated by libgen. ++ * Version: Xilinx EDK 14.5 EDK_P.58f ++ * ++ */ + ++/dts-v1/; + / { +- model = "Xilinx Zynq ZC770 XM012 (DC3)"; +- compatible = "xlnx,zynq-zc770"; +- #address-cells = <0x1>; +- #size-cells = <0x1>; +- interrupt-parent = <0x1>; +- +- memory { +- device_type = "memory"; +- reg = <0x0 0x10000000>; +- }; +- ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "xlnx,zynq-7000"; ++ model = "Xilinx Zynq"; ++ aliases { ++ i2c0 = &ps7_i2c_0; ++ i2c1 = &ps7_i2c_1; ++ serial0 = &ps7_uart_1; ++ spi0 = &ps7_spi_1; ++ } ; + chosen { + bootargs = "console=ttyPS0,115200 root=/dev/ram rw earlyprintk"; +- linux,stdout-path = "/amba@0/uart@E0001000"; +- }; +- ++ linux,stdout-path = "/amba@0/serial@e0001000"; ++ } ; ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ps7_cortexa9_0: cpu@0 { ++ bus-handle = <&ps7_axi_interconnect_0>; ++ compatible = "arm,cortex-a9"; ++ d-cache-line-size = <0x20>; ++ d-cache-size = <0x8000>; ++ device_type = "cpu"; ++ i-cache-line-size = <0x20>; ++ i-cache-size = <0x8000>; ++ interrupt-handle = <&ps7_scugic_0>; ++ reg = <0x0>; ++ } ; ++ ps7_cortexa9_1: cpu@1 { ++ bus-handle = <&ps7_axi_interconnect_0>; ++ compatible = "arm,cortex-a9"; ++ d-cache-line-size = <0x20>; ++ d-cache-size = <0x8000>; ++ device_type = "cpu"; ++ i-cache-line-size = <0x20>; ++ i-cache-size = <0x8000>; ++ interrupt-handle = <&ps7_scugic_0>; ++ reg = <0x1>; ++ } ; ++ } ; + pmu { + compatible = "arm,cortex-a9-pmu"; ++ interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 5 4>, <0 6 4>; +- interrupt-parent = <&gic>; +- }; +- +- +- amba@0 { +- compatible = "simple-bus"; +- #address-cells = <0x1>; +- #size-cells = <0x1>; +- ranges; +- +- gic: intc@f8f01000 { +- interrupt-controller; +- compatible = "arm,cortex-a9-gic"; +- #interrupt-cells = <3>; +- reg = < 0xf8f01000 0x1000 >, +- < 0xf8f00100 0x0100 >; +- }; +- +- pl310@f8f02000 +- { +- compatible = "arm,pl310-cache"; +- cache-unified; +- cache-level = <2>; +- reg = <0xf8f02000 0x1000>; +- arm,data-latency = <3 2 2>; +- arm,tag-latency = <2 2 2>; +- }; +- ++ reg = <0xf8891000 0x1000>, <0xf8893000 0x1000>; ++ reg-names = "cpu0", "cpu1"; ++ } ; ++ ps7_ddr_0: memory@0 { ++ device_type = "memory"; ++ reg = <0x0 0x40000000>; ++ } ; ++ ps7_axi_interconnect_0: amba@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "xlnx,ps7-axi-interconnect-1.00.a", "simple-bus"; ++ ranges ; ++ ps7_afi_0: ps7-afi@f8008000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf8008000 0x1000>; ++ } ; ++ ps7_afi_1: ps7-afi@f8009000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf8009000 0x1000>; ++ } ; ++ ps7_afi_2: ps7-afi@f800a000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf800a000 0x1000>; ++ } ; ++ ps7_afi_3: ps7-afi@f800b000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf800b000 0x1000>; ++ } ; ++ ps7_can_1: ps7-can@e0009000 { ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 20>, <&clkc 37>; ++ compatible = "xlnx,ps7-can-1.00.a", "xlnx,ps7-can"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 51 4>; ++ reg = <0xe0009000 0x1000>; ++ } ; + ps7_ddrc_0: ps7-ddrc@f8006000 { + compatible = "xlnx,ps7-ddrc-1.00.a", "xlnx,ps7-ddrc"; +- reg = < 0xf8006000 0x1000 >; ++ reg = <0xf8006000 0x1000>; + xlnx,has-ecc = <0x0>; + } ; +- +- ps7_ocm_0: ps7-ocm@0xfffc0000 { +- compatible = "xlnx,ps7-ocm"; +- reg = <0xfffc0000 0x40000>; /* 256k */ +- }; +- +- uart@e0001000 { +- compatible = "xlnx,ps7-uart-1.00.a"; +- reg = <0xE0001000 0x1000>; +- interrupts = <0 50 4>; +- interrupt-parent = <&gic>; +- clock = <50000000>; +- }; +- +- slcr: slcr@f8000000 { +- compatible = "xlnx,zynq-slcr"; +- reg = <0xF8000000 0x1000>; +- clocks { +- #address-cells = <1>; +- #size-cells = <0>; +- armpll: armpll { +- #clock-cells = <0>; +- clock-output-names = "armpll"; +- clocks = <&ps_clk>; +- compatible = "xlnx,zynq-pll"; +- lockbit = <0>; +- reg = < 0x100 0x110 0x10c >; +- } ; +- ddrpll: ddrpll { +- #clock-cells = <0>; +- clock-output-names = "ddrpll"; +- clocks = <&ps_clk>; +- compatible = "xlnx,zynq-pll"; +- lockbit = <1>; +- reg = < 0x104 0x114 0x10c >; +- } ; +- iopll: iopll { +- #clock-cells = <0>; +- clock-output-names = "iopll"; +- clocks = <&ps_clk>; +- compatible = "xlnx,zynq-pll"; +- lockbit = <2>; +- reg = < 0x108 0x118 0x10c >; +- } ; +- ps_clk: ps_clk { +- #clock-cells = <0>; +- clock-frequency = <33333333>; +- clock-output-names = "ps_clk"; +- compatible = "fixed-clock"; +- } ; +- } ; +- }; +- +- timer@0xf8001000 { +- compatible = "xlnx,ps7-ttc-1.00.a"; +- reg = <0xf8001000 0x1000>; +- interrupts = <0 10 4>,<0 11 4>,<0 12 4>; +- interrupt-parent = <&gic>; +- }; +- +- swdt@f8005000 { +- device_type = "watchdog"; +- compatible = "xlnx,ps7-wdt-1.00.a"; +- reg = <0xf8005000 0x100>; +- interrupts = <0 9 4>; +- interrupt-parent = <&gic>; +- reset = <0>; +- timeout = <10>; +- }; +- +- scuwdt@f8f00620 { +- device_type = "watchdog"; +- compatible = "arm,mpcore_wdt"; +- reg = <0xf8f00620 0x20>; +- clock-frequency = <400000000>; +- reset = <1>; +- }; +- +- spi1: spi@e0007000 { +- compatible = "xlnx,ps7-spi-1.00.a"; +- reg = <0xE0007000 0x1000>; +- interrupts = <0 49 4>; +- interrupt-parent = <&gic>; +- speed-hz = <166666700>; +- bus-num = <0>; +- num-chip-select = <4>; +- }; +- +- i2c0: i2c@e0004000 { +- compatible = "xlnx,ps7-i2c-1.00.a"; +- reg = <0xE0004000 0x1000>; +- interrupts = <0 25 4>; +- interrupt-parent = <&gic>; ++ ps7_dev_cfg_0: ps7-dev-cfg@f8007000 { ++ clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3"; ++ clocks = <&clkc 12>, <&clkc 15>, <&clkc 16>, <&clkc 17>, <&clkc 18>; ++ compatible = "xlnx,ps7-dev-cfg-1.00.a"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 8 4>; ++ reg = <0xf8007000 0x100>; ++ } ; ++ ps7_dma_s: ps7-dma@f8003000 { ++ #dma-cells = <1>; ++ #dma-channels = <8>; ++ #dma-requests = <4>; ++ arm,primecell-periphid = <0x41330>; ++ clock-names = "apb_pclk"; ++ clocks = <&clkc 27>; ++ compatible = "xlnx,ps7-dma-1.00.a", "arm,primecell", "arm,pl330"; ++ interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3", ++ "dma4", "dma5", "dma6", "dma7"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 13 4>, <0 14 4>, <0 15 4>, <0 16 4>, <0 17 4>, <0 40 4>, <0 41 4>, <0 42 4>, <0 43 4>; ++ reg = <0xf8003000 0x1000>; ++ } ; ++ ps7_gpio_0: ps7-gpio@e000a000 { ++ #gpio-cells = <2>; ++ clocks = <&clkc 42>; ++ compatible = "xlnx,ps7-gpio-1.00.a"; ++ emio-gpio-width = <64>; ++ gpio-controller ; ++ gpio-mask-high = <0x0>; ++ gpio-mask-low = <0x4004>; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 20 4>; ++ reg = <0xe000a000 0x1000>; ++ } ; ++ ps7_i2c_0: ps7-i2c@e0004000 { + bus-id = <0>; +- input-clk = <133000000>; ++ clocks = <&clkc 38>; ++ compatible = "xlnx,ps7-i2c-1.00.a"; + i2c-clk = <400000>; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 25 4>; ++ reg = <0xe0004000 0x1000>; ++ xlnx,has-interrupt = <0x0>; ++ xlnx,i2c-reset = <0xffffffff>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ m24c02_eeprom@52 { ++ compatible = "at,24c02"; ++ reg = <0x52>; ++ }; + ++ } ; ++ ps7_i2c_1: ps7-i2c@e0005000 { ++ bus-id = <1>; ++ clocks = <&clkc 39>; ++ compatible = "xlnx,ps7-i2c-1.00.a"; ++ i2c-clk = <400000>; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 48 4>; ++ reg = <0xe0005000 0x1000>; ++ xlnx,has-interrupt = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + m24c02_eeprom@52 { + compatible = "at,24c02"; + reg = <0x52>; + }; +- }; + +- smc@0xe000e000 { +- compatible = "xlnx,ps7-smc"; +- reg = <0xe000e000 0x1000>; ++ } ; ++ ps7_iop_bus_config_0: ps7-iop-bus-config@e0200000 { ++ compatible = "xlnx,ps7-iop-bus-config-1.00.a"; ++ reg = <0xe0200000 0x1000>; ++ } ; ++ ps7_pl310_0: ps7-pl310@f8f02000 { ++ arm,data-latency = <3 2 2>; ++ arm,tag-latency = <2 2 2>; ++ cache-level = <2>; ++ cache-unified ; ++ compatible = "xlnx,ps7-pl310-1.00.a", "arm,pl310-cache"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 2 4>; ++ reg = <0xf8f02000 0x1000>; ++ } ; ++ ps7_ram_0: ps7-ram@0 { ++ compatible = "xlnx,ps7-ram-1.00.a", "xlnx,ps7-ocm"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 3 4>; ++ reg = <0xfffc0000 0x40000>; ++ } ; ++ ps7_scugic_0: ps7-scugic@f8f01000 { ++ #address-cells = <2>; ++ #interrupt-cells = <3>; ++ #size-cells = <1>; ++ compatible = "xlnx,ps7-scugic-1.00.a", "arm,cortex-a9-gic", "arm,gic"; ++ interrupt-controller ; ++ num_cpus = <2>; ++ num_interrupts = <96>; ++ reg = <0xf8f01000 0x1000>, <0xf8f00100 0x100>; ++ } ; ++ ps7_scutimer_0: ps7-scutimer@f8f00600 { ++ clocks = <&clkc 4>; ++ compatible = "xlnx,ps7-scutimer-1.00.a", "arm,cortex-a9-twd-timer"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <1 13 0x301>; ++ reg = <0xf8f00600 0x20>; ++ } ; ++ ps7_scuwdt_0: ps7-scuwdt@f8f00620 { ++ clocks = <&clkc 4>; ++ compatible = "xlnx,ps7-scuwdt-1.00.a"; ++ device_type = "watchdog"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <1 14 0x301>; ++ reg = <0xf8f00620 0xe0>; ++ } ; ++ ps7_slcr_0: ps7-slcr@f8000000 { ++ compatible = "xlnx,ps7-slcr-1.00.a", "xlnx,zynq-slcr"; ++ reg = <0xf8000000 0x1000>; ++ clocks { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clkc: clkc { ++ #clock-cells = <1>; ++ clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x", "cpu_3or2x", ++ "cpu_2x", "cpu_1x", "ddr2x", "ddr3x", "dci", ++ "lqspi", "smc", "pcap", "gem0", "gem1", ++ "fclk0", "fclk1", "fclk2", "fclk3", "can0", ++ "can1", "sdio0", "sdio1", "uart0", "uart1", ++ "spi0", "spi1", "dma", "usb0_aper", "usb1_aper", ++ "gem0_aper", "gem1_aper", "sdio0_aper", "sdio1_aper", "spi0_aper", ++ "spi1_aper", "can0_aper", "can1_aper", "i2c0_aper", "i2c1_aper", ++ "uart0_aper", "uart1_aper", "gpio_aper", "lqspi_aper", "smc_aper", ++ "swdt", "dbg_trc", "dbg_apb"; ++ compatible = "xlnx,ps7-clkc"; ++ fclk-enable = <0xf>; ++ ps-clk-frequency = <33333333>; ++ } ; ++ } ; ++ } ; ++ ps7_smcc_0: ps7-smcc@e000e000 { + #address-cells = <1>; + #size-cells = <1>; +- ranges; +- +- nor: nor@e2000000 { +- compatible = "cfi-flash"; ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 11>, <&clkc 44>; ++ compatible = "xlnx,ps7-smcc-1.00.a", "xlnx,ps7-smc"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 18 4>; ++ ranges ; ++ reg = <0xe000e000 0x1000>; ++ xlnx,addr25 = <0x1>; ++ xlnx,nor-chip-sel0 = <0x1>; ++ xlnx,nor-chip-sel1 = <0x0>; ++ xlnx,sram-chip-sel0 = <0x0>; ++ xlnx,sram-chip-sel1 = <0x0>; ++ ps7_nor_0: ps7-nor@e2000000 { + bank-width = <1>; +- reg = <0xE2000000 0x2000000>; /* 32MB */ ++ compatible = "xlnx,ps7-nor-1.00.a", "cfi-flash"; ++ reg = <0xe2000000 0x1000>; ++ xlnx,sram-cycle-t0 = <0xb>; ++ xlnx,sram-cycle-t1 = <0xb>; ++ xlnx,sram-cycle-t2 = <0x4>; ++ xlnx,sram-cycle-t3 = <0x4>; ++ xlnx,sram-cycle-t4 = <0x3>; ++ xlnx,sram-cycle-t5 = <0x3>; ++ xlnx,sram-cycle-t6 = <0x2>; + #address-cells = <1>; + #size-cells = <1>; + +@@ -192,31 +286,61 @@ + label = "nor-bitstream"; + reg = <0xC00000 0x400000>; + }; +- }; +- }; +- +- devcfg@f8007000 { +- compatible = "xlnx,ps7-dev-cfg-1.00.a"; +- reg = <0xf8007000 0x1000>; +- interrupts = <0 8 4>; +- interrupt-parent = <&gic>; +- }; +- +- gpio@e000a000 { +- compatible = "xlnx,ps7-gpio-1.00.a"; +- reg = <0xe000a000 0x1000>; +- interrupts = <0 20 4>; +- interrupt-parent = <&gic>; +- }; +- ps7_dma_s: ps7-dma@f8003000 { +- #dma-cells = <1>; +- #dma-channels = <8>; +- #dma-requests = <4>; +- arm,primecell-periphid = <0x41330>; +- compatible = "xlnx,ps7-dma-1.00.a", "arm,primecell", "arm,pl330"; +- interrupt-parent = <&gic>; +- interrupts = < 0 13 4 0 14 4 0 15 4 0 16 4 0 17 4 0 40 4 0 41 4 0 42 4 0 43 4 >; +- reg = < 0xf8003000 0x1000 >; ++ } ; ++ } ; ++ ps7_spi_1: ps7-spi@e0007000 { ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 26>, <&clkc 35>; ++ compatible = "xlnx,ps7-spi-1.00.a"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 49 4>; ++ num-chip-select = <4>; ++ reg = <0xe0007000 0x1000>; ++ } ; ++ ps7_ttc_0: ps7-ttc@f8001000 { ++ clocks = <&clkc 6>; ++ compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; ++ interrupt-names = "ttc0", "ttc1", "ttc2"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 10 4>, <0 11 4>, <0 12 4>; ++ reg = <0xf8001000 0x1000>; ++ } ; ++ ps7_ttc_1: ps7-ttc@f8002000 { ++ clocks = <&clkc 6>; ++ compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; ++ interrupt-names = "ttc0", "ttc1", "ttc2"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 37 4>, <0 38 4>, <0 39 4>; ++ reg = <0xf8002000 0x1000>; ++ } ; ++ ps7_uart_1: serial@e0001000 { ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 24>, <&clkc 41>; ++ compatible = "xlnx,ps7-uart-1.00.a", "xlnx,xuartps"; ++ current-speed = <115200>; ++ device_type = "serial"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 50 4>; ++ port-number = <0>; ++ reg = <0xe0001000 0x1000>; ++ xlnx,has-modem = <0x0>; ++ } ; ++ ps7_wdt_0: ps7-wdt@f8005000 { ++ clocks = <&clkc 45>; ++ compatible = "xlnx,ps7-wdt-1.00.a"; ++ device_type = "watchdog"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 9 1>; ++ reg = <0xf8005000 0x1000>; ++ reset = <0>; ++ timeout = <10>; ++ } ; ++ ps7_xadc: ps7-xadc@f8007100 { ++ clocks = <&clkc 12>; ++ compatible = "xlnx,ps7-xadc-1.00.a"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 7 4>; ++ reg = <0xf8007100 0x20>; + } ; +- }; +-}; ++ } ; ++} ; +diff --git a/arch/arm/boot/dts/zynq-zc770-xm013.dts b/arch/arm/boot/dts/zynq-zc770-xm013.dts +index 8dfae1c..7922a6e 100644 +--- a/arch/arm/boot/dts/zynq-zc770-xm013.dts ++++ b/arch/arm/boot/dts/zynq-zc770-xm013.dts +@@ -1,171 +1,174 @@ +-/dts-v1/; ++/* ++ * Device Tree Generator version: 1.1 ++ * ++ * (C) Copyright 2007-2013 Xilinx, Inc. ++ * (C) Copyright 2007-2013 Michal Simek ++ * (C) Copyright 2007-2012 PetaLogix Qld Pty Ltd ++ * ++ * Michal SIMEK ++ * ++ * CAUTION: This file is automatically generated by libgen. ++ * Version: Xilinx EDK 14.5 EDK_P.58f ++ * ++ */ + ++/dts-v1/; + / { +- model = "Xilinx Zynq ZC770 XM013 (DC4)"; +- compatible = "xlnx,zynq-zc770"; +- #address-cells = <0x1>; +- #size-cells = <0x1>; +- interrupt-parent = <0x1>; +- +- memory { +- device_type = "memory"; +- reg = <0x00000000 0x40000000>; +- }; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "xlnx,zynq-7000"; ++ model = "Xilinx Zynq"; ++ aliases { ++ ethernet0 = &ps7_ethernet_1; ++ i2c0 = &ps7_i2c_1; ++ serial0 = &ps7_uart_0; ++ spi0 = &ps7_spi_0; ++ spi1 = &ps7_qspi_0; ++ } ; + chosen { +- bootargs = "console=ttyPS0,115200 root=/dev/ram rw"; +- linux,stdout-path = "/amba@0/uart@E0000000"; +- }; +- ++ bootargs = "console=ttyPS0,115200 root=/dev/ram rw earlyprintk"; ++ linux,stdout-path = "/amba@0/serial@e0000000"; ++ } ; ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ps7_cortexa9_0: cpu@0 { ++ bus-handle = <&ps7_axi_interconnect_0>; ++ compatible = "arm,cortex-a9"; ++ d-cache-line-size = <0x20>; ++ d-cache-size = <0x8000>; ++ device_type = "cpu"; ++ i-cache-line-size = <0x20>; ++ i-cache-size = <0x8000>; ++ interrupt-handle = <&ps7_scugic_0>; ++ reg = <0x0>; ++ } ; ++ ps7_cortexa9_1: cpu@1 { ++ bus-handle = <&ps7_axi_interconnect_0>; ++ compatible = "arm,cortex-a9"; ++ d-cache-line-size = <0x20>; ++ d-cache-size = <0x8000>; ++ device_type = "cpu"; ++ i-cache-line-size = <0x20>; ++ i-cache-size = <0x8000>; ++ interrupt-handle = <&ps7_scugic_0>; ++ reg = <0x1>; ++ } ; ++ } ; + pmu { + compatible = "arm,cortex-a9-pmu"; ++ interrupt-parent = <&ps7_scugic_0>; + interrupts = <0 5 4>, <0 6 4>; +- interrupt-parent = <&gic>; +- }; +- +- amba@0 { +- compatible = "simple-bus"; +- #address-cells = <0x1>; +- #size-cells = <0x1>; +- ranges; +- +- gic: intc@f8f01000 { +- interrupt-controller; +- compatible = "arm,cortex-a9-gic"; +- #interrupt-cells = <3>; +- reg = < 0xf8f01000 0x1000 >, +- < 0xf8f00100 0x0100 >; +- }; +- +- pl310@f8f02000 { +- compatible = "arm,pl310-cache"; +- cache-unified; +- cache-level = <2>; +- reg = <0xf8f02000 0x1000>; +- arm,data-latency = <3 2 2>; +- arm,tag-latency = <2 2 2>; +- }; +- ++ reg = <0xf8891000 0x1000>, <0xf8893000 0x1000>; ++ reg-names = "cpu0", "cpu1"; ++ } ; ++ ps7_ddr_0: memory@0 { ++ device_type = "memory"; ++ reg = <0x0 0x40000000>; ++ } ; ++ ps7_axi_interconnect_0: amba@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "xlnx,ps7-axi-interconnect-1.00.a", "simple-bus"; ++ ranges ; ++ ps7_afi_0: ps7-afi@f8008000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf8008000 0x1000>; ++ } ; ++ ps7_afi_1: ps7-afi@f8009000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf8009000 0x1000>; ++ } ; ++ ps7_afi_2: ps7-afi@f800a000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf800a000 0x1000>; ++ } ; ++ ps7_afi_3: ps7-afi@f800b000 { ++ compatible = "xlnx,ps7-afi-1.00.a"; ++ reg = <0xf800b000 0x1000>; ++ } ; ++ ps7_can_1: ps7-can@e0009000 { ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 20>, <&clkc 37>; ++ compatible = "xlnx,ps7-can-1.00.a", "xlnx,ps7-can"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 51 4>; ++ reg = <0xe0009000 0x1000>; ++ } ; + ps7_ddrc_0: ps7-ddrc@f8006000 { + compatible = "xlnx,ps7-ddrc-1.00.a", "xlnx,ps7-ddrc"; +- reg = < 0xf8006000 0x1000 >; ++ reg = <0xf8006000 0x1000>; + xlnx,has-ecc = <0x0>; + } ; +- +- ps7_ocm_0: ps7-ocm@0xfffc0000 { +- compatible = "xlnx,ps7-ocm"; +- reg = <0xfffc0000 0x40000>; /* 256k */ +- }; +- +- uart@e0000000 { +- compatible = "xlnx,ps7-uart-1.00.a"; +- reg = <0xe0000000 0x1000>; +- interrupts = < 0 27 4 >; +- interrupt-parent = <&gic>; +- clock = <50000000>; +- }; +- +- slcr: slcr@f8000000 { +- compatible = "xlnx,zynq-slcr"; +- reg = <0xF8000000 0x1000>; +- clocks { ++ ps7_dev_cfg_0: ps7-dev-cfg@f8007000 { ++ clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3"; ++ clocks = <&clkc 12>, <&clkc 15>, <&clkc 16>, <&clkc 17>, <&clkc 18>; ++ compatible = "xlnx,ps7-dev-cfg-1.00.a"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 8 4>; ++ reg = <0xf8007000 0x100>; ++ } ; ++ ps7_dma_s: ps7-dma@f8003000 { ++ #dma-cells = <1>; ++ #dma-channels = <8>; ++ #dma-requests = <4>; ++ arm,primecell-periphid = <0x41330>; ++ clock-names = "apb_pclk"; ++ clocks = <&clkc 27>; ++ compatible = "xlnx,ps7-dma-1.00.a", "arm,primecell", "arm,pl330"; ++ interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3", ++ "dma4", "dma5", "dma6", "dma7"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 13 4>, <0 14 4>, <0 15 4>, <0 16 4>, <0 17 4>, <0 40 4>, <0 41 4>, <0 42 4>, <0 43 4>; ++ reg = <0xf8003000 0x1000>; ++ } ; ++ ps7_ethernet_1: ps7-ethernet@e000c000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 14>, <&clkc 31>; ++ compatible = "xlnx,ps7-ethernet-1.00.a"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 45 4>; ++ local-mac-address = [00 0a 35 00 00 00]; ++ phy-handle = <&phy0>; ++ phy-mode = "rgmii-id"; ++ reg = <0xe000c000 0x1000>; ++ xlnx,enet-reset = <0xffffffff>; ++ xlnx,eth-mode = <0x1>; ++ xlnx,has-mdio = <0x1>; ++ xlnx,ptp-enet-clock = <111111115>; ++ mdio { + #address-cells = <1>; + #size-cells = <0>; +- armpll: armpll { +- #clock-cells = <0>; +- clock-output-names = "armpll"; +- clocks = <&ps_clk>; +- compatible = "xlnx,zynq-pll"; +- lockbit = <0>; +- reg = < 0x100 0x110 0x10c >; +- } ; +- ddrpll: ddrpll { +- #clock-cells = <0>; +- clock-output-names = "ddrpll"; +- clocks = <&ps_clk>; +- compatible = "xlnx,zynq-pll"; +- lockbit = <1>; +- reg = < 0x104 0x114 0x10c >; +- } ; +- iopll: iopll { +- #clock-cells = <0>; +- clock-output-names = "iopll"; +- clocks = <&ps_clk>; +- compatible = "xlnx,zynq-pll"; +- lockbit = <2>; +- reg = < 0x108 0x118 0x10c >; +- } ; +- ps_clk: ps_clk { +- #clock-cells = <0>; +- clock-frequency = <33333333>; +- clock-output-names = "ps_clk"; +- compatible = "fixed-clock"; ++ phy0: phy@7 { ++ compatible = "vitesse,vsc8211"; ++ device_type = "ethernet-phy"; ++ reg = <7>; + } ; + } ; +- }; +- +- timer@0xf8002000 { +- compatible = "xlnx,ps7-ttc-1.00.a"; +- reg = <0xf8002000 0x1000>; +- interrupts = <0 37 4>,<0 38 4>,<0 39 4>; +- interrupt-parent = <&gic>; +- }; +- +- timer@f8f00600 { +- compatible = "arm,cortex-a9-twd-timer"; +- reg = <0xf8f00600 0x20>; +- interrupts = <1 13 0x301>; +- interrupt-parent = <&gic>; +- }; +- +- swdt@f8005000 { +- device_type = "watchdog"; +- compatible = "xlnx,ps7-wdt-1.00.a"; +- interrupts = <0 9 4>; +- interrupt-parent = <&gic>; +- reg = <0xf8005000 0x100>; +- reset = <0>; +- timeout = <10>; +- }; +- +- scuwdt@f8f00620 { +- device_type = "watchdog"; +- compatible = "arm,mpcore_wdt"; +- reg = <0xf8f00620 0x20>; +- clock-frequency = <400000000>; +- reset = <1>; +- }; +- +- spi0: spi@e0006000 { +- compatible = "xlnx,ps7-spi-1.00.a"; +- reg = <0xE0006000 0x1000>; +- interrupts = <0 26 4>; +- interrupt-parent = <&gic>; +- speed-hz = <166666700>; +- bus-num = <0>; +- num-chip-select = <4>; +- +- #address-cells = <1>; +- #size-cells = <0>; +- eeprom: at25@0 { +- at25,byte-len = <8192>; +- at25,addr-mode = <2>; +- at25,page-size = <32>; +- +- compatible = "atmel,at25"; +- reg = <2>; +- spi-max-frequency = <1000000>; +- }; +- }; +- +- i2c1: i2c@e0005000 { +- compatible = "xlnx,ps7-i2c-1.00.a"; +- reg = <0xE0005000 0x1000>; +- interrupts = < 0 48 4 >; +- interrupt-parent = <&gic>; ++ } ; ++ ps7_gpio_0: ps7-gpio@e000a000 { ++ #gpio-cells = <2>; ++ clocks = <&clkc 42>; ++ compatible = "xlnx,ps7-gpio-1.00.a"; ++ emio-gpio-width = <64>; ++ gpio-controller ; ++ gpio-mask-high = <0xdc000>; ++ gpio-mask-low = <0xfc00080>; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 20 4>; ++ reg = <0xe000a000 0x1000>; ++ } ; ++ ps7_i2c_1: ps7-i2c@e0005000 { + bus-id = <0>; +- input-clk = <133000000>; +- i2c-clk = <100000>; +- ++ clocks = <&clkc 39>; ++ compatible = "xlnx,ps7-i2c-1.00.a"; ++ i2c-clk = <400000>; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 48 4>; ++ reg = <0xe0005000 0x1000>; ++ xlnx,has-interrupt = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + osc@55 { +@@ -174,17 +177,33 @@ + factory-fout = <156250000>; + initial-fout = <148500000>; + }; +- }; + +- qspi0: spi@e000d000 { ++ } ; ++ ps7_iop_bus_config_0: ps7-iop-bus-config@e0200000 { ++ compatible = "xlnx,ps7-iop-bus-config-1.00.a"; ++ reg = <0xe0200000 0x1000>; ++ } ; ++ ps7_pl310_0: ps7-pl310@f8f02000 { ++ arm,data-latency = <3 2 2>; ++ arm,tag-latency = <2 2 2>; ++ cache-level = <2>; ++ cache-unified ; ++ compatible = "xlnx,ps7-pl310-1.00.a", "arm,pl310-cache"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 2 4>; ++ reg = <0xf8f02000 0x1000>; ++ } ; ++ ps7_qspi_0: ps7-qspi@e000d000 { ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 10>, <&clkc 43>; + compatible = "xlnx,ps7-qspi-1.00.a"; +- reg = <0xE000D000 0x1000>; +- interrupts = < 0 19 4 >; +- interrupt-parent = <&gic>; +- speed-hz = <200000000>; +- bus-num = <1>; +- num-chip-select = <1>; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 19 4>; + is-dual = <1>; ++ num-chip-select = <1>; ++ reg = <0xe000d000 0x1000>; ++ xlnx,fb-clk = <0x1>; ++ xlnx,qspi-mode = <0x2>; + #address-cells = <1>; + #size-cells = <0>; + flash@0 { +@@ -211,60 +230,128 @@ + }; + partition@qspi-bitstream { + label = "qspi-bitstream"; +- reg = <0xC00000 0x1400000>; ++ reg = <0xC00000 0x400000>; + }; + }; +- }; + +- eth@e000b000 { +- compatible = "xlnx,ps7-ethernet-1.00.a"; +- reg = <0xe000c000 0x1000>; +- interrupts = <0 45 4>; +- interrupt-parent = <&gic>; +- phy-handle = <&phy0>; +- phy-mode = "rgmii-id"; +- xlnx,ptp-enet-clock = <133000000>; +- xlnx,slcr-div0-1000Mbps = <8>; +- xlnx,slcr-div0-100Mbps = <8>; +- xlnx,slcr-div0-10Mbps = <8>; +- xlnx,slcr-div1-1000Mbps = <1>; +- xlnx,slcr-div1-100Mbps = <5>; +- xlnx,slcr-div1-10Mbps = <50>; +- #address-cells = <0x1>; +- #size-cells = <0x0>; +- mdio { ++ } ; ++ ps7_qspi_linear_0: ps7-qspi-linear@fc000000 { ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 10>, <&clkc 43>; ++ compatible = "xlnx,ps7-qspi-linear-1.00.a"; ++ reg = <0xfc000000 0x2000000>; ++ } ; ++ ps7_ram_0: ps7-ram@0 { ++ compatible = "xlnx,ps7-ram-1.00.a", "xlnx,ps7-ocm"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 3 4>; ++ reg = <0xfffc0000 0x40000>; ++ } ; ++ ps7_scugic_0: ps7-scugic@f8f01000 { ++ #address-cells = <2>; ++ #interrupt-cells = <3>; ++ #size-cells = <1>; ++ compatible = "xlnx,ps7-scugic-1.00.a", "arm,cortex-a9-gic", "arm,gic"; ++ interrupt-controller ; ++ num_cpus = <2>; ++ num_interrupts = <96>; ++ reg = <0xf8f01000 0x1000>, <0xf8f00100 0x100>; ++ } ; ++ ps7_scutimer_0: ps7-scutimer@f8f00600 { ++ clocks = <&clkc 4>; ++ compatible = "xlnx,ps7-scutimer-1.00.a", "arm,cortex-a9-twd-timer"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <1 13 0x301>; ++ reg = <0xf8f00600 0x20>; ++ } ; ++ ps7_scuwdt_0: ps7-scuwdt@f8f00620 { ++ clocks = <&clkc 4>; ++ compatible = "xlnx,ps7-scuwdt-1.00.a"; ++ device_type = "watchdog"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <1 14 0x301>; ++ reg = <0xf8f00620 0xe0>; ++ } ; ++ ps7_slcr_0: ps7-slcr@f8000000 { ++ compatible = "xlnx,ps7-slcr-1.00.a", "xlnx,zynq-slcr"; ++ reg = <0xf8000000 0x1000>; ++ clocks { + #address-cells = <1>; + #size-cells = <0>; +- phy0: phy@7 { +- compatible = "vitesse,vsc8211"; +- device_type = "ethernet-phy"; +- reg = <7>; +- }; +- }; +- }; +- +- devcfg@f8007000 { +- compatible = "xlnx,ps7-dev-cfg-1.00.a"; +- reg = <0xf8007000 0x1000>; +- interrupts = <0 8 4>; +- interrupt-parent = <&gic>; +- }; ++ clkc: clkc { ++ #clock-cells = <1>; ++ clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x", "cpu_3or2x", ++ "cpu_2x", "cpu_1x", "ddr2x", "ddr3x", "dci", ++ "lqspi", "smc", "pcap", "gem0", "gem1", ++ "fclk0", "fclk1", "fclk2", "fclk3", "can0", ++ "can1", "sdio0", "sdio1", "uart0", "uart1", ++ "spi0", "spi1", "dma", "usb0_aper", "usb1_aper", ++ "gem0_aper", "gem1_aper", "sdio0_aper", "sdio1_aper", "spi0_aper", ++ "spi1_aper", "can0_aper", "can1_aper", "i2c0_aper", "i2c1_aper", ++ "uart0_aper", "uart1_aper", "gpio_aper", "lqspi_aper", "smc_aper", ++ "swdt", "dbg_trc", "dbg_apb"; ++ compatible = "xlnx,ps7-clkc"; ++ fclk-enable = <0xf>; ++ ps-clk-frequency = <33333333>; ++ } ; ++ } ; ++ } ; ++ ps7_spi_0: ps7-spi@e0006000 { ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 25>, <&clkc 34>; ++ compatible = "xlnx,ps7-spi-1.00.a"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 26 4>; ++ num-chip-select = <4>; ++ reg = <0xe0006000 0x1000>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ eeprom: at25@0 { ++ at25,byte-len = <8192>; ++ at25,addr-mode = <2>; ++ at25,page-size = <32>; + +- gpio@e000a000 { +- compatible = "xlnx,ps7-gpio-1.00.a"; +- reg = <0xe000a000 0x1000>; +- interrupts = <0 20 4>; +- interrupt-parent = <&gic>; +- }; +- ps7_dma_s: ps7-dma@f8003000 { +- #dma-cells = <1>; +- #dma-channels = <8>; +- #dma-requests = <4>; +- arm,primecell-periphid = <0x41330>; +- compatible = "xlnx,ps7-dma-1.00.a", "arm,primecell", "arm,pl330"; +- interrupt-parent = <&gic>; +- interrupts = < 0 13 4 0 14 4 0 15 4 0 16 4 0 17 4 0 40 4 0 41 4 0 42 4 0 43 4 >; +- reg = < 0xf8003000 0x1000 >; ++ compatible = "atmel,at25"; ++ reg = <2>; ++ spi-max-frequency = <1000000>; ++ }; ++ } ; ++ ps7_ttc_0: ps7-ttc@f8001000 { ++ clocks = <&clkc 6>; ++ compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; ++ interrupt-names = "ttc0", "ttc1", "ttc2"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 10 4>, <0 11 4>, <0 12 4>; ++ reg = <0xf8001000 0x1000>; ++ } ; ++ ps7_uart_0: serial@e0000000 { ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 23>, <&clkc 40>; ++ compatible = "xlnx,ps7-uart-1.00.a", "xlnx,xuartps"; ++ current-speed = <115200>; ++ device_type = "serial"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 27 4>; ++ port-number = <0>; ++ reg = <0xe0000000 0x1000>; ++ xlnx,has-modem = <0x0>; ++ } ; ++ ps7_wdt_0: ps7-wdt@f8005000 { ++ clocks = <&clkc 45>; ++ compatible = "xlnx,ps7-wdt-1.00.a"; ++ device_type = "watchdog"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 9 1>; ++ reg = <0xf8005000 0x1000>; ++ reset = <0>; ++ timeout = <10>; ++ } ; ++ ps7_xadc: ps7-xadc@f8007100 { ++ clocks = <&clkc 12>; ++ compatible = "xlnx,ps7-xadc-1.00.a"; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 7 4>; ++ reg = <0xf8007100 0x20>; + } ; +- }; +-}; ++ } ; ++} ; +diff --git a/arch/arm/boot/dts/zynq-zed.dts b/arch/arm/boot/dts/zynq-zed.dts +index cd0bc86..911b88a 100644 +--- a/arch/arm/boot/dts/zynq-zed.dts ++++ b/arch/arm/boot/dts/zynq-zed.dts +@@ -1,86 +1,68 @@ + /* + * Device Tree Generator version: 1.1 + * +- * (C) Copyright 2007-2012 Xilinx, Inc. +- * (C) Copyright 2007-2012 Michal Simek ++ * (C) Copyright 2007-2013 Xilinx, Inc. ++ * (C) Copyright 2007-2013 Michal Simek + * (C) Copyright 2007-2012 PetaLogix Qld Pty Ltd + * + * Michal SIMEK + * +- * This program is free software; you can redistribute it and/or +- * modify it under the terms of the GNU General Public License as +- * published by the Free Software Foundation; either version 2 of +- * the License, or (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, +- * MA 02111-1307 USA +- * + * CAUTION: This file is automatically generated by libgen. +- * Version: Xilinx EDK 14.4 EDK_P.49d +- * Today is: Wednesday, the 06 of February, 2013; 10:43:23 ++ * Version: Xilinx EDK 14.5 EDK_P.58f + * +- * XPS project directory: device-tree_bsp_0 + */ + + /dts-v1/; + / { + #address-cells = <1>; + #size-cells = <1>; +- compatible = "xlnx,zynq-zc770"; ++ compatible = "xlnx,zynq-7000"; + model = "Xilinx Zynq"; + aliases { + ethernet0 = &ps7_ethernet_0; + serial0 = &ps7_uart_1; ++ spi0 = &ps7_qspi_0; + } ; + chosen { +- bootargs = "console=ttyPS0,115200 root=/dev/ram rw ip=:::::eth0:dhcp earlyprintk"; +- linux,stdout-path = "/axi@0/serial@e0001000"; ++ bootargs = "console=ttyPS0,115200 root=/dev/ram rw earlyprintk"; ++ linux,stdout-path = "/amba@0/serial@e0001000"; + } ; + cpus { + #address-cells = <1>; +- #cpus = <0x2>; + #size-cells = <0>; + ps7_cortexa9_0: cpu@0 { +- compatible = "xlnx,ps7-cortexa9-1.00.a"; ++ bus-handle = <&ps7_axi_interconnect_0>; ++ compatible = "arm,cortex-a9"; + d-cache-line-size = <0x20>; + d-cache-size = <0x8000>; + device_type = "cpu"; + i-cache-line-size = <0x20>; + i-cache-size = <0x8000>; +- model = "ps7_cortexa9,1.00.a"; +- reg = <0>; +- xlnx,cpu-1x-clk-freq-hz = <0x69f6bcb>; +- xlnx,cpu-clk-freq-hz = <0x27bc86bf>; ++ interrupt-handle = <&ps7_scugic_0>; ++ reg = <0x0>; + } ; + ps7_cortexa9_1: cpu@1 { +- compatible = "xlnx,ps7-cortexa9-1.00.a"; ++ bus-handle = <&ps7_axi_interconnect_0>; ++ compatible = "arm,cortex-a9"; + d-cache-line-size = <0x20>; + d-cache-size = <0x8000>; + device_type = "cpu"; + i-cache-line-size = <0x20>; + i-cache-size = <0x8000>; +- model = "ps7_cortexa9,1.00.a"; +- reg = <1>; +- xlnx,cpu-1x-clk-freq-hz = <0x69f6bcb>; +- xlnx,cpu-clk-freq-hz = <0x27bc86bf>; ++ interrupt-handle = <&ps7_scugic_0>; ++ reg = <0x1>; + } ; + } ; + pmu { + compatible = "arm,cortex-a9-pmu"; + interrupt-parent = <&ps7_scugic_0>; +- interrupts = < 0 5 4 0 6 4 >; +- reg = < 0xf8891000 0x1000 0xf8893000 0x1000 >; ++ interrupts = <0 5 4>, <0 6 4>; ++ reg = <0xf8891000 0x1000>, <0xf8893000 0x1000>; ++ reg-names = "cpu0", "cpu1"; + } ; + ps7_ddr_0: memory@0 { + device_type = "memory"; +- reg = < 0x0 0x20000000 >; ++ reg = <0x0 0x20000000>; + } ; + ps7_axi_interconnect_0: amba@0 { + #address-cells = <1>; +@@ -89,59 +71,60 @@ + ranges ; + ps7_afi_0: ps7-afi@f8008000 { + compatible = "xlnx,ps7-afi-1.00.a"; +- reg = < 0xf8008000 0x1000 >; ++ reg = <0xf8008000 0x1000>; + } ; + ps7_afi_1: ps7-afi@f8009000 { + compatible = "xlnx,ps7-afi-1.00.a"; +- reg = < 0xf8009000 0x1000 >; ++ reg = <0xf8009000 0x1000>; + } ; + ps7_afi_2: ps7-afi@f800a000 { + compatible = "xlnx,ps7-afi-1.00.a"; +- reg = < 0xf800a000 0x1000 >; ++ reg = <0xf800a000 0x1000>; + } ; + ps7_afi_3: ps7-afi@f800b000 { + compatible = "xlnx,ps7-afi-1.00.a"; +- reg = < 0xf800b000 0x1000 >; ++ reg = <0xf800b000 0x1000>; + } ; + ps7_ddrc_0: ps7-ddrc@f8006000 { + compatible = "xlnx,ps7-ddrc-1.00.a", "xlnx,ps7-ddrc"; +- reg = < 0xf8006000 0x1000 >; ++ reg = <0xf8006000 0x1000>; + xlnx,has-ecc = <0x0>; + } ; + ps7_dev_cfg_0: ps7-dev-cfg@f8007000 { ++ clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3"; ++ clocks = <&clkc 12>, <&clkc 15>, <&clkc 16>, <&clkc 17>, <&clkc 18>; + compatible = "xlnx,ps7-dev-cfg-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; +- interrupts = < 0 8 4 >; +- reg = < 0xf8007000 0x1000 >; ++ interrupts = <0 8 4>; ++ reg = <0xf8007000 0x100>; + } ; + ps7_dma_s: ps7-dma@f8003000 { + #dma-cells = <1>; + #dma-channels = <8>; + #dma-requests = <4>; + arm,primecell-periphid = <0x41330>; ++ clock-names = "apb_pclk"; ++ clocks = <&clkc 27>; + compatible = "xlnx,ps7-dma-1.00.a", "arm,primecell", "arm,pl330"; ++ interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3", ++ "dma4", "dma5", "dma6", "dma7"; + interrupt-parent = <&ps7_scugic_0>; +- interrupts = < 0 13 4 0 14 4 0 15 4 0 16 4 0 17 4 0 40 4 0 41 4 0 42 4 0 43 4 >; +- reg = < 0xf8003000 0x1000 >; ++ interrupts = <0 13 4>, <0 14 4>, <0 15 4>, <0 16 4>, <0 17 4>, <0 40 4>, <0 41 4>, <0 42 4>, <0 43 4>; ++ reg = <0xf8003000 0x1000>; + } ; + ps7_ethernet_0: ps7-ethernet@e000b000 { + #address-cells = <1>; + #size-cells = <0>; ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 13>, <&clkc 30>; + compatible = "xlnx,ps7-ethernet-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; +- interrupts = < 0 22 1 >; +- local-mac-address = [ 00 0a 35 00 00 00 ]; ++ interrupts = <0 22 4>; ++ local-mac-address = [00 0a 35 00 00 00]; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; +- reg = < 0xe000b000 0x1000 >; +- xlnx,enet-clk-freq-hz = <0x7735940>; ++ reg = <0xe000b000 0x1000>; + xlnx,enet-reset = <0xffffffff>; +- xlnx,enet-slcr-1000mbps-div0 = <0x8>; +- xlnx,enet-slcr-1000mbps-div1 = <0x1>; +- xlnx,enet-slcr-100mbps-div0 = <0x8>; +- xlnx,enet-slcr-100mbps-div1 = <0x5>; +- xlnx,enet-slcr-10mbps-div0 = <0x8>; +- xlnx,enet-slcr-10mbps-div1 = <0x32>; + xlnx,eth-mode = <0x1>; + xlnx,has-mdio = <0x1>; + xlnx,ptp-enet-clock = <111111115>; +@@ -157,40 +140,40 @@ + } ; + ps7_gpio_0: ps7-gpio@e000a000 { + #gpio-cells = <2>; ++ clocks = <&clkc 42>; + compatible = "xlnx,ps7-gpio-1.00.a"; + emio-gpio-width = <64>; + gpio-controller ; + gpio-mask-high = <0xc0000>; + gpio-mask-low = <0xfe81>; + interrupt-parent = <&ps7_scugic_0>; +- interrupts = < 0 20 4 >; +- reg = < 0xe000a000 0x1000 >; ++ interrupts = <0 20 4>; ++ reg = <0xe000a000 0x1000>; + } ; + ps7_iop_bus_config_0: ps7-iop-bus-config@e0200000 { + compatible = "xlnx,ps7-iop-bus-config-1.00.a"; +- reg = < 0xe0200000 0x1000 >; ++ reg = <0xe0200000 0x1000>; + } ; + ps7_pl310_0: ps7-pl310@f8f02000 { +- arm,data-latency = < 3 2 2 >; +- arm,tag-latency = < 2 2 2 >; +- cache-level = < 2 >; ++ arm,data-latency = <3 2 2>; ++ arm,tag-latency = <2 2 2>; ++ cache-level = <2>; + cache-unified ; + compatible = "xlnx,ps7-pl310-1.00.a", "arm,pl310-cache"; + interrupt-parent = <&ps7_scugic_0>; +- interrupts = < 0 2 4 >; +- reg = < 0xf8f02000 0x1000 >; ++ interrupts = <0 2 4>; ++ reg = <0xf8f02000 0x1000>; + } ; + ps7_qspi_0: ps7-qspi@e000d000 { +- bus-num = <0>; ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 10>, <&clkc 43>; + compatible = "xlnx,ps7-qspi-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; +- interrupts = < 0 19 4 >; ++ interrupts = <0 19 4>; + is-dual = <0>; + num-chip-select = <1>; +- reg = < 0xe000d000 0x1000 >; +- speed-hz = <200000000>; ++ reg = <0xe000d000 0x1000>; + xlnx,fb-clk = <0x1>; +- xlnx,qspi-clk-freq-hz = <0xbebc200>; + xlnx,qspi-mode = <0x0>; + #address-cells = <1>; + #size-cells = <0>; +@@ -221,119 +204,116 @@ + reg = <0xC00000 0x400000>; + }; + }; ++ + } ; + ps7_qspi_linear_0: ps7-qspi-linear@fc000000 { ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 10>, <&clkc 43>; + compatible = "xlnx,ps7-qspi-linear-1.00.a"; +- reg = < 0xfc000000 0x1000000 >; +- xlnx,qspi-clk-freq-hz = <0xe4e1c0>; ++ reg = <0xfc000000 0x1000000>; + } ; + ps7_ram_0: ps7-ram@0 { + compatible = "xlnx,ps7-ram-1.00.a", "xlnx,ps7-ocm"; +- reg = < 0xfffc0000 0x40000 >; ++ interrupt-parent = <&ps7_scugic_0>; ++ interrupts = <0 3 4>; ++ reg = <0xfffc0000 0x40000>; + } ; + ps7_scugic_0: ps7-scugic@f8f01000 { +- #address-cells = < 2 >; +- #interrupt-cells = < 3 >; +- #size-cells = < 1 >; ++ #address-cells = <2>; ++ #interrupt-cells = <3>; ++ #size-cells = <1>; + compatible = "xlnx,ps7-scugic-1.00.a", "arm,cortex-a9-gic", "arm,gic"; + interrupt-controller ; +- linux,phandle = < 0x1 >; +- phandle = < 0x1 >; +- reg = < 0xf8f01000 0x1000 0xf8f00100 0x100 >; ++ num_cpus = <2>; ++ num_interrupts = <96>; ++ reg = <0xf8f01000 0x1000>, <0xf8f00100 0x100>; + } ; + ps7_scutimer_0: ps7-scutimer@f8f00600 { ++ clocks = <&clkc 4>; + compatible = "xlnx,ps7-scutimer-1.00.a", "arm,cortex-a9-twd-timer"; + interrupt-parent = <&ps7_scugic_0>; +- interrupts = < 1 13 769 >; +- reg = < 0xf8f00600 0x20 >; ++ interrupts = <1 13 0x301>; ++ reg = <0xf8f00600 0x20>; + } ; + ps7_scuwdt_0: ps7-scuwdt@f8f00620 { ++ clocks = <&clkc 4>; + compatible = "xlnx,ps7-scuwdt-1.00.a"; + device_type = "watchdog"; + interrupt-parent = <&ps7_scugic_0>; +- interrupts = < 1 14 769 >; +- reg = < 0xf8f00620 0xe0 >; ++ interrupts = <1 14 0x301>; ++ reg = <0xf8f00620 0xe0>; + } ; + ps7_sd_0: ps7-sdio@e0100000 { + clock-frequency = <50000000>; +- compatible = "xlnx,ps7-sdio-1.00.a", "generic-sdhci"; ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 21>, <&clkc 32>; ++ compatible = "xlnx,ps7-sdio-1.00.a", "generic-sdhci", "arasan,sdhci"; + interrupt-parent = <&ps7_scugic_0>; +- interrupts = < 0 24 4 >; +- reg = < 0xe0100000 0x1000 >; ++ interrupts = <0 24 4>; ++ reg = <0xe0100000 0x1000>; + xlnx,has-cd = <0x1>; + xlnx,has-power = <0x0>; + xlnx,has-wp = <0x1>; +- xlnx,sdio-clk-freq-hz = <0x2faf080>; + } ; + ps7_slcr_0: ps7-slcr@f8000000 { + compatible = "xlnx,ps7-slcr-1.00.a", "xlnx,zynq-slcr"; +- reg = < 0xf8000000 0x1000 >; ++ reg = <0xf8000000 0x1000>; + clocks { + #address-cells = <1>; + #size-cells = <0>; +- armpll: armpll { +- #clock-cells = <0>; +- clock-output-names = "armpll"; +- clocks = <&ps_clk>; +- compatible = "xlnx,zynq-pll"; +- lockbit = <0>; +- reg = < 0x100 0x110 0x10c >; +- } ; +- ddrpll: ddrpll { +- #clock-cells = <0>; +- clock-output-names = "ddrpll"; +- clocks = <&ps_clk>; +- compatible = "xlnx,zynq-pll"; +- lockbit = <1>; +- reg = < 0x104 0x114 0x10c >; +- } ; +- iopll: iopll { +- #clock-cells = <0>; +- clock-output-names = "iopll"; +- clocks = <&ps_clk>; +- compatible = "xlnx,zynq-pll"; +- lockbit = <2>; +- reg = < 0x108 0x118 0x10c >; +- } ; +- ps_clk: ps_clk { +- #clock-cells = <0>; +- clock-frequency = <33333333>; +- clock-output-names = "ps_clk"; +- compatible = "fixed-clock"; ++ clkc: clkc { ++ #clock-cells = <1>; ++ clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x", "cpu_3or2x", ++ "cpu_2x", "cpu_1x", "ddr2x", "ddr3x", "dci", ++ "lqspi", "smc", "pcap", "gem0", "gem1", ++ "fclk0", "fclk1", "fclk2", "fclk3", "can0", ++ "can1", "sdio0", "sdio1", "uart0", "uart1", ++ "spi0", "spi1", "dma", "usb0_aper", "usb1_aper", ++ "gem0_aper", "gem1_aper", "sdio0_aper", "sdio1_aper", "spi0_aper", ++ "spi1_aper", "can0_aper", "can1_aper", "i2c0_aper", "i2c1_aper", ++ "uart0_aper", "uart1_aper", "gpio_aper", "lqspi_aper", "smc_aper", ++ "swdt", "dbg_trc", "dbg_apb"; ++ compatible = "xlnx,ps7-clkc"; ++ fclk-enable = <0xf>; ++ ps-clk-frequency = <33333333>; + } ; + } ; + } ; + ps7_ttc_0: ps7-ttc@f8001000 { +- compatible = "xlnx,ps7-ttc-1.00.a"; ++ clocks = <&clkc 6>; ++ compatible = "xlnx,ps7-ttc-1.00.a", "cdns,ttc"; ++ interrupt-names = "ttc0", "ttc1", "ttc2"; + interrupt-parent = <&ps7_scugic_0>; +- interrupts = < 0 10 4 0 11 4 0 12 4 >; +- reg = < 0xf8001000 0x1000 >; ++ interrupts = <0 10 4>, <0 11 4>, <0 12 4>; ++ reg = <0xf8001000 0x1000>; + } ; + ps7_uart_1: serial@e0001000 { ++ clock-names = "ref_clk", "aper_clk"; ++ clocks = <&clkc 24>, <&clkc 41>; + compatible = "xlnx,ps7-uart-1.00.a", "xlnx,xuartps"; + current-speed = <115200>; + device_type = "serial"; + interrupt-parent = <&ps7_scugic_0>; +- interrupts = < 0 50 4 >; ++ interrupts = <0 50 4>; + port-number = <0>; +- reg = < 0xe0001000 0x1000 >; ++ reg = <0xe0001000 0x1000>; + xlnx,has-modem = <0x0>; +- xlnx,uart-clk-freq-hz = <0x2faf080>; + } ; + ps7_usb_0: ps7-usb@e0002000 { ++ clocks = <&clkc 28>; + compatible = "xlnx,ps7-usb-1.00.a"; + dr_mode = "host"; + interrupt-parent = <&ps7_scugic_0>; +- interrupts = < 0 21 4 >; ++ interrupts = <0 21 4>; + phy_type = "ulpi"; +- reg = < 0xe0002000 0x1000 >; +- xlnx,usb-reset = <0xffffffff>; ++ reg = <0xe0002000 0x1000>; + } ; + ps7_xadc: ps7-xadc@f8007100 { ++ clocks = <&clkc 12>; + compatible = "xlnx,ps7-xadc-1.00.a"; + interrupt-parent = <&ps7_scugic_0>; +- interrupts = < 0 7 4 >; +- reg = < 0xf8007100 0x20 >; ++ interrupts = <0 7 4>; ++ reg = <0xf8007100 0x20>; + } ; + } ; + } ; +diff --git a/arch/arm/configs/at91sam9g45_defconfig b/arch/arm/configs/at91sam9g45_defconfig +index 8aab786..606d48f 100644 +--- a/arch/arm/configs/at91sam9g45_defconfig ++++ b/arch/arm/configs/at91sam9g45_defconfig +@@ -173,6 +173,7 @@ CONFIG_MMC=y + # CONFIG_MMC_BLOCK_BOUNCE is not set + CONFIG_SDIO_UART=m + CONFIG_MMC_ATMELMCI=y ++CONFIG_MMC_ATMELMCI_DMA=y + CONFIG_LEDS_ATMEL_PWM=y + CONFIG_LEDS_GPIO=y + CONFIG_LEDS_TRIGGER_TIMER=y +diff --git a/arch/arm/configs/xilinx_zynq_apf_defconfig b/arch/arm/configs/xilinx_zynq_apf_defconfig +new file mode 100644 +index 0000000..69d41c9 +--- /dev/null ++++ b/arch/arm/configs/xilinx_zynq_apf_defconfig +@@ -0,0 +1,2954 @@ ++# ++# Automatically generated file; DO NOT EDIT. ++# Linux/arm 3.10.0 Kernel Configuration ++# ++CONFIG_ARM=y ++CONFIG_MIGHT_HAVE_PCI=y ++CONFIG_SYS_SUPPORTS_APM_EMULATION=y ++CONFIG_HAVE_PROC_CPU=y ++CONFIG_NO_IOPORT=y ++CONFIG_STACKTRACE_SUPPORT=y ++CONFIG_LOCKDEP_SUPPORT=y ++CONFIG_TRACE_IRQFLAGS_SUPPORT=y ++CONFIG_RWSEM_GENERIC_SPINLOCK=y ++CONFIG_ARCH_HAS_CPUFREQ=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=y ++CONFIG_GENERIC_BUG=y ++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" ++CONFIG_IRQ_WORK=y ++CONFIG_BUILDTIME_EXTABLE_SORT=y ++ ++# ++# General setup ++# ++CONFIG_INIT_ENV_ARG_LIMIT=32 ++CONFIG_CROSS_COMPILE="arm-xilinx-linux-gnueabi-" ++CONFIG_LOCALVERSION="-xilinx-trd" ++CONFIG_LOCALVERSION_AUTO=y ++CONFIG_HAVE_KERNEL_GZIP=y ++CONFIG_HAVE_KERNEL_LZMA=y ++CONFIG_HAVE_KERNEL_XZ=y ++CONFIG_HAVE_KERNEL_LZO=y ++CONFIG_KERNEL_GZIP=y ++# CONFIG_KERNEL_LZMA is not set ++# CONFIG_KERNEL_XZ is not set ++# CONFIG_KERNEL_LZO is not set ++CONFIG_DEFAULT_HOSTNAME="(none)" ++CONFIG_SWAP=y ++CONFIG_SYSVIPC=y ++CONFIG_SYSVIPC_SYSCTL=y ++# CONFIG_POSIX_MQUEUE is not set ++# CONFIG_FHANDLE is not set ++# CONFIG_AUDIT is not set ++CONFIG_HAVE_GENERIC_HARDIRQS=y ++ ++# ++# IRQ subsystem ++# ++CONFIG_GENERIC_HARDIRQS=y ++CONFIG_GENERIC_IRQ_PROBE=y ++CONFIG_GENERIC_IRQ_SHOW=y ++CONFIG_HARDIRQS_SW_RESEND=y ++CONFIG_GENERIC_IRQ_CHIP=y ++CONFIG_IRQ_DOMAIN=y ++CONFIG_IRQ_DOMAIN_DEBUG=y ++CONFIG_SPARSE_IRQ=y ++CONFIG_KTIME_SCALAR=y ++CONFIG_GENERIC_CLOCKEVENTS=y ++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y ++CONFIG_ARCH_HAS_TICK_BROADCAST=y ++CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y ++ ++# ++# Timers subsystem ++# ++CONFIG_TICK_ONESHOT=y ++CONFIG_NO_HZ_COMMON=y ++# CONFIG_HZ_PERIODIC is not set ++CONFIG_NO_HZ_IDLE=y ++CONFIG_NO_HZ=y ++CONFIG_HIGH_RES_TIMERS=y ++ ++# ++# CPU/Task time and stats accounting ++# ++CONFIG_TICK_CPU_ACCOUNTING=y ++# CONFIG_IRQ_TIME_ACCOUNTING is not set ++# CONFIG_BSD_PROCESS_ACCT is not set ++# CONFIG_TASKSTATS is not set ++ ++# ++# RCU Subsystem ++# ++CONFIG_TREE_PREEMPT_RCU=y ++CONFIG_PREEMPT_RCU=y ++CONFIG_RCU_STALL_COMMON=y ++# CONFIG_RCU_USER_QS is not set ++CONFIG_RCU_FANOUT=32 ++CONFIG_RCU_FANOUT_LEAF=16 ++# CONFIG_RCU_FANOUT_EXACT is not set ++# CONFIG_RCU_FAST_NO_HZ is not set ++# CONFIG_TREE_RCU_TRACE is not set ++# CONFIG_RCU_BOOST is not set ++# CONFIG_RCU_NOCB_CPU is not set ++CONFIG_IKCONFIG=y ++CONFIG_IKCONFIG_PROC=y ++CONFIG_LOG_BUF_SHIFT=14 ++# CONFIG_CGROUPS is not set ++# CONFIG_CHECKPOINT_RESTORE is not set ++# CONFIG_NAMESPACES is not set ++CONFIG_UIDGID_CONVERTED=y ++# CONFIG_UIDGID_STRICT_TYPE_CHECKS is not set ++# CONFIG_SCHED_AUTOGROUP is not set ++CONFIG_SYSFS_DEPRECATED=y ++CONFIG_SYSFS_DEPRECATED_V2=y ++# 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 is not set ++# CONFIG_RD_LZO is not set ++CONFIG_CC_OPTIMIZE_FOR_SIZE=y ++CONFIG_SYSCTL=y ++CONFIG_ANON_INODES=y ++CONFIG_HAVE_UID16=y ++CONFIG_HOTPLUG=y ++CONFIG_EXPERT=y ++CONFIG_UID16=y ++CONFIG_SYSCTL_SYSCALL=y ++CONFIG_KALLSYMS=y ++# CONFIG_KALLSYMS_ALL is not set ++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_PCI_QUIRKS=y ++CONFIG_EMBEDDED=y ++CONFIG_HAVE_PERF_EVENTS=y ++CONFIG_PERF_USE_VMALLOC=y ++ ++# ++# Kernel Performance Events And Counters ++# ++CONFIG_PERF_EVENTS=y ++# CONFIG_DEBUG_PERF_USE_VMALLOC is not set ++CONFIG_VM_EVENT_COUNTERS=y ++CONFIG_COMPAT_BRK=y ++CONFIG_SLAB=y ++# CONFIG_SLUB is not set ++# CONFIG_SLOB is not set ++# CONFIG_PROFILING is not set ++CONFIG_HAVE_OPROFILE=y ++# CONFIG_KPROBES is not set ++# CONFIG_JUMP_LABEL is not set ++# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set ++CONFIG_HAVE_KPROBES=y ++CONFIG_HAVE_KRETPROBES=y ++CONFIG_HAVE_ARCH_TRACEHOOK=y ++CONFIG_HAVE_DMA_ATTRS=y ++CONFIG_HAVE_DMA_CONTIGUOUS=y ++CONFIG_USE_GENERIC_SMP_HELPERS=y ++CONFIG_GENERIC_SMP_IDLE_THREAD=y ++CONFIG_GENERIC_IDLE_POLL_SETUP=y ++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y ++CONFIG_HAVE_CLK=y ++CONFIG_HAVE_DMA_API_DEBUG=y ++CONFIG_HAVE_HW_BREAKPOINT=y ++CONFIG_HAVE_ARCH_JUMP_LABEL=y ++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y ++CONFIG_HAVE_ARCH_SECCOMP_FILTER=y ++CONFIG_HAVE_CONTEXT_TRACKING=y ++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y ++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y ++CONFIG_MODULES_USE_ELF_REL=y ++CONFIG_CLONE_BACKWARDS=y ++CONFIG_OLD_SIGSUSPEND3=y ++CONFIG_OLD_SIGACTION=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 is not set ++CONFIG_MODULE_UNLOAD=y ++CONFIG_MODULE_FORCE_UNLOAD=y ++CONFIG_MODVERSIONS=y ++# CONFIG_MODULE_SRCVERSION_ALL is not set ++# CONFIG_MODULE_SIG is not set ++CONFIG_STOP_MACHINE=y ++CONFIG_BLOCK=y ++CONFIG_LBDAF=y ++# CONFIG_BLK_DEV_BSG is not set ++# CONFIG_BLK_DEV_BSGLIB is not set ++# CONFIG_BLK_DEV_INTEGRITY is not set ++ ++# ++# Partition Types ++# ++# CONFIG_PARTITION_ADVANCED is not set ++CONFIG_MSDOS_PARTITION=y ++CONFIG_EFI_PARTITION=y ++ ++# ++# 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_UNINLINE_SPIN_UNLOCK=y ++CONFIG_MUTEX_SPIN_ON_OWNER=y ++# CONFIG_FREEZER is not set ++ ++# ++# System Type ++# ++CONFIG_MMU=y ++CONFIG_ARCH_MULTIPLATFORM=y ++# CONFIG_ARCH_INTEGRATOR is not set ++# CONFIG_ARCH_REALVIEW is not set ++# CONFIG_ARCH_VERSATILE is not set ++# CONFIG_ARCH_AT91 is not set ++# CONFIG_ARCH_CLPS711X 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_NETX is not set ++# CONFIG_ARCH_IOP13XX is not set ++# CONFIG_ARCH_IOP32X is not set ++# CONFIG_ARCH_IOP33X is not set ++# CONFIG_ARCH_IXP4XX is not set ++# CONFIG_ARCH_DOVE is not set ++# CONFIG_ARCH_KIRKWOOD 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_W90X900 is not set ++# CONFIG_ARCH_LPC32XX 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_S3C24XX is not set ++# CONFIG_ARCH_S3C64XX is not set ++# CONFIG_ARCH_S5P64X0 is not set ++# CONFIG_ARCH_S5PC100 is not set ++# CONFIG_ARCH_S5PV210 is not set ++# CONFIG_ARCH_EXYNOS is not set ++# CONFIG_ARCH_SHARK is not set ++# CONFIG_ARCH_U300 is not set ++# CONFIG_ARCH_DAVINCI is not set ++# CONFIG_ARCH_OMAP1 is not set ++ ++# ++# Multiple platform selection ++# ++ ++# ++# CPU Core family selection ++# ++# CONFIG_ARCH_MULTI_V6 is not set ++CONFIG_ARCH_MULTI_V7=y ++CONFIG_ARCH_MULTI_V6_V7=y ++# CONFIG_ARCH_MULTI_CPU_AUTO is not set ++# CONFIG_ARCH_MVEBU is not set ++# CONFIG_ARCH_BCM is not set ++CONFIG_GPIO_PCA953X=y ++# CONFIG_KEYBOARD_GPIO_POLLED is not set ++# CONFIG_ARCH_HIGHBANK is not set ++# CONFIG_ARCH_MXC is not set ++# CONFIG_ARCH_OMAP2PLUS is not set ++# CONFIG_ARCH_SOCFPGA is not set ++# CONFIG_PLAT_SPEAR is not set ++# CONFIG_ARCH_SUNXI is not set ++# CONFIG_ARCH_SIRF is not set ++# CONFIG_ARCH_TEGRA is not set ++# CONFIG_ARCH_U8500 is not set ++CONFIG_ARCH_VEXPRESS=y ++ ++# ++# Versatile Express platform type ++# ++CONFIG_ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA=y ++# CONFIG_ARCH_VEXPRESS_CA9X4 is not set ++CONFIG_PLAT_VERSATILE_CLCD=y ++CONFIG_PLAT_VERSATILE_SCHED_CLOCK=y ++# CONFIG_ARCH_VIRT is not set ++# CONFIG_ARCH_WM8850 is not set ++CONFIG_ARCH_ZYNQ=y ++ ++# ++# Xilinx Specific Options ++# ++CONFIG_XILINX_L1_PREFETCH=y ++CONFIG_XILINX_L2_PREFETCH=y ++CONFIG_DMA_ENGINE=y ++CONFIG_XILINX_AXIPCIE=y ++CONFIG_PLAT_VERSATILE=y ++CONFIG_ARM_TIMER_SP804=y ++ ++# ++# 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_LPAE is not set ++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set ++CONFIG_ARM_THUMB=y ++# CONFIG_ARM_THUMBEE is not set ++CONFIG_ARM_VIRT_EXT=y ++CONFIG_SWP_EMULATE=y ++# CONFIG_CPU_ICACHE_DISABLE is not set ++# CONFIG_CPU_DCACHE_DISABLE is not set ++# CONFIG_CPU_BPREDICT_DISABLE is not set ++CONFIG_OUTER_CACHE=y ++CONFIG_OUTER_CACHE_SYNC=y ++CONFIG_MIGHT_HAVE_CACHE_L2X0=y ++CONFIG_CACHE_L2X0=y ++CONFIG_CACHE_PL310=y ++CONFIG_ARM_L1_CACHE_SHIFT_6=y ++CONFIG_ARM_L1_CACHE_SHIFT=6 ++CONFIG_ARM_DMA_MEM_BUFFERABLE=y ++CONFIG_ARM_NR_BANKS=8 ++CONFIG_MULTI_IRQ_HANDLER=y ++# CONFIG_ARM_ERRATA_430973 is not set ++CONFIG_PL310_ERRATA_588369=y ++# CONFIG_ARM_ERRATA_643719 is not set ++CONFIG_ARM_ERRATA_720789=y ++CONFIG_PL310_ERRATA_727915=y ++CONFIG_PL310_ERRATA_753970=y ++CONFIG_ARM_ERRATA_754322=y ++CONFIG_ARM_ERRATA_754327=y ++CONFIG_ARM_ERRATA_764369=y ++CONFIG_PL310_ERRATA_769419=y ++CONFIG_ARM_ERRATA_775420=y ++# CONFIG_ARM_ERRATA_798181 is not set ++CONFIG_ICST=y ++ ++# ++# Bus support ++# ++CONFIG_ARM_AMBA=y ++CONFIG_PCI=y ++CONFIG_PCI_SYSCALL=y ++CONFIG_ARCH_SUPPORTS_MSI=y ++CONFIG_PCI_MSI=y ++# CONFIG_PCI_DEBUG is not set ++# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set ++# CONFIG_PCI_STUB is not set ++# CONFIG_PCI_IOV is not set ++# CONFIG_PCI_PRI is not set ++# CONFIG_PCI_PASID is not set ++# CONFIG_PCCARD is not set ++ ++# ++# Kernel Features ++# ++CONFIG_HAVE_SMP=y ++CONFIG_SMP=y ++CONFIG_SMP_ON_UP=y ++CONFIG_ARM_CPU_TOPOLOGY=y ++CONFIG_SCHED_MC=y ++CONFIG_SCHED_SMT=y ++CONFIG_HAVE_ARM_SCU=y ++# CONFIG_HAVE_ARM_ARCH_TIMER is not set ++CONFIG_HAVE_ARM_TWD=y ++# CONFIG_MCPM is not set ++CONFIG_VMSPLIT_3G=y ++# CONFIG_VMSPLIT_2G is not set ++# CONFIG_VMSPLIT_1G is not set ++CONFIG_PAGE_OFFSET=0xC0000000 ++CONFIG_NR_CPUS=4 ++CONFIG_HOTPLUG_CPU=y ++# CONFIG_ARM_PSCI is not set ++CONFIG_LOCAL_TIMERS=y ++CONFIG_ARCH_NR_GPIO=1024 ++# CONFIG_PREEMPT_NONE is not set ++# CONFIG_PREEMPT_VOLUNTARY is not set ++CONFIG_PREEMPT=y ++CONFIG_PREEMPT_COUNT=y ++CONFIG_HZ=100 ++CONFIG_SCHED_HRTICK=y ++# CONFIG_THUMB2_KERNEL is not set ++CONFIG_AEABI=y ++# CONFIG_OABI_COMPAT is not set ++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set ++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set ++CONFIG_HAVE_ARCH_PFN_VALID=y ++CONFIG_HIGHMEM=y ++# CONFIG_HIGHPTE is not set ++CONFIG_HW_PERF_EVENTS=y ++CONFIG_FLATMEM=y ++CONFIG_FLAT_NODE_MEM_MAP=y ++CONFIG_HAVE_MEMBLOCK=y ++CONFIG_MEMORY_ISOLATION=y ++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set ++CONFIG_PAGEFLAGS_EXTENDED=y ++CONFIG_SPLIT_PTLOCK_CPUS=4 ++# CONFIG_COMPACTION is not set ++CONFIG_MIGRATION=y ++# CONFIG_PHYS_ADDR_T_64BIT is not set ++CONFIG_ZONE_DMA_FLAG=0 ++CONFIG_BOUNCE=y ++# CONFIG_KSM is not set ++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 ++CONFIG_CROSS_MEMORY_ATTACH=y ++# CONFIG_CLEANCACHE is not set ++# CONFIG_FRONTSWAP is not set ++CONFIG_FORCE_MAX_ZONEORDER=11 ++CONFIG_ALIGNMENT_TRAP=y ++# CONFIG_UACCESS_WITH_MEMCPY is not set ++# CONFIG_SECCOMP is not set ++# CONFIG_CC_STACKPROTECTOR is not set ++# CONFIG_XEN is not set ++ ++# ++# Boot options ++# ++CONFIG_USE_OF=y ++CONFIG_ATAGS=y ++# CONFIG_DEPRECATED_PARAM_STRUCT is not set ++CONFIG_ZBOOT_ROM_TEXT=0x0 ++CONFIG_ZBOOT_ROM_BSS=0x0 ++# CONFIG_ARM_APPENDED_DTB is not set ++CONFIG_CMDLINE="console=ttyPS0,115200n8 root=/dev/ram rw initrd=0x00800000,16M earlyprintk mtdparts=physmap-flash.0:512K(nor-fsbl),512K(nor-u-boot),5M(nor-linux),9M(nor-user),1M(nor-scratch),-(nor-rootfs)" ++CONFIG_CMDLINE_FROM_BOOTLOADER=y ++# CONFIG_CMDLINE_EXTEND is not set ++# CONFIG_CMDLINE_FORCE is not set ++# CONFIG_CRASH_DUMP is not set ++CONFIG_AUTO_ZRELADDR=y ++ ++# ++# CPU Power Management ++# ++ ++# ++# CPU Frequency scaling ++# ++CONFIG_CPU_FREQ=y ++CONFIG_CPU_FREQ_TABLE=y ++CONFIG_CPU_FREQ_GOV_COMMON=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 ++ ++# ++# ARM CPU frequency scaling drivers ++# ++# CONFIG_ARM_BIG_LITTLE_CPUFREQ is not set ++# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set ++# CONFIG_ARM_EXYNOS4X12_CPUFREQ is not set ++# CONFIG_ARM_EXYNOS5250_CPUFREQ is not set ++# CONFIG_ARM_EXYNOS5440_CPUFREQ is not set ++# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set ++CONFIG_ARM_ZYNQ_CPUFREQ=y ++# CONFIG_CPU_IDLE is not set ++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set ++ ++# ++# 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_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y ++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set ++CONFIG_BINFMT_SCRIPT=y ++CONFIG_HAVE_AOUT=y ++# CONFIG_BINFMT_AOUT is not set ++# CONFIG_BINFMT_MISC is not set ++CONFIG_COREDUMP=y ++ ++# ++# Power management options ++# ++# CONFIG_SUSPEND is not set ++CONFIG_PM_RUNTIME=y ++CONFIG_PM=y ++# CONFIG_PM_DEBUG is not set ++# CONFIG_APM_EMULATION is not set ++CONFIG_ARCH_HAS_OPP=y ++CONFIG_PM_OPP=y ++CONFIG_PM_CLK=y ++CONFIG_ARCH_SUSPEND_POSSIBLE=y ++# CONFIG_ARM_CPU_SUSPEND is not set ++CONFIG_NET=y ++ ++# ++# Networking options ++# ++CONFIG_PACKET=y ++# CONFIG_PACKET_DIAG is not set ++CONFIG_UNIX=y ++# CONFIG_UNIX_DIAG is not set ++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_NET_KEY is not set ++CONFIG_INET=y ++CONFIG_IP_MULTICAST=y ++# CONFIG_IP_ADVANCED_ROUTER is not set ++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 is not set ++CONFIG_NET_IP_TUNNEL=m ++# CONFIG_IP_MROUTE is not set ++# CONFIG_ARPD is not set ++# CONFIG_SYN_COOKIES is not set ++# CONFIG_NET_IPVTI is not set ++# CONFIG_INET_AH is not set ++# CONFIG_INET_ESP is not set ++# CONFIG_INET_IPCOMP is not set ++# CONFIG_INET_XFRM_TUNNEL is not set ++CONFIG_INET_TUNNEL=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=y ++CONFIG_INET_TCP_DIAG=y ++# CONFIG_INET_UDP_DIAG is not set ++# CONFIG_TCP_CONG_ADVANCED is not set ++CONFIG_TCP_CONG_CUBIC=y ++CONFIG_DEFAULT_TCP_CONG="cubic" ++# CONFIG_TCP_MD5SIG is not set ++CONFIG_IPV6=m ++# CONFIG_IPV6_PRIVACY is not set ++# CONFIG_IPV6_ROUTER_PREF is not set ++# CONFIG_IPV6_OPTIMISTIC_DAD is not set ++# CONFIG_INET6_AH is not set ++# CONFIG_INET6_ESP is not set ++# CONFIG_INET6_IPCOMP is not set ++# CONFIG_IPV6_MIP6 is not set ++# CONFIG_INET6_XFRM_TUNNEL is not set ++# CONFIG_INET6_TUNNEL is not set ++CONFIG_INET6_XFRM_MODE_TRANSPORT=m ++CONFIG_INET6_XFRM_MODE_TUNNEL=m ++CONFIG_INET6_XFRM_MODE_BEET=m ++# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set ++CONFIG_IPV6_SIT=m ++# CONFIG_IPV6_SIT_6RD is not set ++CONFIG_IPV6_NDISC_NODETYPE=y ++# CONFIG_IPV6_TUNNEL is not set ++# CONFIG_IPV6_GRE is not set ++# CONFIG_IPV6_MULTIPLE_TABLES is not set ++# CONFIG_IPV6_MROUTE is not set ++# CONFIG_NETWORK_SECMARK is not set ++# CONFIG_NETWORK_PHY_TIMESTAMPING is not set ++# CONFIG_NETFILTER is not set ++# CONFIG_IP_DCCP is not set ++# CONFIG_IP_SCTP is not set ++# CONFIG_RDS is not set ++# CONFIG_TIPC is not set ++# CONFIG_ATM is not set ++# CONFIG_L2TP is not set ++# CONFIG_BRIDGE is not set ++CONFIG_HAVE_NET_DSA=y ++CONFIG_VLAN_8021Q=m ++# CONFIG_VLAN_8021Q_GVRP is not set ++# CONFIG_VLAN_8021Q_MVRP is not set ++# CONFIG_DECNET is not set ++# 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_PHONET is not set ++# CONFIG_IEEE802154 is not set ++# CONFIG_NET_SCHED is not set ++# CONFIG_DCB is not set ++# CONFIG_BATMAN_ADV is not set ++# CONFIG_OPENVSWITCH is not set ++# CONFIG_VSOCKETS is not set ++# CONFIG_NETLINK_MMAP is not set ++# CONFIG_NETLINK_DIAG is not set ++CONFIG_RPS=y ++CONFIG_RFS_ACCEL=y ++CONFIG_XPS=y ++CONFIG_BQL=y ++# CONFIG_BPF_JIT is not set ++ ++# ++# Network testing ++# ++# CONFIG_NET_PKTGEN is not set ++# CONFIG_HAMRADIO is not set ++# CONFIG_CAN is not set ++# CONFIG_IRDA is not set ++# CONFIG_BT is not set ++# CONFIG_AF_RXRPC is not set ++CONFIG_WIRELESS=y ++# CONFIG_CFG80211 is not set ++# CONFIG_LIB80211 is not set ++ ++# ++# CFG80211 needs to be enabled for MAC80211 ++# ++# CONFIG_WIMAX is not set ++# CONFIG_RFKILL is not set ++# CONFIG_NET_9P is not set ++# CONFIG_CAIF is not set ++# CONFIG_CEPH_LIB is not set ++# CONFIG_NFC is not set ++CONFIG_HAVE_BPF_JIT=y ++ ++# ++# Device Drivers ++# ++ ++# ++# Generic Driver Options ++# ++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" ++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_FW_LOADER_USER_HELPER=y ++# CONFIG_DEBUG_DRIVER is not set ++# CONFIG_DEBUG_DEVRES is not set ++# CONFIG_SYS_HYPERVISOR is not set ++# CONFIG_GENERIC_CPU_DEVICES is not set ++# CONFIG_DMA_SHARED_BUFFER is not set ++CONFIG_CMA=y ++# CONFIG_CMA_DEBUG is not set ++ ++# ++# Default contiguous memory area size: ++# ++CONFIG_CMA_SIZE_MBYTES=16 ++CONFIG_CMA_SIZE_SEL_MBYTES=y ++# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set ++# CONFIG_CMA_SIZE_SEL_MIN is not set ++# CONFIG_CMA_SIZE_SEL_MAX is not set ++CONFIG_CMA_ALIGNMENT=8 ++CONFIG_CMA_AREAS=7 ++ ++# ++# Bus devices ++# ++CONFIG_CONNECTOR=y ++CONFIG_PROC_EVENTS=y ++CONFIG_MTD=y ++# CONFIG_MTD_TESTS is not set ++# CONFIG_MTD_REDBOOT_PARTS is not set ++CONFIG_MTD_CMDLINE_PARTS=y ++# CONFIG_MTD_AFS_PARTS is not set ++CONFIG_MTD_OF_PARTS=y ++# CONFIG_MTD_AR7_PARTS is not set ++ ++# ++# User Modules And Translation Layers ++# ++CONFIG_MTD_BLKDEVS=y ++CONFIG_MTD_BLOCK=y ++# CONFIG_FTL is not set ++# CONFIG_NFTL is not set ++# CONFIG_INFTL is not set ++# CONFIG_RFD_FTL is not set ++# CONFIG_SSFDC is not set ++# CONFIG_SM_FTL is not set ++# CONFIG_MTD_OOPS is not set ++# CONFIG_MTD_SWAP is not set ++ ++# ++# RAM/ROM/Flash chip drivers ++# ++CONFIG_MTD_CFI=y ++# CONFIG_MTD_JEDECPROBE is not set ++CONFIG_MTD_GEN_PROBE=y ++# CONFIG_MTD_CFI_ADV_OPTIONS is not set ++CONFIG_MTD_MAP_BANK_WIDTH_1=y ++CONFIG_MTD_MAP_BANK_WIDTH_2=y ++CONFIG_MTD_MAP_BANK_WIDTH_4=y ++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set ++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set ++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set ++CONFIG_MTD_CFI_I1=y ++CONFIG_MTD_CFI_I2=y ++# CONFIG_MTD_CFI_I4 is not set ++# CONFIG_MTD_CFI_I8 is not set ++# CONFIG_MTD_CFI_INTELEXT is not set ++CONFIG_MTD_CFI_AMDSTD=y ++# CONFIG_MTD_CFI_STAA is not set ++CONFIG_MTD_CFI_UTIL=y ++# 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_PHYSMAP=y ++# CONFIG_MTD_PHYSMAP_COMPAT is not set ++CONFIG_MTD_PHYSMAP_OF=y ++# CONFIG_MTD_INTEL_VR_NOR is not set ++# CONFIG_MTD_PLATRAM is not set ++ ++# ++# Self-contained MTD device drivers ++# ++# CONFIG_MTD_PMC551 is not set ++# CONFIG_MTD_DATAFLASH is not set ++CONFIG_MTD_M25P80=y ++# CONFIG_M25PXX_USE_FAST_READ 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_DOCG3 is not set ++CONFIG_MTD_NAND_ECC=y ++# CONFIG_MTD_NAND_ECC_SMC is not set ++CONFIG_MTD_NAND=y ++# CONFIG_MTD_NAND_ECC_BCH is not set ++# CONFIG_MTD_SM_COMMON is not set ++# CONFIG_MTD_NAND_DENALI is not set ++# CONFIG_MTD_NAND_GPIO is not set ++CONFIG_MTD_NAND_IDS=y ++# CONFIG_MTD_NAND_RICOH is not set ++# CONFIG_MTD_NAND_DISKONCHIP is not set ++# CONFIG_MTD_NAND_DOCG4 is not set ++# CONFIG_MTD_NAND_CAFE is not set ++# CONFIG_MTD_NAND_NANDSIM is not set ++# CONFIG_MTD_NAND_PLATFORM is not set ++# CONFIG_MTD_ALAUDA is not set ++CONFIG_MTD_NAND_XILINX_PS=y ++# CONFIG_MTD_ONENAND is not set ++ ++# ++# LPDDR flash memory drivers ++# ++# CONFIG_MTD_LPDDR is not set ++# CONFIG_MTD_UBI is not set ++CONFIG_DTC=y ++CONFIG_OF=y ++ ++# ++# Device Tree and Open Firmware support ++# ++CONFIG_PROC_DEVICETREE=y ++# CONFIG_OF_SELFTEST is not set ++CONFIG_OF_FLATTREE=y ++CONFIG_OF_EARLY_FLATTREE=y ++CONFIG_OF_ADDRESS=y ++CONFIG_OF_IRQ=y ++CONFIG_OF_DEVICE=y ++CONFIG_OF_I2C=y ++CONFIG_OF_NET=y ++CONFIG_OF_MDIO=y ++CONFIG_OF_PCI=y ++CONFIG_OF_PCI_IRQ=y ++CONFIG_OF_MTD=y ++# CONFIG_PARPORT is not set ++CONFIG_BLK_DEV=y ++# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set ++# CONFIG_BLK_CPQ_CISS_DA is not set ++# CONFIG_BLK_DEV_DAC960 is not set ++# CONFIG_BLK_DEV_UMEM is not set ++# CONFIG_BLK_DEV_COW_COMMON is not set ++CONFIG_BLK_DEV_LOOP=y ++CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 ++# CONFIG_BLK_DEV_CRYPTOLOOP is not set ++# CONFIG_BLK_DEV_DRBD is not set ++# CONFIG_BLK_DEV_NBD is not set ++# CONFIG_BLK_DEV_NVME is not set ++# CONFIG_BLK_DEV_SX8 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 is not set ++# CONFIG_ATA_OVER_ETH is not set ++# CONFIG_MG_DISK is not set ++# CONFIG_VIRTIO_BLK is not set ++# CONFIG_BLK_DEV_RBD is not set ++# CONFIG_BLK_DEV_RSXX is not set ++ ++# ++# Misc devices ++# ++# CONFIG_SENSORS_LIS3LV02D is not set ++# CONFIG_AD525X_DPOT is not set ++# CONFIG_ATMEL_PWM is not set ++# CONFIG_DUMMY_IRQ is not set ++# CONFIG_PHANTOM is not set ++# CONFIG_INTEL_MID_PTI is not set ++# CONFIG_SGI_IOC4 is not set ++# CONFIG_TIFM_CORE is not set ++# CONFIG_ICS932S401 is not set ++# CONFIG_ATMEL_SSC is not set ++# CONFIG_ENCLOSURE_SERVICES is not set ++# CONFIG_HP_ILO is not set ++# CONFIG_APDS9802ALS is not set ++# CONFIG_ISL29003 is not set ++# CONFIG_ISL29020 is not set ++# CONFIG_SENSORS_TSL2550 is not set ++# CONFIG_SENSORS_BH1780 is not set ++# CONFIG_SENSORS_BH1770 is not set ++# CONFIG_SENSORS_APDS990X is not set ++# CONFIG_HMC6352 is not set ++# CONFIG_DS1682 is not set ++# CONFIG_TI_DAC7512 is not set ++# CONFIG_ARM_CHARLCD is not set ++# CONFIG_BMP085_I2C is not set ++# CONFIG_BMP085_SPI is not set ++# CONFIG_PCH_PHUB is not set ++# CONFIG_USB_SWITCH_FSA9480 is not set ++CONFIG_SI570=y ++# CONFIG_LATTICE_ECP3_CONFIG is not set ++# CONFIG_SRAM is not set ++# CONFIG_C2PORT is not set ++ ++# ++# EEPROM support ++# ++CONFIG_EEPROM_AT24=y ++CONFIG_EEPROM_AT25=y ++# CONFIG_EEPROM_LEGACY is not set ++# CONFIG_EEPROM_MAX6875 is not set ++# CONFIG_EEPROM_93CX6 is not set ++# CONFIG_EEPROM_93XX46 is not set ++# CONFIG_CB710_CORE is not set ++ ++# ++# Texas Instruments shared transport line discipline ++# ++# CONFIG_TI_ST is not set ++# CONFIG_SENSORS_LIS3_SPI is not set ++# CONFIG_SENSORS_LIS3_I2C is not set ++ ++# ++# Altera FPGA firmware download module ++# ++# CONFIG_ALTERA_STAPL is not set ++CONFIG_HAVE_IDE=y ++# CONFIG_IDE is not set ++ ++# ++# SCSI device support ++# ++CONFIG_SCSI_MOD=y ++# CONFIG_RAID_ATTRS is not set ++CONFIG_SCSI=y ++CONFIG_SCSI_DMA=y ++# CONFIG_SCSI_TGT is not set ++# CONFIG_SCSI_NETLINK is not set ++CONFIG_SCSI_PROC_FS=y ++ ++# ++# SCSI support type (disk, tape, CD-ROM) ++# ++CONFIG_BLK_DEV_SD=y ++# CONFIG_CHR_DEV_ST is not set ++# CONFIG_CHR_DEV_OSST is not set ++# CONFIG_BLK_DEV_SR is not set ++CONFIG_CHR_DEV_SG=y ++# CONFIG_CHR_DEV_SCH is not set ++CONFIG_SCSI_MULTI_LUN=y ++# CONFIG_SCSI_CONSTANTS is not set ++# CONFIG_SCSI_LOGGING is not set ++# CONFIG_SCSI_SCAN_ASYNC is not set ++ ++# ++# SCSI Transports ++# ++# CONFIG_SCSI_SPI_ATTRS is not set ++# CONFIG_SCSI_FC_ATTRS is not set ++# CONFIG_SCSI_ISCSI_ATTRS is not set ++# CONFIG_SCSI_SAS_ATTRS is not set ++# CONFIG_SCSI_SAS_LIBSAS is not set ++# CONFIG_SCSI_SRP_ATTRS is not set ++CONFIG_SCSI_LOWLEVEL=y ++# CONFIG_ISCSI_TCP is not set ++# CONFIG_ISCSI_BOOT_SYSFS is not set ++# CONFIG_SCSI_CXGB3_ISCSI is not set ++# CONFIG_SCSI_CXGB4_ISCSI is not set ++# CONFIG_SCSI_BNX2_ISCSI is not set ++# CONFIG_SCSI_BNX2X_FCOE is not set ++# CONFIG_BE2ISCSI is not set ++# CONFIG_BLK_DEV_3W_XXXX_RAID is not set ++# CONFIG_SCSI_HPSA is not set ++# CONFIG_SCSI_3W_9XXX is not set ++# CONFIG_SCSI_3W_SAS is not set ++# CONFIG_SCSI_ACARD is not set ++# CONFIG_SCSI_AACRAID is not set ++# CONFIG_SCSI_AIC7XXX is not set ++# CONFIG_SCSI_AIC7XXX_OLD is not set ++# CONFIG_SCSI_AIC79XX is not set ++# CONFIG_SCSI_AIC94XX is not set ++# CONFIG_SCSI_MVSAS is not set ++# CONFIG_SCSI_MVUMI is not set ++# CONFIG_SCSI_ARCMSR is not set ++# CONFIG_MEGARAID_NEWGEN is not set ++# CONFIG_MEGARAID_LEGACY is not set ++# CONFIG_MEGARAID_SAS is not set ++# CONFIG_SCSI_MPT2SAS is not set ++# CONFIG_SCSI_MPT3SAS is not set ++# CONFIG_SCSI_UFSHCD is not set ++# CONFIG_SCSI_HPTIOP is not set ++# CONFIG_LIBFC is not set ++# CONFIG_LIBFCOE is not set ++# CONFIG_FCOE is not set ++# CONFIG_SCSI_DMX3191D is not set ++# CONFIG_SCSI_FUTURE_DOMAIN is not set ++# CONFIG_SCSI_IPS is not set ++# CONFIG_SCSI_INITIO is not set ++# CONFIG_SCSI_INIA100 is not set ++# CONFIG_SCSI_STEX is not set ++# CONFIG_SCSI_SYM53C8XX_2 is not set ++# CONFIG_SCSI_QLOGIC_1280 is not set ++# CONFIG_SCSI_QLA_FC is not set ++# CONFIG_SCSI_QLA_ISCSI is not set ++# CONFIG_SCSI_LPFC is not set ++# CONFIG_SCSI_DC395x is not set ++# CONFIG_SCSI_DC390T is not set ++# CONFIG_SCSI_NSP32 is not set ++# CONFIG_SCSI_DEBUG is not set ++# CONFIG_SCSI_PMCRAID is not set ++# CONFIG_SCSI_PM8001 is not set ++# CONFIG_SCSI_SRP is not set ++# CONFIG_SCSI_BFA_FC is not set ++# CONFIG_SCSI_VIRTIO is not set ++# CONFIG_SCSI_CHELSIO_FCOE is not set ++# CONFIG_SCSI_DH is not set ++# CONFIG_SCSI_OSD_INITIATOR is not set ++CONFIG_HAVE_PATA_PLATFORM=y ++# CONFIG_ATA is not set ++# CONFIG_MD is not set ++# CONFIG_TARGET_CORE is not set ++# CONFIG_FUSION is not set ++ ++# ++# IEEE 1394 (FireWire) support ++# ++# CONFIG_FIREWIRE is not set ++# CONFIG_FIREWIRE_NOSY is not set ++# CONFIG_I2O is not set ++CONFIG_NETDEVICES=y ++CONFIG_NET_CORE=y ++# CONFIG_BONDING is not set ++# CONFIG_DUMMY is not set ++# CONFIG_EQUALIZER is not set ++# CONFIG_NET_FC is not set ++CONFIG_MII=y ++# CONFIG_NET_TEAM is not set ++# CONFIG_MACVLAN is not set ++# CONFIG_VXLAN is not set ++# CONFIG_NETCONSOLE is not set ++# CONFIG_NETPOLL is not set ++# CONFIG_NET_POLL_CONTROLLER is not set ++# CONFIG_TUN is not set ++# CONFIG_VETH is not set ++# CONFIG_VIRTIO_NET is not set ++# CONFIG_ARCNET is not set ++ ++# ++# CAIF transport drivers ++# ++ ++# ++# Distributed Switch Architecture drivers ++# ++# CONFIG_NET_DSA_MV88E6XXX is not set ++# CONFIG_NET_DSA_MV88E6060 is not set ++# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set ++# CONFIG_NET_DSA_MV88E6131 is not set ++# CONFIG_NET_DSA_MV88E6123_61_65 is not set ++CONFIG_ETHERNET=y ++# CONFIG_NET_VENDOR_3COM is not set ++# CONFIG_NET_VENDOR_ADAPTEC is not set ++# CONFIG_NET_VENDOR_ALTEON is not set ++# CONFIG_NET_VENDOR_AMD is not set ++# CONFIG_NET_VENDOR_ATHEROS is not set ++CONFIG_NET_CADENCE=y ++# CONFIG_ARM_AT91_ETHER is not set ++# CONFIG_MACB is not set ++CONFIG_NET_VENDOR_BROADCOM=y ++# CONFIG_B44 is not set ++# CONFIG_BNX2 is not set ++# CONFIG_CNIC is not set ++CONFIG_TIGON3=y ++# CONFIG_BNX2X is not set ++# CONFIG_NET_VENDOR_BROCADE is not set ++# CONFIG_NET_CALXEDA_XGMAC is not set ++# CONFIG_NET_VENDOR_CHELSIO is not set ++# CONFIG_NET_VENDOR_CIRRUS is not set ++# CONFIG_NET_VENDOR_CISCO is not set ++# CONFIG_DM9000 is not set ++# CONFIG_DNET is not set ++# CONFIG_NET_VENDOR_DEC is not set ++# CONFIG_NET_VENDOR_DLINK is not set ++# CONFIG_NET_VENDOR_EMULEX is not set ++# CONFIG_NET_VENDOR_EXAR is not set ++# CONFIG_NET_VENDOR_FARADAY is not set ++# CONFIG_NET_VENDOR_HP is not set ++CONFIG_NET_VENDOR_INTEL=y ++# CONFIG_E100 is not set ++# CONFIG_E1000 is not set ++CONFIG_E1000E=y ++# CONFIG_IGB is not set ++# CONFIG_IGBVF is not set ++# CONFIG_IXGB is not set ++# CONFIG_IXGBE is not set ++# CONFIG_IXGBEVF is not set ++CONFIG_NET_VENDOR_I825XX=y ++# CONFIG_IP1000 is not set ++# CONFIG_JME is not set ++# CONFIG_NET_VENDOR_MARVELL is not set ++# CONFIG_NET_VENDOR_MELLANOX is not set ++# CONFIG_NET_VENDOR_MICREL is not set ++# CONFIG_NET_VENDOR_MICROCHIP is not set ++# CONFIG_NET_VENDOR_MYRI is not set ++# CONFIG_FEALNX is not set ++# CONFIG_NET_VENDOR_NATSEMI is not set ++# CONFIG_NET_VENDOR_NVIDIA is not set ++# CONFIG_NET_VENDOR_OKI is not set ++# CONFIG_ETHOC is not set ++# CONFIG_NET_PACKET_ENGINE is not set ++# CONFIG_NET_VENDOR_QLOGIC is not set ++CONFIG_NET_VENDOR_REALTEK=y ++# CONFIG_8139CP is not set ++# CONFIG_8139TOO is not set ++CONFIG_R8169=y ++# CONFIG_NET_VENDOR_RDC is not set ++# CONFIG_NET_VENDOR_SEEQ is not set ++# CONFIG_NET_VENDOR_SILAN is not set ++# CONFIG_NET_VENDOR_SIS is not set ++# CONFIG_SFC is not set ++# CONFIG_NET_VENDOR_SMSC is not set ++# CONFIG_NET_VENDOR_STMICRO is not set ++# CONFIG_NET_VENDOR_SUN is not set ++# CONFIG_NET_VENDOR_TEHUTI is not set ++# CONFIG_NET_VENDOR_TI is not set ++# CONFIG_NET_VENDOR_VIA is not set ++# CONFIG_NET_VENDOR_WIZNET is not set ++CONFIG_NET_VENDOR_XILINX=y ++CONFIG_XILINX_EMACLITE=y ++CONFIG_XILINX_AXI_EMAC=y ++CONFIG_XILINX_PS_EMAC=y ++# CONFIG_XILINX_PS_EMAC_HWTSTAMP is not set ++# CONFIG_FDDI is not set ++# CONFIG_HIPPI is not set ++CONFIG_PHYLIB=y ++ ++# ++# MII PHY device drivers ++# ++# CONFIG_AT803X_PHY is not set ++# CONFIG_AMD_PHY is not set ++CONFIG_MARVELL_PHY=y ++# 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=y ++# CONFIG_SMSC_PHY is not set ++# CONFIG_BROADCOM_PHY is not set ++# CONFIG_BCM87XX_PHY is not set ++# 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 is not set ++# CONFIG_FIXED_PHY is not set ++CONFIG_MDIO_BITBANG=y ++# CONFIG_MDIO_GPIO is not set ++# CONFIG_MDIO_BUS_MUX_GPIO is not set ++# CONFIG_MDIO_BUS_MUX_MMIOREG is not set ++# CONFIG_MICREL_KS8995MA is not set ++# CONFIG_PPP is not set ++# CONFIG_SLIP is not set ++ ++# ++# USB Network Adapters ++# ++# CONFIG_USB_CATC is not set ++# CONFIG_USB_KAWETH is not set ++# CONFIG_USB_PEGASUS is not set ++# CONFIG_USB_RTL8150 is not set ++# CONFIG_USB_RTL8152 is not set ++# CONFIG_USB_USBNET is not set ++# CONFIG_USB_IPHETH is not set ++CONFIG_WLAN=y ++# CONFIG_ATMEL is not set ++# CONFIG_PRISM54 is not set ++# CONFIG_USB_ZD1201 is not set ++# CONFIG_HOSTAP is not set ++# CONFIG_WL_TI is not set ++ ++# ++# Enable WiMAX (Networking options) to see the WiMAX drivers ++# ++# CONFIG_WAN is not set ++# CONFIG_VMXNET3 is not set ++# CONFIG_ISDN is not set ++ ++# ++# Input device support ++# ++CONFIG_INPUT=y ++# CONFIG_INPUT_FF_MEMLESS is not set ++# CONFIG_INPUT_POLLDEV is not set ++CONFIG_INPUT_SPARSEKMAP=y ++# CONFIG_INPUT_MATRIXKMAP 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_ADP5589 is not set ++CONFIG_KEYBOARD_ATKBD=y ++# CONFIG_KEYBOARD_QT1070 is not set ++# CONFIG_KEYBOARD_QT2160 is not set ++# CONFIG_KEYBOARD_LKKBD is not set ++# CONFIG_KEYBOARD_GPIO is not set ++# CONFIG_KEYBOARD_TCA6416 is not set ++# CONFIG_KEYBOARD_TCA8418 is not set ++# CONFIG_KEYBOARD_MATRIX is not set ++# CONFIG_KEYBOARD_LM8333 is not set ++# CONFIG_KEYBOARD_MAX7359 is not set ++# CONFIG_KEYBOARD_MCS is not set ++# CONFIG_KEYBOARD_MPR121 is not set ++# CONFIG_KEYBOARD_NEWTON is not set ++# CONFIG_KEYBOARD_OPENCORES is not set ++# CONFIG_KEYBOARD_SAMSUNG is not set ++# CONFIG_KEYBOARD_STOWAWAY is not set ++# CONFIG_KEYBOARD_SUNKBD 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_CYPRESS=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_CYAPA is not set ++# CONFIG_MOUSE_VSXXXAA is not set ++# CONFIG_MOUSE_GPIO is not set ++# CONFIG_MOUSE_SYNAPTICS_I2C is not set ++# CONFIG_MOUSE_SYNAPTICS_USB is not set ++# CONFIG_INPUT_JOYSTICK is not set ++# CONFIG_INPUT_TABLET is not set ++# CONFIG_INPUT_TOUCHSCREEN is not set ++# CONFIG_INPUT_MISC is not set ++ ++# ++# Hardware I/O ports ++# ++CONFIG_SERIO=y ++CONFIG_SERIO_SERPORT=y ++# CONFIG_SERIO_AMBAKMI is not set ++# CONFIG_SERIO_PCIPS2 is not set ++CONFIG_SERIO_LIBPS2=y ++# CONFIG_SERIO_RAW is not set ++# CONFIG_SERIO_ALTERA_PS2 is not set ++# CONFIG_SERIO_PS2MULT is not set ++# CONFIG_SERIO_ARC_PS2 is not set ++# CONFIG_SERIO_APBPS2 is not set ++# CONFIG_GAMEPORT is not set ++ ++# ++# Character devices ++# ++CONFIG_TTY=y ++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_NOZOMI is not set ++# CONFIG_N_GSM is not set ++# CONFIG_TRACE_SINK is not set ++# CONFIG_DEVKMEM is not set ++ ++# ++# Serial drivers ++# ++# CONFIG_SERIAL_8250 is not set ++ ++# ++# Non-8250 serial port support ++# ++# CONFIG_SERIAL_AMBA_PL010 is not set ++# CONFIG_SERIAL_AMBA_PL011 is not set ++# CONFIG_SERIAL_MAX3100 is not set ++# CONFIG_SERIAL_MAX310X is not set ++# CONFIG_SERIAL_MFD_HSU is not set ++# CONFIG_SERIAL_UARTLITE is not set ++CONFIG_SERIAL_CORE=y ++CONFIG_SERIAL_CORE_CONSOLE=y ++# CONFIG_SERIAL_JSM is not set ++# CONFIG_SERIAL_SCCNXP is not set ++# CONFIG_SERIAL_TIMBERDALE is not set ++# CONFIG_SERIAL_ALTERA_JTAGUART is not set ++# CONFIG_SERIAL_ALTERA_UART is not set ++# CONFIG_SERIAL_IFX6X60 is not set ++# CONFIG_SERIAL_PCH_UART is not set ++CONFIG_SERIAL_XILINX_PS_UART=y ++CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y ++# CONFIG_SERIAL_ARC is not set ++# CONFIG_SERIAL_RP2 is not set ++# CONFIG_TTY_PRINTK is not set ++# CONFIG_HVC_DCC is not set ++# CONFIG_VIRTIO_CONSOLE is not set ++# CONFIG_IPMI_HANDLER is not set ++# CONFIG_HW_RANDOM is not set ++CONFIG_XILINX_DEVCFG=y ++# CONFIG_R3964 is not set ++# CONFIG_APPLICOM is not set ++# CONFIG_RAW_DRIVER is not set ++# CONFIG_TCG_TPM is not set ++CONFIG_DEVPORT=y ++CONFIG_I2C=y ++CONFIG_I2C_BOARDINFO=y ++CONFIG_I2C_COMPAT=y ++CONFIG_I2C_CHARDEV=y ++CONFIG_I2C_MUX=y ++ ++# ++# Multiplexer I2C Chip support ++# ++# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set ++# CONFIG_I2C_MUX_GPIO is not set ++# CONFIG_I2C_MUX_PCA9541 is not set ++CONFIG_I2C_MUX_PCA954x=y ++CONFIG_I2C_HELPER_AUTO=y ++CONFIG_I2C_ALGOBIT=m ++ ++# ++# I2C Hardware Bus support ++# ++ ++# ++# PC SMBus host controller drivers ++# ++# CONFIG_I2C_ALI1535 is not set ++# CONFIG_I2C_ALI1563 is not set ++# CONFIG_I2C_ALI15X3 is not set ++# CONFIG_I2C_AMD756 is not set ++# CONFIG_I2C_AMD8111 is not set ++# CONFIG_I2C_I801 is not set ++# CONFIG_I2C_ISCH is not set ++# CONFIG_I2C_PIIX4 is not set ++# CONFIG_I2C_NFORCE2 is not set ++# CONFIG_I2C_SIS5595 is not set ++# CONFIG_I2C_SIS630 is not set ++# CONFIG_I2C_SIS96X is not set ++# CONFIG_I2C_VIA is not set ++# CONFIG_I2C_VIAPRO is not set ++ ++# ++# I2C system bus drivers (mostly embedded / system-on-chip) ++# ++# CONFIG_I2C_CBUS_GPIO is not set ++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set ++# CONFIG_I2C_DESIGNWARE_PCI is not set ++# CONFIG_I2C_EG20T is not set ++# CONFIG_I2C_GPIO is not set ++# CONFIG_I2C_INTEL_MID is not set ++# CONFIG_I2C_NOMADIK is not set ++# CONFIG_I2C_OCORES is not set ++# CONFIG_I2C_PCA_PLATFORM is not set ++# CONFIG_I2C_PXA_PCI is not set ++# CONFIG_I2C_SIMTEC is not set ++# CONFIG_I2C_VERSATILE is not set ++CONFIG_I2C_XILINX_PS=y ++# CONFIG_I2C_XILINX is not set ++ ++# ++# External I2C/SMBus adapter drivers ++# ++# CONFIG_I2C_DIOLAN_U2C is not set ++# 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_FSL_SPI is not set ++# CONFIG_SPI_OC_TINY is not set ++# CONFIG_SPI_PL022 is not set ++# CONFIG_SPI_PXA2XX is not set ++# CONFIG_SPI_PXA2XX_PCI is not set ++# CONFIG_SPI_SC18IS602 is not set ++# CONFIG_SPI_TOPCLIFF_PCH is not set ++# CONFIG_SPI_XCOMM is not set ++# CONFIG_SPI_XILINX is not set ++CONFIG_SPI_XILINX_PS_QSPI=y ++# CONFIG_SPI_XILINX_PS_QSPI_DUAL_STACKED is not set ++CONFIG_SPI_XILINX_PS_SPI=y ++# CONFIG_SPI_DESIGNWARE is not set ++ ++# ++# SPI Protocol Masters ++# ++# CONFIG_SPI_SPIDEV is not set ++# CONFIG_SPI_TLE62X0 is not set ++ ++# ++# Qualcomm MSM SSBI bus support ++# ++# CONFIG_SSBI is not set ++# CONFIG_HSI is not set ++ ++# ++# PPS support ++# ++CONFIG_PPS=y ++# CONFIG_PPS_DEBUG is not set ++ ++# ++# PPS clients support ++# ++# CONFIG_PPS_CLIENT_KTIMER is not set ++# CONFIG_PPS_CLIENT_LDISC is not set ++# CONFIG_PPS_CLIENT_GPIO is not set ++ ++# ++# PPS generators support ++# ++ ++# ++# PTP clock support ++# ++CONFIG_PTP_1588_CLOCK=y ++ ++# ++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. ++# ++# CONFIG_PTP_1588_CLOCK_PCH is not set ++CONFIG_ARCH_REQUIRE_GPIOLIB=y ++CONFIG_GPIO_DEVRES=y ++CONFIG_GPIOLIB=y ++CONFIG_OF_GPIO=y ++# CONFIG_DEBUG_GPIO is not set ++CONFIG_GPIO_SYSFS=y ++ ++# ++# Memory mapped GPIO drivers: ++# ++# CONFIG_GPIO_GENERIC_PLATFORM is not set ++# CONFIG_GPIO_EM is not set ++# CONFIG_GPIO_PL061 is not set ++# CONFIG_GPIO_RCAR is not set ++# CONFIG_GPIO_TS5500 is not set ++CONFIG_GPIO_XILINX=y ++CONFIG_GPIO_XILINX_PS=y ++# CONFIG_GPIO_VX855 is not set ++# CONFIG_GPIO_GRGPIO is not set ++ ++# ++# I2C GPIO expanders: ++# ++# CONFIG_GPIO_MAX7300 is not set ++# CONFIG_GPIO_MAX732X is not set ++# CONFIG_GPIO_PCA953X_IRQ is not set ++# CONFIG_GPIO_PCF857X is not set ++# CONFIG_GPIO_SX150X is not set ++# CONFIG_GPIO_ADP5588 is not set ++# CONFIG_GPIO_ADNP is not set ++ ++# ++# PCI GPIO expanders: ++# ++# CONFIG_GPIO_BT8XX is not set ++# CONFIG_GPIO_AMD8111 is not set ++# CONFIG_GPIO_ML_IOH is not set ++# CONFIG_GPIO_RDC321X is not set ++ ++# ++# 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: ++# ++ ++# ++# USB GPIO expanders: ++# ++# CONFIG_W1 is not set ++CONFIG_POWER_SUPPLY=y ++# CONFIG_POWER_SUPPLY_DEBUG is not set ++# CONFIG_PDA_POWER is not set ++# CONFIG_TEST_POWER is not set ++# CONFIG_BATTERY_DS2780 is not set ++# CONFIG_BATTERY_DS2781 is not set ++# CONFIG_BATTERY_DS2782 is not set ++# CONFIG_BATTERY_SBS is not set ++# CONFIG_BATTERY_BQ27x00 is not set ++# CONFIG_BATTERY_MAX17040 is not set ++# CONFIG_BATTERY_MAX17042 is not set ++# CONFIG_CHARGER_ISP1704 is not set ++# CONFIG_CHARGER_MAX8903 is not set ++# CONFIG_CHARGER_LP8727 is not set ++# CONFIG_CHARGER_GPIO is not set ++# CONFIG_CHARGER_BQ2415X is not set ++# CONFIG_CHARGER_SMB347 is not set ++# CONFIG_BATTERY_GOLDFISH is not set ++CONFIG_POWER_RESET=y ++# CONFIG_POWER_RESET_GPIO is not set ++# CONFIG_POWER_RESET_RESTART is not set ++CONFIG_POWER_RESET_VEXPRESS=y ++# CONFIG_POWER_AVS is not set ++CONFIG_HWMON=y ++# CONFIG_HWMON_VID is not set ++# CONFIG_HWMON_DEBUG_CHIP is not set ++ ++# ++# Native drivers ++# ++# CONFIG_SENSORS_AD7314 is not set ++# 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_ADT7310 is not set ++# CONFIG_SENSORS_ADT7410 is not set ++# CONFIG_SENSORS_ADT7411 is not set ++# CONFIG_SENSORS_ADT7462 is not set ++# CONFIG_SENSORS_ADT7470 is not set ++# CONFIG_SENSORS_ADT7475 is not set ++# CONFIG_SENSORS_ASC7621 is not set ++# CONFIG_SENSORS_ATXP1 is not set ++# CONFIG_SENSORS_DS620 is not set ++# CONFIG_SENSORS_DS1621 is not set ++# CONFIG_SENSORS_I5K_AMB 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 is not set ++# CONFIG_SENSORS_HIH6130 is not set ++# CONFIG_SENSORS_IT87 is not set ++# CONFIG_SENSORS_JC42 is not set ++# 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_LM95234 is not set ++# CONFIG_SENSORS_LM95241 is not set ++# CONFIG_SENSORS_LM95245 is not set ++# CONFIG_SENSORS_MAX1111 is not set ++# CONFIG_SENSORS_MAX16065 is not set ++# CONFIG_SENSORS_MAX1619 is not set ++# CONFIG_SENSORS_MAX1668 is not set ++# CONFIG_SENSORS_MAX197 is not set ++# CONFIG_SENSORS_MAX6639 is not set ++# CONFIG_SENSORS_MAX6642 is not set ++# CONFIG_SENSORS_MAX6650 is not set ++# CONFIG_SENSORS_MAX6697 is not set ++# CONFIG_SENSORS_MCP3021 is not set ++# CONFIG_SENSORS_NCT6775 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_SIS5595 is not set ++# CONFIG_SENSORS_SMM665 is not set ++# CONFIG_SENSORS_DME1737 is not set ++# CONFIG_SENSORS_EMC1403 is not set ++# CONFIG_SENSORS_EMC2103 is not set ++# CONFIG_SENSORS_EMC6W201 is not set ++# CONFIG_SENSORS_SMSC47M1 is not set ++# CONFIG_SENSORS_SMSC47M192 is not set ++# CONFIG_SENSORS_SMSC47B397 is not set ++# CONFIG_SENSORS_SCH56XX_COMMON is not set ++# CONFIG_SENSORS_SCH5627 is not set ++# CONFIG_SENSORS_SCH5636 is not set ++# CONFIG_SENSORS_ADS1015 is not set ++# CONFIG_SENSORS_ADS7828 is not set ++# CONFIG_SENSORS_ADS7871 is not set ++# CONFIG_SENSORS_AMC6821 is not set ++# CONFIG_SENSORS_INA209 is not set ++# CONFIG_SENSORS_INA2XX is not set ++# CONFIG_SENSORS_THMC50 is not set ++# CONFIG_SENSORS_TMP102 is not set ++# CONFIG_SENSORS_TMP401 is not set ++# CONFIG_SENSORS_TMP421 is not set ++# CONFIG_SENSORS_VEXPRESS is not set ++# CONFIG_SENSORS_VIA686A is not set ++# CONFIG_SENSORS_VT1211 is not set ++# CONFIG_SENSORS_VT8231 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_SENSORS_XADCPS=y ++# CONFIG_THERMAL is not set ++CONFIG_WATCHDOG=y ++CONFIG_WATCHDOG_CORE=y ++# CONFIG_WATCHDOG_NOWAYOUT is not set ++ ++# ++# Watchdog Device Drivers ++# ++# CONFIG_SOFT_WATCHDOG is not set ++# CONFIG_ARM_SP805_WATCHDOG is not set ++# CONFIG_DW_WATCHDOG is not set ++CONFIG_MPCORE_WATCHDOG=y ++CONFIG_XILINX_PS_WATCHDOG=y ++# CONFIG_MAX63XX_WATCHDOG is not set ++# CONFIG_ALIM7101_WDT is not set ++# CONFIG_I6300ESB_WDT is not set ++# CONFIG_XILINX_WATCHDOG is not set ++ ++# ++# PCI-based Watchdog Cards ++# ++# CONFIG_PCIPCWATCHDOG is not set ++# CONFIG_WDTPCI is not set ++ ++# ++# USB-based Watchdog Cards ++# ++# CONFIG_USBPCWATCHDOG is not set ++CONFIG_SSB_POSSIBLE=y ++ ++# ++# Sonics Silicon Backplane ++# ++# CONFIG_SSB is not set ++CONFIG_BCMA_POSSIBLE=y ++ ++# ++# Broadcom specific AMBA ++# ++# CONFIG_BCMA is not set ++ ++# ++# Multifunction device drivers ++# ++# CONFIG_MFD_CORE is not set ++# CONFIG_MFD_AS3711 is not set ++# CONFIG_PMIC_ADP5520 is not set ++# CONFIG_MFD_AAT2870_CORE is not set ++# CONFIG_MFD_CROS_EC is not set ++# CONFIG_MFD_ASIC3 is not set ++# CONFIG_PMIC_DA903X is not set ++# CONFIG_MFD_DA9052_SPI is not set ++# CONFIG_MFD_DA9052_I2C is not set ++# CONFIG_MFD_DA9055 is not set ++# CONFIG_MFD_MC13XXX_SPI is not set ++# CONFIG_MFD_MC13XXX_I2C is not set ++# CONFIG_HTC_EGPIO is not set ++# CONFIG_HTC_PASIC3 is not set ++# CONFIG_HTC_I2CPLD is not set ++# CONFIG_LPC_ICH is not set ++# CONFIG_LPC_SCH is not set ++# CONFIG_MFD_JANZ_CMODIO is not set ++# CONFIG_MFD_88PM800 is not set ++# CONFIG_MFD_88PM805 is not set ++# CONFIG_MFD_88PM860X is not set ++# CONFIG_MFD_MAX77686 is not set ++# CONFIG_MFD_MAX77693 is not set ++# CONFIG_MFD_MAX8907 is not set ++# CONFIG_MFD_MAX8925 is not set ++# CONFIG_MFD_MAX8997 is not set ++# CONFIG_MFD_MAX8998 is not set ++# CONFIG_EZX_PCAP is not set ++# CONFIG_MFD_VIPERBOARD is not set ++# CONFIG_MFD_RETU is not set ++# CONFIG_MFD_PCF50633 is not set ++# CONFIG_MFD_RDC321X is not set ++# CONFIG_MFD_RTSX_PCI is not set ++# CONFIG_MFD_RC5T583 is not set ++# CONFIG_MFD_SEC_CORE is not set ++# CONFIG_MFD_SI476X_CORE is not set ++# CONFIG_MFD_SM501 is not set ++# CONFIG_MFD_SMSC is not set ++# CONFIG_ABX500_CORE is not set ++# CONFIG_MFD_STMPE is not set ++# CONFIG_MFD_SYSCON is not set ++# CONFIG_MFD_TI_AM335X_TSCADC is not set ++# CONFIG_MFD_LP8788 is not set ++# CONFIG_MFD_PALMAS is not set ++# CONFIG_TPS6105X is not set ++# CONFIG_TPS65010 is not set ++# CONFIG_TPS6507X is not set ++# CONFIG_MFD_TPS65090 is not set ++# CONFIG_MFD_TPS65217 is not set ++# CONFIG_MFD_TPS6586X is not set ++# CONFIG_MFD_TPS65910 is not set ++# CONFIG_MFD_TPS65912 is not set ++# CONFIG_MFD_TPS65912_I2C is not set ++# CONFIG_MFD_TPS65912_SPI is not set ++# CONFIG_MFD_TPS80031 is not set ++# CONFIG_TWL4030_CORE is not set ++# CONFIG_TWL6040_CORE is not set ++# CONFIG_MFD_WL1273_CORE is not set ++# CONFIG_MFD_LM3533 is not set ++# CONFIG_MFD_TIMBERDALE 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_MFD_VX855 is not set ++# CONFIG_MFD_ARIZONA_I2C is not set ++# CONFIG_MFD_ARIZONA_SPI 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_VEXPRESS_CONFIG=y ++# CONFIG_REGULATOR is not set ++CONFIG_MEDIA_SUPPORT=y ++ ++# ++# Multimedia core support ++# ++CONFIG_MEDIA_CAMERA_SUPPORT=y ++# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set ++# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set ++# CONFIG_MEDIA_RADIO_SUPPORT is not set ++# CONFIG_MEDIA_RC_SUPPORT is not set ++CONFIG_MEDIA_CONTROLLER=y ++CONFIG_VIDEO_DEV=y ++CONFIG_VIDEO_V4L2_SUBDEV_API=y ++CONFIG_VIDEO_V4L2=y ++# CONFIG_VIDEO_ADV_DEBUG is not set ++# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set ++# CONFIG_VIDEO_V4L2_INT_DEVICE is not set ++# CONFIG_TTPCI_EEPROM is not set ++ ++# ++# Media drivers ++# ++# CONFIG_MEDIA_USB_SUPPORT is not set ++# CONFIG_MEDIA_PCI_SUPPORT is not set ++CONFIG_V4L_PLATFORM_DRIVERS=y ++# CONFIG_VIDEO_CAFE_CCIC is not set ++# CONFIG_VIDEO_TIMBERDALE is not set ++# CONFIG_SOC_CAMERA is not set ++# CONFIG_V4L_MEM2MEM_DRIVERS is not set ++# CONFIG_V4L_TEST_DRIVERS is not set ++ ++# ++# Supported MMC/SDIO adapters ++# ++# CONFIG_CYPRESS_FIRMWARE is not set ++ ++# ++# Media ancillary drivers (tuners, sensors, i2c, frontends) ++# ++# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set ++ ++# ++# Encoders, decoders, sensors and other helper chips ++# ++ ++# ++# Audio decoders, processors and mixers ++# ++# 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 is not set ++# CONFIG_VIDEO_CS5345 is not set ++# CONFIG_VIDEO_CS53L32A is not set ++# CONFIG_VIDEO_TLV320AIC23B is not set ++# CONFIG_VIDEO_UDA1342 is not set ++# CONFIG_VIDEO_WM8775 is not set ++# CONFIG_VIDEO_WM8739 is not set ++# CONFIG_VIDEO_VP27SMPX is not set ++# CONFIG_VIDEO_SONY_BTF_MPX is not set ++ ++# ++# RDS decoders ++# ++# CONFIG_VIDEO_SAA6588 is not set ++ ++# ++# Video decoders ++# ++# CONFIG_VIDEO_ADV7180 is not set ++# CONFIG_VIDEO_ADV7183 is not set ++CONFIG_VIDEO_ADV7604=y ++# 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_SAA7110 is not set ++# CONFIG_VIDEO_SAA711X 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_TW2804 is not set ++# CONFIG_VIDEO_TW9903 is not set ++# CONFIG_VIDEO_TW9906 is not set ++# CONFIG_VIDEO_VPX3220 is not set ++ ++# ++# Video and audio decoders ++# ++# CONFIG_VIDEO_SAA717X is not set ++# CONFIG_VIDEO_CX25840 is not set ++ ++# ++# 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_ADV7343 is not set ++# CONFIG_VIDEO_ADV7393 is not set ++CONFIG_VIDEO_ADV7511=y ++# CONFIG_VIDEO_AD9389B is not set ++# CONFIG_VIDEO_AK881X is not set ++ ++# ++# Camera sensor devices ++# ++# CONFIG_VIDEO_OV7640 is not set ++# CONFIG_VIDEO_OV7670 is not set ++# CONFIG_VIDEO_OV9650 is not set ++# CONFIG_VIDEO_VS6624 is not set ++# CONFIG_VIDEO_MT9M032 is not set ++# CONFIG_VIDEO_MT9P031 is not set ++# CONFIG_VIDEO_MT9T001 is not set ++# CONFIG_VIDEO_MT9V011 is not set ++# CONFIG_VIDEO_MT9V032 is not set ++# CONFIG_VIDEO_SR030PC30 is not set ++# CONFIG_VIDEO_NOON010PC30 is not set ++# CONFIG_VIDEO_M5MOLS is not set ++# CONFIG_VIDEO_S5K6AA is not set ++# CONFIG_VIDEO_S5K4ECGX is not set ++# CONFIG_VIDEO_SMIAPP is not set ++# CONFIG_VIDEO_S5C73M3 is not set ++ ++# ++# Flash devices ++# ++# CONFIG_VIDEO_ADP1653 is not set ++# CONFIG_VIDEO_AS3645A is not set ++ ++# ++# Video improvement chips ++# ++# CONFIG_VIDEO_UPD64031A is not set ++# CONFIG_VIDEO_UPD64083 is not set ++ ++# ++# Miscelaneous helper chips ++# ++# CONFIG_VIDEO_THS7303 is not set ++# CONFIG_VIDEO_M52790 is not set ++ ++# ++# Sensors used on soc_camera driver ++# ++ ++# ++# Customise DVB Frontends ++# ++# CONFIG_DVB_AU8522_V4L is not set ++# CONFIG_DVB_TUNER_DIB0070 is not set ++# CONFIG_DVB_TUNER_DIB0090 is not set ++ ++# ++# Tools to develop new frontends ++# ++# CONFIG_DVB_DUMMY_FE is not set ++ ++# ++# Graphics support ++# ++CONFIG_VGA_ARB=y ++CONFIG_VGA_ARB_MAX_GPUS=16 ++# CONFIG_DRM is not set ++# CONFIG_TEGRA_HOST1X is not set ++# CONFIG_VGASTATE is not set ++# CONFIG_VIDEO_OUTPUT_CONTROL is not set ++CONFIG_FB=y ++# CONFIG_FIRMWARE_EDID is not set ++# CONFIG_FB_DDC is not set ++# CONFIG_FB_BOOT_VESA_SUPPORT is not set ++CONFIG_FB_CFB_FILLRECT=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 is not set ++# CONFIG_FB_SYS_COPYAREA is not set ++# CONFIG_FB_SYS_IMAGEBLIT is not set ++# CONFIG_FB_FOREIGN_ENDIAN is not set ++# CONFIG_FB_SYS_FOPS is not set ++# CONFIG_FB_SVGALIB is not set ++# CONFIG_FB_MACMODES is not set ++# CONFIG_FB_BACKLIGHT is not set ++CONFIG_FB_MODE_HELPERS=y ++# CONFIG_FB_TILEBLITTING is not set ++ ++# ++# Frame buffer hardware drivers ++# ++# CONFIG_FB_CIRRUS is not set ++# CONFIG_FB_PM2 is not set ++# CONFIG_FB_ARMCLCD is not set ++# CONFIG_FB_CYBER2000 is not set ++# CONFIG_FB_ASILIANT is not set ++# CONFIG_FB_IMSTT is not set ++# CONFIG_FB_UVESA is not set ++# CONFIG_FB_S1D13XXX is not set ++# CONFIG_FB_NVIDIA is not set ++# CONFIG_FB_RIVA is not set ++# CONFIG_FB_I740 is not set ++# CONFIG_FB_MATROX is not set ++# CONFIG_FB_RADEON is not set ++# CONFIG_FB_ATY128 is not set ++# CONFIG_FB_ATY is not set ++# CONFIG_FB_S3 is not set ++# CONFIG_FB_SAVAGE is not set ++# CONFIG_FB_SIS is not set ++# CONFIG_FB_NEOMAGIC is not set ++# CONFIG_FB_KYRO is not set ++# CONFIG_FB_3DFX is not set ++# CONFIG_FB_VOODOO1 is not set ++# CONFIG_FB_VT8623 is not set ++# CONFIG_FB_TRIDENT is not set ++# CONFIG_FB_ARK is not set ++# CONFIG_FB_PM3 is not set ++# CONFIG_FB_CARMINE is not set ++# CONFIG_FB_SMSCUFX is not set ++# CONFIG_FB_UDL is not set ++# CONFIG_FB_XILINX is not set ++# CONFIG_FB_GOLDFISH is not set ++# CONFIG_FB_VIRTUAL is not set ++# CONFIG_FB_METRONOME is not set ++# CONFIG_FB_MB862XX is not set ++# CONFIG_FB_BROADSHEET is not set ++# CONFIG_FB_AUO_K190X is not set ++# CONFIG_FB_SIMPLE is not set ++CONFIG_FB_XYLON=y ++# CONFIG_FB_XYLON_PLATFORM is not set ++CONFIG_FB_XYLON_OF=y ++CONFIG_FB_XYLON_PIXCLK=y ++# CONFIG_FB_XYLON_PIXCLK_ZYNQ_PS is not set ++# CONFIG_FB_XYLON_PIXCLK_LOGICLK is not set ++CONFIG_FB_XYLON_PIXCLK_SI570=y ++CONFIG_FB_XYLON_MISC=y ++CONFIG_FB_XYLON_MISC_ADV7511=y ++# CONFIG_EXYNOS_VIDEO is not set ++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set ++ ++# ++# Console display driver support ++# ++CONFIG_DUMMY_CONSOLE=y ++CONFIG_FRAMEBUFFER_CONSOLE=y ++# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set ++# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set ++CONFIG_FONTS=y ++CONFIG_FONT_8x8=y ++CONFIG_FONT_8x16=y ++# CONFIG_FONT_6x11 is not set ++# CONFIG_FONT_7x14 is not set ++# CONFIG_FONT_PEARL_8x8 is not set ++# CONFIG_FONT_ACORN_8x8 is not set ++# CONFIG_FONT_MINI_4x6 is not set ++# CONFIG_FONT_SUN8x16 is not set ++# CONFIG_FONT_SUN12x22 is not set ++# CONFIG_FONT_10x18 is not set ++# CONFIG_LOGO is not set ++# CONFIG_FB_SSD1307 is not set ++# CONFIG_SOUND is not set ++ ++# ++# HID support ++# ++CONFIG_HID=y ++# CONFIG_HID_BATTERY_STRENGTH is not set ++# CONFIG_HIDRAW is not set ++# CONFIG_UHID is not set ++CONFIG_HID_GENERIC=y ++ ++# ++# Special HID drivers ++# ++# CONFIG_HID_A4TECH is not set ++# CONFIG_HID_ACRUX is not set ++# CONFIG_HID_APPLE is not set ++# CONFIG_HID_APPLEIR is not set ++# CONFIG_HID_AUREAL is not set ++# CONFIG_HID_BELKIN is not set ++# CONFIG_HID_CHERRY is not set ++# CONFIG_HID_CHICONY is not set ++# CONFIG_HID_CYPRESS is not set ++# CONFIG_HID_DRAGONRISE is not set ++# CONFIG_HID_EMS_FF is not set ++# CONFIG_HID_ELECOM is not set ++# CONFIG_HID_EZKEY is not set ++# CONFIG_HID_HOLTEK is not set ++# CONFIG_HID_KEYTOUCH is not set ++# CONFIG_HID_KYE is not set ++# CONFIG_HID_UCLOGIC is not set ++# CONFIG_HID_WALTOP is not set ++# CONFIG_HID_GYRATION is not set ++# CONFIG_HID_ICADE is not set ++# CONFIG_HID_TWINHAN is not set ++# CONFIG_HID_KENSINGTON is not set ++# CONFIG_HID_LCPOWER is not set ++# CONFIG_HID_LENOVO_TPKBD is not set ++# CONFIG_HID_LOGITECH is not set ++# CONFIG_HID_MAGICMOUSE is not set ++CONFIG_HID_MICROSOFT=y ++# CONFIG_HID_MONTEREY is not set ++# CONFIG_HID_MULTITOUCH is not set ++# CONFIG_HID_NTRIG is not set ++# CONFIG_HID_ORTEK is not set ++# CONFIG_HID_PANTHERLORD is not set ++# CONFIG_HID_PETALYNX is not set ++# CONFIG_HID_PICOLCD is not set ++# CONFIG_HID_PRIMAX is not set ++# CONFIG_HID_PS3REMOTE is not set ++# CONFIG_HID_ROCCAT is not set ++# CONFIG_HID_SAITEK is not set ++# CONFIG_HID_SAMSUNG is not set ++# CONFIG_HID_SONY is not set ++# CONFIG_HID_SPEEDLINK is not set ++# CONFIG_HID_STEELSERIES is not set ++# CONFIG_HID_SUNPLUS is not set ++# CONFIG_HID_GREENASIA is not set ++# CONFIG_HID_SMARTJOYPLUS is not set ++# CONFIG_HID_TIVO is not set ++# CONFIG_HID_TOPSEED is not set ++# CONFIG_HID_THRUSTMASTER is not set ++# CONFIG_HID_ZEROPLUS is not set ++# CONFIG_HID_ZYDACRON is not set ++# CONFIG_HID_SENSOR_HUB is not set ++ ++# ++# USB HID support ++# ++CONFIG_USB_HID=y ++# CONFIG_HID_PID is not set ++# CONFIG_USB_HIDDEV is not set ++ ++# ++# I2C HID support ++# ++# CONFIG_I2C_HID is not set ++CONFIG_USB_ARCH_HAS_OHCI=y ++CONFIG_USB_ARCH_HAS_EHCI=y ++CONFIG_USB_ARCH_HAS_XHCI=y ++CONFIG_USB_SUPPORT=y ++CONFIG_USB_COMMON=y ++CONFIG_USB_ARCH_HAS_HCD=y ++CONFIG_USB=y ++# CONFIG_USB_DEBUG is not set ++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set ++ ++# ++# Miscellaneous USB options ++# ++CONFIG_USB_DEFAULT_PERSIST=y ++# CONFIG_USB_DYNAMIC_MINORS is not set ++CONFIG_USB_OTG=y ++# CONFIG_USB_OTG_WHITELIST is not set ++# CONFIG_USB_OTG_BLACKLIST_HUB is not set ++# CONFIG_USB_MON is not set ++# CONFIG_USB_WUSB_CBAF is not set ++ ++# ++# USB Host Controller Drivers ++# ++# CONFIG_USB_C67X00_HCD is not set ++# CONFIG_USB_XHCI_HCD is not set ++CONFIG_USB_EHCI_HCD=y ++CONFIG_USB_EHCI_ROOT_HUB_TT=y ++# CONFIG_USB_EHCI_TT_NEWSCHED is not set ++CONFIG_USB_EHCI_PCI=y ++CONFIG_USB_XUSBPS_DR_OF=y ++CONFIG_USB_EHCI_XUSBPS=y ++# CONFIG_USB_EHCI_HCD_PLATFORM is not set ++# CONFIG_USB_OXU210HP_HCD is not set ++# CONFIG_USB_ISP116X_HCD is not set ++# CONFIG_USB_ISP1760_HCD is not set ++# CONFIG_USB_ISP1362_HCD is not set ++# CONFIG_USB_OHCI_HCD is not set ++# CONFIG_USB_UHCI_HCD is not set ++# CONFIG_USB_SL811_HCD is not set ++# CONFIG_USB_R8A66597_HCD is not set ++# CONFIG_USB_MUSB_HDRC is not set ++# CONFIG_USB_RENESAS_USBHS is not set ++ ++# ++# USB Device Class drivers ++# ++# CONFIG_USB_ACM is not set ++# CONFIG_USB_PRINTER is not set ++# CONFIG_USB_WDM is not set ++# CONFIG_USB_TMC is not set ++ ++# ++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may ++# ++ ++# ++# also be needed; see USB_STORAGE Help for more info ++# ++CONFIG_USB_STORAGE=y ++# CONFIG_USB_STORAGE_DEBUG is not set ++# CONFIG_USB_STORAGE_REALTEK is not set ++# CONFIG_USB_STORAGE_DATAFAB is not set ++# CONFIG_USB_STORAGE_FREECOM is not set ++# CONFIG_USB_STORAGE_ISD200 is not set ++# CONFIG_USB_STORAGE_USBAT is not set ++# CONFIG_USB_STORAGE_SDDR09 is not set ++# CONFIG_USB_STORAGE_SDDR55 is not set ++# CONFIG_USB_STORAGE_JUMPSHOT is not set ++# CONFIG_USB_STORAGE_ALAUDA is not set ++# CONFIG_USB_STORAGE_ONETOUCH is not set ++# CONFIG_USB_STORAGE_KARMA is not set ++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set ++# CONFIG_USB_STORAGE_ENE_UB6250 is not set ++ ++# ++# USB Imaging devices ++# ++# CONFIG_USB_MDC800 is not set ++# CONFIG_USB_MICROTEK is not set ++# CONFIG_USB_DWC3 is not set ++# CONFIG_USB_CHIPIDEA is not set ++ ++# ++# USB port drivers ++# ++# CONFIG_USB_SERIAL is not set ++ ++# ++# USB Miscellaneous drivers ++# ++# CONFIG_USB_EMI62 is not set ++# CONFIG_USB_EMI26 is not set ++# CONFIG_USB_ADUTUX is not set ++# CONFIG_USB_SEVSEG is not set ++# CONFIG_USB_RIO500 is not set ++# CONFIG_USB_LEGOTOWER is not set ++# CONFIG_USB_LCD is not set ++# CONFIG_USB_LED is not set ++# CONFIG_USB_CYPRESS_CY7C63 is not set ++# CONFIG_USB_CYTHERM is not set ++# CONFIG_USB_IDMOUSE is not set ++# CONFIG_USB_FTDI_ELAN is not set ++# CONFIG_USB_APPLEDISPLAY is not set ++# CONFIG_USB_SISUSBVGA is not set ++# CONFIG_USB_LD is not set ++# CONFIG_USB_TRANCEVIBRATOR is not set ++# CONFIG_USB_IOWARRIOR is not set ++# CONFIG_USB_TEST is not set ++# CONFIG_USB_ISIGHTFW is not set ++# CONFIG_USB_YUREX is not set ++# CONFIG_USB_EZUSB_FX2 is not set ++# CONFIG_USB_HSIC_USB3503 is not set ++CONFIG_USB_PHY=y ++# CONFIG_NOP_USB_XCEIV is not set ++# CONFIG_OMAP_CONTROL_USB is not set ++# CONFIG_OMAP_USB3 is not set ++# CONFIG_SAMSUNG_USBPHY is not set ++# CONFIG_SAMSUNG_USB2PHY is not set ++# CONFIG_SAMSUNG_USB3PHY is not set ++# CONFIG_USB_GPIO_VBUS is not set ++# CONFIG_USB_ISP1301 is not set ++# CONFIG_USB_RCAR_PHY is not set ++CONFIG_USB_ULPI=y ++CONFIG_USB_ULPI_VIEWPORT=y ++# CONFIG_USB_ZYNQ_PHY is not set ++CONFIG_USB_GADGET=y ++# CONFIG_USB_GADGET_DEBUG is not set ++# CONFIG_USB_GADGET_DEBUG_FILES is not set ++# CONFIG_USB_GADGET_DEBUG_FS is not set ++CONFIG_USB_GADGET_VBUS_DRAW=2 ++CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 ++ ++# ++# USB Peripheral Controller ++# ++CONFIG_USB_GADGET_XUSBPS=y ++CONFIG_XUSBPS_ERRATA_DT654401=y ++CONFIG_USB_XUSBPS=y ++# CONFIG_USB_FUSB300 is not set ++# CONFIG_USB_R8A66597 is not set ++# CONFIG_USB_GADGET_XILINX is not set ++# CONFIG_USB_PXA27X is not set ++# CONFIG_USB_MV_UDC is not set ++# CONFIG_USB_MV_U3D is not set ++# CONFIG_USB_M66592 is not set ++# CONFIG_USB_AMD5536UDC is not set ++# CONFIG_USB_NET2272 is not set ++# CONFIG_USB_NET2280 is not set ++# CONFIG_USB_GOKU is not set ++# CONFIG_USB_EG20T is not set ++# CONFIG_USB_DUMMY_HCD is not set ++CONFIG_USB_LIBCOMPOSITE=m ++CONFIG_USB_F_SS_LB=m ++CONFIG_USB_ZERO=m ++# CONFIG_USB_ZERO_HNPTEST is not set ++# CONFIG_USB_ETH is not set ++# CONFIG_USB_G_NCM is not set ++# CONFIG_USB_GADGETFS is not set ++# CONFIG_USB_FUNCTIONFS is not set ++# CONFIG_USB_MASS_STORAGE is not set ++# CONFIG_USB_G_SERIAL is not set ++# CONFIG_USB_G_PRINTER is not set ++# CONFIG_USB_CDC_COMPOSITE is not set ++# CONFIG_USB_G_ACM_MS is not set ++# CONFIG_USB_G_MULTI is not set ++# CONFIG_USB_G_HID is not set ++# CONFIG_USB_G_DBGP is not set ++# CONFIG_USB_G_WEBCAM is not set ++# CONFIG_UWB is not set ++CONFIG_MMC=y ++# CONFIG_MMC_DEBUG is not set ++# CONFIG_MMC_UNSAFE_RESUME is not set ++# 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 is not set ++# CONFIG_MMC_TEST is not set ++ ++# ++# MMC/SD/SDIO Host Controller Drivers ++# ++# CONFIG_MMC_ARMMMCI is not set ++CONFIG_MMC_SDHCI=y ++# CONFIG_MMC_SDHCI_PCI is not set ++CONFIG_MMC_SDHCI_PLTFM=y ++CONFIG_MMC_SDHCI_OF_XILINX_PS=y ++# CONFIG_MMC_SDHCI_PXAV3 is not set ++# CONFIG_MMC_SDHCI_PXAV2 is not set ++# CONFIG_MMC_TIFM_SD is not set ++# CONFIG_MMC_CB710 is not set ++# CONFIG_MMC_VIA_SDMMC is not set ++# CONFIG_MMC_DW is not set ++# CONFIG_MMC_VUB300 is not set ++# CONFIG_MMC_USHC is not set ++# CONFIG_MEMSTICK is not set ++# CONFIG_NEW_LEDS is not set ++# CONFIG_ACCESSIBILITY is not set ++# CONFIG_INFINIBAND is not set ++CONFIG_EDAC=y ++CONFIG_EDAC_LEGACY_SYSFS=y ++# CONFIG_EDAC_DEBUG is not set ++CONFIG_EDAC_MM_EDAC=y ++CONFIG_EDAC_ZYNQ=y ++CONFIG_RTC_LIB=y ++CONFIG_RTC_CLASS=y ++CONFIG_RTC_HCTOSYS=y ++CONFIG_RTC_SYSTOHC=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 is not set ++# 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_PCF8523 is not set ++CONFIG_RTC_DRV_PCF8563=y ++# CONFIG_RTC_DRV_PCF8583 is not set ++# CONFIG_RTC_DRV_M41T80 is not set ++# CONFIG_RTC_DRV_BQ32K is not set ++# 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 ++# CONFIG_RTC_DRV_EM3027 is not set ++# CONFIG_RTC_DRV_RV3029C2 is not set ++ ++# ++# SPI RTC drivers ++# ++# CONFIG_RTC_DRV_M41T93 is not set ++# 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 ++# CONFIG_RTC_DRV_RX4581 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 ++# CONFIG_RTC_DRV_DS2404 is not set ++ ++# ++# on-CPU RTC drivers ++# ++# CONFIG_RTC_DRV_PL030 is not set ++# CONFIG_RTC_DRV_PL031 is not set ++# CONFIG_RTC_DRV_SNVS is not set ++ ++# ++# HID Sensor RTC drivers ++# ++# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set ++CONFIG_DMADEVICES=y ++# CONFIG_DMADEVICES_DEBUG is not set ++ ++# ++# DMA Devices ++# ++CONFIG_XILINX_DMA_ENGINES=y ++CONFIG_XILINX_AXIDMA=y ++# CONFIG_XILINX_DMATEST is not set ++CONFIG_XILINX_AXIVDMA=y ++# CONFIG_XILINX_VDMATEST is not set ++CONFIG_XILINX_AXICDMA=y ++# CONFIG_XILINX_CDMATEST is not set ++# CONFIG_AMBA_PL08X is not set ++# CONFIG_DW_DMAC is not set ++# CONFIG_TIMB_DMA is not set ++CONFIG_PL330_DMA=y ++CONFIG_DMA_OF=y ++ ++# ++# DMA Clients ++# ++# CONFIG_NET_DMA is not set ++# CONFIG_ASYNC_TX_DMA is not set ++# CONFIG_DMATEST is not set ++# CONFIG_AUXDISPLAY is not set ++CONFIG_XILINX_APF=y ++CONFIG_XILINX_DMA_APF=y ++CONFIG_UIO=y ++# CONFIG_UIO_CIF is not set ++CONFIG_UIO_PDRV_GENIRQ=y ++# CONFIG_UIO_DMEM_GENIRQ is not set ++# CONFIG_UIO_AEC is not set ++# CONFIG_UIO_SERCOS3 is not set ++# CONFIG_UIO_PCI_GENERIC is not set ++# CONFIG_UIO_NETX is not set ++# CONFIG_VIRT_DRIVERS is not set ++CONFIG_VIRTIO=m ++ ++# ++# Virtio drivers ++# ++# CONFIG_VIRTIO_PCI is not set ++# CONFIG_VIRTIO_BALLOON is not set ++# CONFIG_VIRTIO_MMIO is not set ++ ++# ++# Microsoft Hyper-V guest support ++# ++CONFIG_STAGING=y ++# CONFIG_ET131X is not set ++# CONFIG_USBIP_CORE is not set ++# CONFIG_ECHO is not set ++# CONFIG_COMEDI is not set ++# CONFIG_ASUS_OLED is not set ++# CONFIG_R8187SE is not set ++# CONFIG_RTL8192U is not set ++# CONFIG_RTLLIB is not set ++# CONFIG_R8712U is not set ++# CONFIG_RTS5139 is not set ++# CONFIG_TRANZPORT is not set ++# CONFIG_VT6655 is not set ++# CONFIG_VT6656 is not set ++# CONFIG_DX_SEP is not set ++# CONFIG_ZSMALLOC is not set ++# CONFIG_FB_SM7XX is not set ++# CONFIG_CRYSTALHD is not set ++# CONFIG_FB_XGI is not set ++# CONFIG_USB_ENESTORAGE is not set ++# CONFIG_BCM_WIMAX is not set ++# CONFIG_FT1000 is not set ++ ++# ++# Speakup console speech ++# ++# CONFIG_SPEAKUP is not set ++# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set ++# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set ++# CONFIG_STAGING_MEDIA is not set ++ ++# ++# Android ++# ++# CONFIG_ANDROID is not set ++# CONFIG_USB_WPAN_HCD is not set ++# CONFIG_WIMAX_GDM72XX is not set ++CONFIG_NET_VENDOR_SILICOM=y ++# CONFIG_SBYPASS is not set ++# CONFIG_BPCTL is not set ++# CONFIG_CED1401 is not set ++# CONFIG_DGRP is not set ++CONFIG_XILINX_VIDEO_IP=y ++CONFIG_XILINX_VDMA_WRAPPER=y ++CONFIG_VIDEO_IMAGEON=m ++CONFIG_CLKDEV_LOOKUP=y ++CONFIG_HAVE_CLK_PREPARE=y ++CONFIG_COMMON_CLK=y ++ ++# ++# Common Clock Framework ++# ++CONFIG_COMMON_CLK_DEBUG=y ++CONFIG_COMMON_CLK_VERSATILE=y ++# CONFIG_COMMON_CLK_SI5351 is not set ++# CONFIG_COMMON_CLK_AXI_CLKGEN is not set ++ ++# ++# Hardware Spinlock drivers ++# ++CONFIG_CLKSRC_OF=y ++CONFIG_CLKSRC_MMIO=y ++CONFIG_CADENCE_TTC_TIMER=y ++# CONFIG_MAILBOX is not set ++CONFIG_IOMMU_SUPPORT=y ++CONFIG_OF_IOMMU=y ++ ++# ++# Remoteproc drivers ++# ++CONFIG_REMOTEPROC=m ++# CONFIG_STE_MODEM_RPROC is not set ++CONFIG_ZYNQ_REMOTEPROC=m ++CONFIG_MB_REMOTEPROC=m ++ ++# ++# Rpmsg drivers ++# ++CONFIG_RPMSG=m ++# CONFIG_RPMSG_SERVER_SAMPLE is not set ++# CONFIG_RPMSG_OMX is not set ++# CONFIG_RPMSG_FREERTOS_STAT is not set ++# CONFIG_PM_DEVFREQ is not set ++# CONFIG_EXTCON is not set ++CONFIG_MEMORY=y ++CONFIG_ZYNQ_SMC=y ++# CONFIG_IIO is not set ++# CONFIG_VME_BUS is not set ++# CONFIG_PWM is not set ++# CONFIG_PMODS is not set ++CONFIG_IRQCHIP=y ++CONFIG_ARM_GIC=y ++# CONFIG_IPACK_BUS is not set ++# CONFIG_RESET_CONTROLLER is not set ++ ++# ++# File systems ++# ++CONFIG_DCACHE_WORD_ACCESS=y ++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=y ++# CONFIG_EXT3_FS_POSIX_ACL is not set ++# CONFIG_EXT3_FS_SECURITY is not set ++CONFIG_EXT4_FS=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 is not set ++# CONFIG_JFS_FS is not set ++# CONFIG_XFS_FS is not set ++# CONFIG_GFS2_FS is not set ++# CONFIG_OCFS2_FS is not set ++# CONFIG_BTRFS_FS is not set ++# CONFIG_NILFS2_FS is not set ++# CONFIG_FS_POSIX_ACL is not set ++CONFIG_FILE_LOCKING=y ++CONFIG_FSNOTIFY=y ++# CONFIG_DNOTIFY is not set ++CONFIG_INOTIFY_USER=y ++# CONFIG_FANOTIFY is not set ++# CONFIG_QUOTA is not set ++# CONFIG_QUOTACTL is not set ++# CONFIG_AUTOFS4_FS is not set ++# CONFIG_FUSE_FS is not set ++ ++# ++# Caches ++# ++# CONFIG_FSCACHE is not set ++ ++# ++# CD-ROM/DVD Filesystems ++# ++# CONFIG_ISO9660_FS is not set ++# CONFIG_UDF_FS is not set ++ ++# ++# DOS/FAT/NT Filesystems ++# ++CONFIG_FAT_FS=y ++CONFIG_MSDOS_FS=y ++CONFIG_VFAT_FS=y ++CONFIG_FAT_DEFAULT_CODEPAGE=437 ++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" ++# CONFIG_NTFS_FS is not set ++ ++# ++# Pseudo filesystems ++# ++CONFIG_PROC_FS=y ++CONFIG_PROC_SYSCTL=y ++CONFIG_PROC_PAGE_MONITOR=y ++CONFIG_SYSFS=y ++CONFIG_TMPFS=y ++# CONFIG_TMPFS_POSIX_ACL is not set ++# CONFIG_TMPFS_XATTR is not set ++# CONFIG_HUGETLB_PAGE is not set ++CONFIG_CONFIGFS_FS=m ++CONFIG_MISC_FILESYSTEMS=y ++# CONFIG_ADFS_FS is not set ++# CONFIG_AFFS_FS is not set ++# CONFIG_HFS_FS is not set ++# CONFIG_HFSPLUS_FS is not set ++# CONFIG_BEFS_FS is not set ++# CONFIG_BFS_FS is not set ++# CONFIG_EFS_FS is not set ++CONFIG_JFFS2_FS=y ++CONFIG_JFFS2_FS_DEBUG=0 ++CONFIG_JFFS2_FS_WRITEBUFFER=y ++# CONFIG_JFFS2_FS_WBUF_VERIFY is not set ++CONFIG_JFFS2_SUMMARY=y ++# CONFIG_JFFS2_FS_XATTR is not set ++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set ++CONFIG_JFFS2_ZLIB=y ++# CONFIG_JFFS2_LZO is not set ++CONFIG_JFFS2_RTIME=y ++# CONFIG_JFFS2_RUBIN is not set ++# CONFIG_LOGFS is not set ++# CONFIG_CRAMFS is not set ++# CONFIG_SQUASHFS is not set ++# CONFIG_VXFS_FS is not set ++# CONFIG_MINIX_FS is not set ++# CONFIG_OMFS_FS is not set ++# CONFIG_HPFS_FS is not set ++# CONFIG_QNX4FS_FS is not set ++# CONFIG_QNX6FS_FS is not set ++# CONFIG_ROMFS_FS is not set ++# CONFIG_PSTORE is not set ++# CONFIG_SYSV_FS is not set ++# CONFIG_UFS_FS is not set ++# CONFIG_F2FS_FS is not set ++CONFIG_NETWORK_FILESYSTEMS=y ++CONFIG_NFS_FS=y ++CONFIG_NFS_V2=y ++CONFIG_NFS_V3=y ++# CONFIG_NFS_V3_ACL is not set ++# CONFIG_NFS_V4 is not set ++# CONFIG_NFS_SWAP is not set ++CONFIG_ROOT_NFS=y ++# CONFIG_NFSD is not set ++CONFIG_LOCKD=y ++CONFIG_LOCKD_V4=y ++CONFIG_NFS_COMMON=y ++CONFIG_SUNRPC=y ++# CONFIG_SUNRPC_DEBUG is not set ++# CONFIG_CEPH_FS is not set ++# CONFIG_CIFS is not set ++# CONFIG_NCP_FS is not set ++# CONFIG_CODA_FS is not set ++# CONFIG_AFS_FS is not set ++CONFIG_NLS=y ++CONFIG_NLS_DEFAULT="iso8859-1" ++CONFIG_NLS_CODEPAGE_437=y ++# CONFIG_NLS_CODEPAGE_737 is not set ++# CONFIG_NLS_CODEPAGE_775 is not set ++# CONFIG_NLS_CODEPAGE_850 is not set ++# CONFIG_NLS_CODEPAGE_852 is not set ++# CONFIG_NLS_CODEPAGE_855 is not set ++# CONFIG_NLS_CODEPAGE_857 is not set ++# CONFIG_NLS_CODEPAGE_860 is not set ++# CONFIG_NLS_CODEPAGE_861 is not set ++# CONFIG_NLS_CODEPAGE_862 is not set ++# CONFIG_NLS_CODEPAGE_863 is not set ++# CONFIG_NLS_CODEPAGE_864 is not set ++# CONFIG_NLS_CODEPAGE_865 is not set ++# CONFIG_NLS_CODEPAGE_866 is not set ++# CONFIG_NLS_CODEPAGE_869 is not set ++# CONFIG_NLS_CODEPAGE_936 is not set ++# CONFIG_NLS_CODEPAGE_950 is not set ++# CONFIG_NLS_CODEPAGE_932 is not set ++# CONFIG_NLS_CODEPAGE_949 is not set ++# CONFIG_NLS_CODEPAGE_874 is not set ++# CONFIG_NLS_ISO8859_8 is not set ++# CONFIG_NLS_CODEPAGE_1250 is not set ++# CONFIG_NLS_CODEPAGE_1251 is not set ++CONFIG_NLS_ASCII=y ++CONFIG_NLS_ISO8859_1=y ++# CONFIG_NLS_ISO8859_2 is not set ++# CONFIG_NLS_ISO8859_3 is not set ++# CONFIG_NLS_ISO8859_4 is not set ++# CONFIG_NLS_ISO8859_5 is not set ++# CONFIG_NLS_ISO8859_6 is not set ++# CONFIG_NLS_ISO8859_7 is not set ++# CONFIG_NLS_ISO8859_9 is not set ++# CONFIG_NLS_ISO8859_13 is not set ++# CONFIG_NLS_ISO8859_14 is not set ++# CONFIG_NLS_ISO8859_15 is not set ++# CONFIG_NLS_KOI8_R is not set ++# CONFIG_NLS_KOI8_U is not set ++# CONFIG_NLS_MAC_ROMAN is not set ++# CONFIG_NLS_MAC_CELTIC is not set ++# CONFIG_NLS_MAC_CENTEURO is not set ++# CONFIG_NLS_MAC_CROATIAN is not set ++# CONFIG_NLS_MAC_CYRILLIC is not set ++# CONFIG_NLS_MAC_GAELIC is not set ++# CONFIG_NLS_MAC_GREEK is not set ++# CONFIG_NLS_MAC_ICELAND is not set ++# CONFIG_NLS_MAC_INUIT is not set ++# CONFIG_NLS_MAC_ROMANIAN is not set ++# CONFIG_NLS_MAC_TURKISH is not set ++# CONFIG_NLS_UTF8 is not set ++# CONFIG_DLM is not set ++ ++# ++# Kernel hacking ++# ++# CONFIG_PRINTK_TIME is not set ++CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 ++# CONFIG_ENABLE_WARN_DEPRECATED is not set ++# CONFIG_ENABLE_MUST_CHECK is not set ++CONFIG_FRAME_WARN=1024 ++# CONFIG_MAGIC_SYSRQ is not set ++# CONFIG_STRIP_ASM_SYMS is not set ++# CONFIG_READABLE_ASM 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_PANIC_ON_OOPS is not set ++CONFIG_PANIC_ON_OOPS_VALUE=0 ++# CONFIG_DETECT_HUNG_TASK is not set ++# CONFIG_SCHED_DEBUG is not set ++# CONFIG_SCHEDSTATS is not set ++CONFIG_TIMER_STATS=y ++# CONFIG_DEBUG_OBJECTS is not set ++# CONFIG_DEBUG_SLAB is not set ++CONFIG_HAVE_DEBUG_KMEMLEAK=y ++# CONFIG_DEBUG_KMEMLEAK is not set ++# CONFIG_DEBUG_PREEMPT is not set ++# CONFIG_DEBUG_RT_MUTEXES is not set ++# CONFIG_RT_MUTEX_TESTER is not set ++# CONFIG_DEBUG_SPINLOCK is not set ++# CONFIG_DEBUG_MUTEXES is not set ++# CONFIG_DEBUG_LOCK_ALLOC is not set ++# CONFIG_PROVE_LOCKING is not set ++# CONFIG_LOCK_STAT is not set ++# CONFIG_DEBUG_ATOMIC_SLEEP is not set ++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set ++# CONFIG_DEBUG_STACK_USAGE is not set ++# CONFIG_DEBUG_KOBJECT is not set ++# CONFIG_DEBUG_HIGHMEM 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 ++ ++# ++# RCU Debugging ++# ++# CONFIG_PROVE_RCU_DELAY is not set ++# CONFIG_SPARSE_RCU_POINTER is not set ++# CONFIG_RCU_TORTURE_TEST is not set ++CONFIG_RCU_CPU_STALL_TIMEOUT=60 ++# CONFIG_RCU_CPU_STALL_VERBOSE is not set ++# CONFIG_RCU_CPU_STALL_INFO is not set ++# CONFIG_RCU_TRACE 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_DEBUG_PER_CPU_MAPS is not set ++# CONFIG_LKDTM is not set ++# CONFIG_NOTIFIER_ERROR_INJECTION is not set ++# CONFIG_FAULT_INJECTION 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_SYSCALL_TRACEPOINTS=y ++CONFIG_HAVE_C_RECORDMCOUNT=y ++CONFIG_TRACING_SUPPORT=y ++# CONFIG_FTRACE is not set ++# CONFIG_RBTREE_TEST is not set ++# CONFIG_INTERVAL_TREE_TEST is not set ++CONFIG_DYNAMIC_DEBUG=y ++# CONFIG_DMA_API_DEBUG is not set ++# CONFIG_ATOMIC64_SELFTEST is not set ++# CONFIG_SAMPLES is not set ++CONFIG_HAVE_ARCH_KGDB=y ++# CONFIG_KGDB is not set ++# CONFIG_TEST_STRING_HELPERS 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_LL=y ++# CONFIG_DEBUG_ZYNQ_UART0 is not set ++CONFIG_DEBUG_ZYNQ_UART1=y ++# CONFIG_DEBUG_VEXPRESS_UART0_DETECT is not set ++# CONFIG_DEBUG_VEXPRESS_UART0_CA9 is not set ++# CONFIG_DEBUG_VEXPRESS_UART0_RS1 is not set ++# CONFIG_DEBUG_ICEDCC is not set ++# CONFIG_DEBUG_SEMIHOSTING is not set ++CONFIG_DEBUG_LL_INCLUDE="debug/zynq.S" ++CONFIG_DEBUG_UNCOMPRESS=y ++CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h" ++CONFIG_EARLY_PRINTK=y ++# CONFIG_OC_ETM is not set ++# CONFIG_PID_IN_CONTEXTIDR is not set ++ ++# ++# Security options ++# ++# CONFIG_KEYS is not set ++# CONFIG_SECURITY_DMESG_RESTRICT is not set ++# CONFIG_SECURITY is not set ++# CONFIG_SECURITYFS is not set ++CONFIG_DEFAULT_SECURITY_DAC=y ++CONFIG_DEFAULT_SECURITY="" ++CONFIG_CRYPTO=y ++ ++# ++# Crypto core or helper ++# ++# CONFIG_CRYPTO_FIPS is not set ++CONFIG_CRYPTO_ALGAPI=y ++CONFIG_CRYPTO_ALGAPI2=y ++CONFIG_CRYPTO_HASH=y ++CONFIG_CRYPTO_HASH2=y ++CONFIG_CRYPTO_RNG=m ++CONFIG_CRYPTO_RNG2=m ++# CONFIG_CRYPTO_MANAGER is not set ++# CONFIG_CRYPTO_MANAGER2 is not set ++# CONFIG_CRYPTO_USER is not set ++# CONFIG_CRYPTO_GF128MUL is not set ++# CONFIG_CRYPTO_NULL is not set ++# CONFIG_CRYPTO_PCRYPT is not set ++# CONFIG_CRYPTO_CRYPTD is not set ++# CONFIG_CRYPTO_AUTHENC is not set ++# CONFIG_CRYPTO_TEST is not set ++ ++# ++# Authenticated Encryption with Associated Data ++# ++# CONFIG_CRYPTO_CCM is not set ++# CONFIG_CRYPTO_GCM is not set ++# CONFIG_CRYPTO_SEQIV is not set ++ ++# ++# Block modes ++# ++# CONFIG_CRYPTO_CBC is not set ++# CONFIG_CRYPTO_CTR is not set ++# CONFIG_CRYPTO_CTS is not set ++# CONFIG_CRYPTO_ECB is not set ++# CONFIG_CRYPTO_LRW is not set ++# CONFIG_CRYPTO_PCBC is not set ++# CONFIG_CRYPTO_XTS is not set ++ ++# ++# Hash modes ++# ++# CONFIG_CRYPTO_CMAC is not set ++# CONFIG_CRYPTO_HMAC is not set ++# CONFIG_CRYPTO_XCBC is not set ++# CONFIG_CRYPTO_VMAC is not set ++ ++# ++# Digest ++# ++CONFIG_CRYPTO_CRC32C=y ++# CONFIG_CRYPTO_CRC32 is not set ++# CONFIG_CRYPTO_GHASH is not set ++# CONFIG_CRYPTO_MD4 is not set ++# CONFIG_CRYPTO_MD5 is not set ++# CONFIG_CRYPTO_MICHAEL_MIC is not set ++# CONFIG_CRYPTO_RMD128 is not set ++# CONFIG_CRYPTO_RMD160 is not set ++# CONFIG_CRYPTO_RMD256 is not set ++# CONFIG_CRYPTO_RMD320 is not set ++# CONFIG_CRYPTO_SHA1 is not set ++# CONFIG_CRYPTO_SHA1_ARM is not set ++# CONFIG_CRYPTO_SHA256 is not set ++# CONFIG_CRYPTO_SHA512 is not set ++# CONFIG_CRYPTO_TGR192 is not set ++# CONFIG_CRYPTO_WP512 is not set ++ ++# ++# Ciphers ++# ++CONFIG_CRYPTO_AES=y ++# CONFIG_CRYPTO_AES_ARM is not set ++# CONFIG_CRYPTO_ANUBIS is not set ++# CONFIG_CRYPTO_ARC4 is not set ++# CONFIG_CRYPTO_BLOWFISH is not set ++# CONFIG_CRYPTO_CAMELLIA is not set ++# CONFIG_CRYPTO_CAST5 is not set ++# CONFIG_CRYPTO_CAST6 is not set ++# CONFIG_CRYPTO_DES is not set ++# CONFIG_CRYPTO_FCRYPT is not set ++# CONFIG_CRYPTO_KHAZAD is not set ++# CONFIG_CRYPTO_SALSA20 is not set ++# CONFIG_CRYPTO_SEED is not set ++# CONFIG_CRYPTO_SERPENT is not set ++# CONFIG_CRYPTO_TEA is not set ++# CONFIG_CRYPTO_TWOFISH is not set ++ ++# ++# Compression ++# ++# CONFIG_CRYPTO_DEFLATE is not set ++# CONFIG_CRYPTO_ZLIB is not set ++# CONFIG_CRYPTO_LZO is not set ++ ++# ++# Random Number Generation ++# ++CONFIG_CRYPTO_ANSI_CPRNG=m ++# CONFIG_CRYPTO_USER_API_HASH is not set ++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set ++CONFIG_CRYPTO_HW=y ++# CONFIG_CRYPTO_DEV_HIFN_795X is not set ++# CONFIG_BINARY_PRINTF is not set ++ ++# ++# Library routines ++# ++CONFIG_BITREVERSE=y ++CONFIG_GENERIC_STRNCPY_FROM_USER=y ++CONFIG_GENERIC_STRNLEN_USER=y ++CONFIG_GENERIC_PCI_IOMAP=y ++CONFIG_GENERIC_IO=y ++# CONFIG_CRC_CCITT is not set ++CONFIG_CRC16=y ++# CONFIG_CRC_T10DIF is not set ++# CONFIG_CRC_ITU_T is not set ++CONFIG_CRC32=y ++# CONFIG_CRC32_SELFTEST is not set ++CONFIG_CRC32_SLICEBY8=y ++# CONFIG_CRC32_SLICEBY4 is not set ++# CONFIG_CRC32_SARWATE is not set ++# CONFIG_CRC32_BIT is not set ++# CONFIG_CRC7 is not set ++# CONFIG_LIBCRC32C is not set ++# CONFIG_CRC8 is not set ++CONFIG_ZLIB_INFLATE=y ++CONFIG_ZLIB_DEFLATE=y ++# CONFIG_XZ_DEC is not set ++# CONFIG_XZ_DEC_BCJ is not set ++CONFIG_DECOMPRESS_GZIP=y ++CONFIG_HAS_IOMEM=y ++CONFIG_HAS_DMA=y ++CONFIG_CPU_RMAP=y ++CONFIG_DQL=y ++CONFIG_NLATTR=y ++CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y ++# CONFIG_AVERAGE is not set ++# CONFIG_CORDIC is not set ++# CONFIG_DDR is not set ++CONFIG_VIRTUALIZATION=y ++CONFIG_KVM_ARM_MAX_VCPUS=0 ++ ++# ++# Virtio drivers ++# +diff --git a/arch/arm/configs/xilinx_zynq_base_trd_defconfig b/arch/arm/configs/xilinx_zynq_base_trd_defconfig +new file mode 100644 +index 0000000..e39d1e6 +--- /dev/null ++++ b/arch/arm/configs/xilinx_zynq_base_trd_defconfig +@@ -0,0 +1,2843 @@ ++# ++# Automatically generated file; DO NOT EDIT. ++# Linux/arm 3.8.0 Kernel Configuration ++# ++CONFIG_ARM=y ++CONFIG_MIGHT_HAVE_PCI=y ++CONFIG_SYS_SUPPORTS_APM_EMULATION=y ++CONFIG_GENERIC_GPIO=y ++CONFIG_HAVE_PROC_CPU=y ++CONFIG_NO_IOPORT=y ++CONFIG_STACKTRACE_SUPPORT=y ++CONFIG_LOCKDEP_SUPPORT=y ++CONFIG_TRACE_IRQFLAGS_SUPPORT=y ++CONFIG_RWSEM_GENERIC_SPINLOCK=y ++CONFIG_ARCH_HAS_CPUFREQ=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=y ++CONFIG_GENERIC_BUG=y ++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" ++CONFIG_HAVE_IRQ_WORK=y ++CONFIG_IRQ_WORK=y ++CONFIG_BUILDTIME_EXTABLE_SORT=y ++ ++# ++# General setup ++# ++CONFIG_EXPERIMENTAL=y ++CONFIG_INIT_ENV_ARG_LIMIT=32 ++CONFIG_CROSS_COMPILE="" ++CONFIG_LOCALVERSION="-xilinx-trd" ++CONFIG_LOCALVERSION_AUTO=y ++CONFIG_HAVE_KERNEL_GZIP=y ++CONFIG_HAVE_KERNEL_LZMA=y ++CONFIG_HAVE_KERNEL_XZ=y ++CONFIG_HAVE_KERNEL_LZO=y ++CONFIG_KERNEL_GZIP=y ++# CONFIG_KERNEL_LZMA is not set ++# CONFIG_KERNEL_XZ is not set ++# CONFIG_KERNEL_LZO is not set ++CONFIG_DEFAULT_HOSTNAME="(none)" ++CONFIG_SWAP=y ++CONFIG_SYSVIPC=y ++CONFIG_SYSVIPC_SYSCTL=y ++# CONFIG_POSIX_MQUEUE is not set ++# CONFIG_FHANDLE is not set ++# CONFIG_AUDIT is not set ++CONFIG_HAVE_GENERIC_HARDIRQS=y ++ ++# ++# IRQ subsystem ++# ++CONFIG_GENERIC_HARDIRQS=y ++CONFIG_GENERIC_IRQ_PROBE=y ++CONFIG_GENERIC_IRQ_SHOW=y ++CONFIG_HARDIRQS_SW_RESEND=y ++CONFIG_IRQ_DOMAIN=y ++CONFIG_IRQ_DOMAIN_DEBUG=y ++CONFIG_SPARSE_IRQ=y ++CONFIG_KTIME_SCALAR=y ++CONFIG_GENERIC_CLOCKEVENTS=y ++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y ++CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y ++ ++# ++# Timers subsystem ++# ++CONFIG_TICK_ONESHOT=y ++CONFIG_NO_HZ=y ++CONFIG_HIGH_RES_TIMERS=y ++ ++# ++# CPU/Task time and stats accounting ++# ++CONFIG_TICK_CPU_ACCOUNTING=y ++# CONFIG_BSD_PROCESS_ACCT is not set ++# CONFIG_TASKSTATS is not set ++ ++# ++# RCU Subsystem ++# ++CONFIG_TREE_PREEMPT_RCU=y ++CONFIG_PREEMPT_RCU=y ++CONFIG_RCU_FANOUT=32 ++CONFIG_RCU_FANOUT_LEAF=16 ++# CONFIG_RCU_FANOUT_EXACT is not set ++# CONFIG_RCU_FAST_NO_HZ is not set ++# CONFIG_TREE_RCU_TRACE is not set ++# CONFIG_RCU_BOOST is not set ++# CONFIG_RCU_NOCB_CPU is not set ++CONFIG_IKCONFIG=y ++CONFIG_IKCONFIG_PROC=y ++CONFIG_LOG_BUF_SHIFT=14 ++# CONFIG_CGROUPS is not set ++# CONFIG_CHECKPOINT_RESTORE is not set ++# CONFIG_NAMESPACES is not set ++# CONFIG_SCHED_AUTOGROUP is not set ++CONFIG_SYSFS_DEPRECATED=y ++CONFIG_SYSFS_DEPRECATED_V2=y ++# 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 is not set ++# CONFIG_RD_LZO is not set ++CONFIG_CC_OPTIMIZE_FOR_SIZE=y ++CONFIG_SYSCTL=y ++CONFIG_ANON_INODES=y ++CONFIG_EXPERT=y ++CONFIG_HAVE_UID16=y ++CONFIG_UID16=y ++CONFIG_SYSCTL_SYSCALL=y ++CONFIG_KALLSYMS=y ++# CONFIG_KALLSYMS_ALL 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_DEBUG_PERF_USE_VMALLOC is not set ++CONFIG_VM_EVENT_COUNTERS=y ++CONFIG_PCI_QUIRKS=y ++CONFIG_COMPAT_BRK=y ++CONFIG_SLAB=y ++# CONFIG_SLUB is not set ++# CONFIG_SLOB is not set ++# CONFIG_PROFILING is not set ++CONFIG_HAVE_OPROFILE=y ++# CONFIG_KPROBES is not set ++# CONFIG_JUMP_LABEL is not set ++CONFIG_HAVE_KPROBES=y ++CONFIG_HAVE_KRETPROBES=y ++CONFIG_HAVE_ARCH_TRACEHOOK=y ++CONFIG_HAVE_DMA_ATTRS=y ++CONFIG_HAVE_DMA_CONTIGUOUS=y ++CONFIG_USE_GENERIC_SMP_HELPERS=y ++CONFIG_GENERIC_SMP_IDLE_THREAD=y ++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y ++CONFIG_HAVE_CLK=y ++CONFIG_HAVE_DMA_API_DEBUG=y ++CONFIG_HAVE_HW_BREAKPOINT=y ++CONFIG_HAVE_ARCH_JUMP_LABEL=y ++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y ++CONFIG_HAVE_ARCH_SECCOMP_FILTER=y ++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y ++CONFIG_MODULES_USE_ELF_REL=y ++CONFIG_CLONE_BACKWARDS=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 is not set ++CONFIG_MODULE_UNLOAD=y ++CONFIG_MODULE_FORCE_UNLOAD=y ++CONFIG_MODVERSIONS=y ++# CONFIG_MODULE_SRCVERSION_ALL is not set ++# CONFIG_MODULE_SIG is not set ++CONFIG_STOP_MACHINE=y ++CONFIG_BLOCK=y ++CONFIG_LBDAF=y ++# CONFIG_BLK_DEV_BSG is not set ++# CONFIG_BLK_DEV_BSGLIB is not set ++# CONFIG_BLK_DEV_INTEGRITY is not set ++ ++# ++# Partition Types ++# ++# CONFIG_PARTITION_ADVANCED is not set ++CONFIG_MSDOS_PARTITION=y ++CONFIG_EFI_PARTITION=y ++ ++# ++# 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_UNINLINE_SPIN_UNLOCK=y ++CONFIG_MUTEX_SPIN_ON_OWNER=y ++# CONFIG_FREEZER is not set ++ ++# ++# System Type ++# ++CONFIG_MMU=y ++CONFIG_ARCH_MULTIPLATFORM=y ++# CONFIG_ARCH_INTEGRATOR is not set ++# CONFIG_ARCH_REALVIEW is not set ++# CONFIG_ARCH_VERSATILE is not set ++# CONFIG_ARCH_AT91 is not set ++# CONFIG_ARCH_BCM2835 is not set ++# CONFIG_ARCH_CNS3XXX is not set ++# CONFIG_ARCH_CLPS711X is not set ++# CONFIG_ARCH_GEMINI is not set ++# CONFIG_ARCH_SIRF is not set ++# CONFIG_ARCH_EBSA110 is not set ++# CONFIG_ARCH_EP93XX is not set ++# CONFIG_ARCH_FOOTBRIDGE is not set ++# CONFIG_ARCH_MXS 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_IXP4XX is not set ++# CONFIG_ARCH_DOVE is not set ++# CONFIG_ARCH_KIRKWOOD 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_W90X900 is not set ++# CONFIG_ARCH_LPC32XX is not set ++# CONFIG_ARCH_TEGRA 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_S3C24XX is not set ++# CONFIG_ARCH_S3C64XX is not set ++# CONFIG_ARCH_S5P64X0 is not set ++# CONFIG_ARCH_S5PC100 is not set ++# CONFIG_ARCH_S5PV210 is not set ++# CONFIG_ARCH_EXYNOS is not set ++# CONFIG_ARCH_SHARK is not set ++# CONFIG_ARCH_U300 is not set ++# CONFIG_ARCH_U8500 is not set ++# CONFIG_ARCH_NOMADIK is not set ++# CONFIG_PLAT_SPEAR is not set ++# CONFIG_ARCH_DAVINCI is not set ++# CONFIG_ARCH_OMAP is not set ++# CONFIG_ARCH_VT8500_SINGLE is not set ++ ++# ++# Multiple platform selection ++# ++ ++# ++# CPU Core family selection ++# ++# CONFIG_ARCH_MULTI_V6 is not set ++CONFIG_ARCH_MULTI_V7=y ++CONFIG_ARCH_MULTI_V6_V7=y ++# CONFIG_ARCH_MULTI_CPU_AUTO is not set ++# CONFIG_ARCH_MVEBU is not set ++# CONFIG_ARCH_BCM is not set ++CONFIG_GPIO_PCA953X=y ++# CONFIG_KEYBOARD_GPIO_POLLED is not set ++# CONFIG_ARCH_HIGHBANK is not set ++# CONFIG_ARCH_MXC is not set ++# CONFIG_ARCH_SOCFPGA is not set ++# CONFIG_ARCH_SUNXI is not set ++CONFIG_ARCH_VEXPRESS=y ++ ++# ++# Versatile Express platform type ++# ++CONFIG_ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA=y ++# CONFIG_ARCH_VEXPRESS_CA9X4 is not set ++CONFIG_PLAT_VERSATILE_CLCD=y ++CONFIG_PLAT_VERSATILE_SCHED_CLOCK=y ++# CONFIG_ARCH_VT8500 is not set ++CONFIG_ARCH_ZYNQ=y ++ ++# ++# Xilinx Specific Options ++# ++CONFIG_XILINX_L1_PREFETCH=y ++CONFIG_XILINX_L2_PREFETCH=y ++CONFIG_DMA_ENGINE=y ++CONFIG_XILINX_AXIPCIE=y ++CONFIG_PLAT_VERSATILE=y ++CONFIG_ARM_TIMER_SP804=y ++ ++# ++# 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_LPAE is not set ++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set ++CONFIG_ARM_THUMB=y ++# CONFIG_ARM_THUMBEE is not set ++# CONFIG_ARM_VIRT_EXT is not set ++CONFIG_SWP_EMULATE=y ++# CONFIG_CPU_ICACHE_DISABLE is not set ++# CONFIG_CPU_DCACHE_DISABLE is not set ++# CONFIG_CPU_BPREDICT_DISABLE is not set ++CONFIG_OUTER_CACHE=y ++CONFIG_OUTER_CACHE_SYNC=y ++CONFIG_MIGHT_HAVE_CACHE_L2X0=y ++CONFIG_CACHE_L2X0=y ++CONFIG_CACHE_PL310=y ++CONFIG_ARM_L1_CACHE_SHIFT_6=y ++CONFIG_ARM_L1_CACHE_SHIFT=6 ++CONFIG_ARM_DMA_MEM_BUFFERABLE=y ++CONFIG_ARM_NR_BANKS=8 ++CONFIG_MULTI_IRQ_HANDLER=y ++# CONFIG_ARM_ERRATA_430973 is not set ++CONFIG_PL310_ERRATA_588369=y ++CONFIG_ARM_ERRATA_720789=y ++CONFIG_PL310_ERRATA_727915=y ++CONFIG_ARM_ERRATA_742230=y ++CONFIG_ARM_ERRATA_742231=y ++CONFIG_ARM_ERRATA_743622=y ++CONFIG_ARM_ERRATA_751472=y ++CONFIG_PL310_ERRATA_753970=y ++CONFIG_ARM_ERRATA_754322=y ++CONFIG_ARM_ERRATA_754327=y ++CONFIG_ARM_ERRATA_764369=y ++CONFIG_PL310_ERRATA_769419=y ++CONFIG_ARM_ERRATA_775420=y ++CONFIG_ARM_GIC=y ++CONFIG_ICST=y ++ ++# ++# Bus support ++# ++CONFIG_ARM_AMBA=y ++CONFIG_PCI=y ++CONFIG_PCI_SYSCALL=y ++CONFIG_ARCH_SUPPORTS_MSI=y ++CONFIG_PCI_MSI=y ++# CONFIG_PCI_DEBUG is not set ++# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set ++# CONFIG_PCI_STUB is not set ++# CONFIG_PCI_IOV is not set ++# CONFIG_PCI_PRI is not set ++# CONFIG_PCI_PASID is not set ++# CONFIG_PCCARD is not set ++ ++# ++# Kernel Features ++# ++CONFIG_HAVE_SMP=y ++CONFIG_SMP=y ++CONFIG_SMP_ON_UP=y ++CONFIG_ARM_CPU_TOPOLOGY=y ++CONFIG_SCHED_MC=y ++CONFIG_SCHED_SMT=y ++CONFIG_HAVE_ARM_SCU=y ++# CONFIG_ARM_ARCH_TIMER is not set ++CONFIG_HAVE_ARM_TWD=y ++CONFIG_VMSPLIT_3G=y ++# CONFIG_VMSPLIT_2G is not set ++# CONFIG_VMSPLIT_1G is not set ++CONFIG_PAGE_OFFSET=0xC0000000 ++CONFIG_NR_CPUS=4 ++CONFIG_HOTPLUG_CPU=y ++CONFIG_LOCAL_TIMERS=y ++CONFIG_ARCH_NR_GPIO=1024 ++# CONFIG_PREEMPT_NONE is not set ++# CONFIG_PREEMPT_VOLUNTARY is not set ++CONFIG_PREEMPT=y ++CONFIG_PREEMPT_COUNT=y ++CONFIG_HZ=100 ++# CONFIG_THUMB2_KERNEL is not set ++CONFIG_AEABI=y ++# CONFIG_OABI_COMPAT is not set ++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set ++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set ++CONFIG_HAVE_ARCH_PFN_VALID=y ++CONFIG_HIGHMEM=y ++# CONFIG_HIGHPTE is not set ++CONFIG_HW_PERF_EVENTS=y ++CONFIG_SELECT_MEMORY_MODEL=y ++CONFIG_FLATMEM_MANUAL=y ++CONFIG_FLATMEM=y ++CONFIG_FLAT_NODE_MEM_MAP=y ++CONFIG_HAVE_MEMBLOCK=y ++CONFIG_MEMORY_ISOLATION=y ++CONFIG_PAGEFLAGS_EXTENDED=y ++CONFIG_SPLIT_PTLOCK_CPUS=4 ++# CONFIG_COMPACTION is not set ++CONFIG_MIGRATION=y ++# CONFIG_PHYS_ADDR_T_64BIT is not set ++CONFIG_ZONE_DMA_FLAG=0 ++CONFIG_BOUNCE=y ++CONFIG_VIRT_TO_BUS=y ++# CONFIG_KSM is not set ++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 ++CONFIG_CROSS_MEMORY_ATTACH=y ++# CONFIG_CLEANCACHE is not set ++# CONFIG_FRONTSWAP is not set ++CONFIG_FORCE_MAX_ZONEORDER=11 ++CONFIG_ALIGNMENT_TRAP=y ++# CONFIG_UACCESS_WITH_MEMCPY is not set ++# CONFIG_SECCOMP is not set ++# CONFIG_CC_STACKPROTECTOR is not set ++# CONFIG_XEN is not set ++ ++# ++# Boot options ++# ++CONFIG_USE_OF=y ++CONFIG_ATAGS=y ++# CONFIG_DEPRECATED_PARAM_STRUCT is not set ++CONFIG_ZBOOT_ROM_TEXT=0x0 ++CONFIG_ZBOOT_ROM_BSS=0x0 ++# CONFIG_ARM_APPENDED_DTB is not set ++CONFIG_CMDLINE="console=ttyPS0,115200n8 root=/dev/ram rw initrd=0x00800000,16M earlyprintk mtdparts=physmap-flash.0:512K(nor-fsbl),512K(nor-u-boot),5M(nor-linux),9M(nor-user),1M(nor-scratch),-(nor-rootfs)" ++CONFIG_CMDLINE_FROM_BOOTLOADER=y ++# CONFIG_CMDLINE_EXTEND is not set ++# CONFIG_CMDLINE_FORCE is not set ++# CONFIG_KEXEC is not set ++# CONFIG_CRASH_DUMP is not set ++CONFIG_AUTO_ZRELADDR=y ++ ++# ++# CPU Power Management ++# ++ ++# ++# CPU Frequency scaling ++# ++CONFIG_CPU_FREQ=y ++CONFIG_CPU_FREQ_TABLE=y ++CONFIG_CPU_FREQ_GOV_COMMON=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 ++ ++# ++# ARM CPU frequency scaling drivers ++# ++# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set ++# CONFIG_ARM_EXYNOS4X12_CPUFREQ is not set ++# CONFIG_ARM_EXYNOS5250_CPUFREQ is not set ++CONFIG_ARM_ZYNQ_CPUFREQ=y ++# CONFIG_CPU_IDLE is not set ++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set ++ ++# ++# 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_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y ++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set ++CONFIG_HAVE_AOUT=y ++# CONFIG_BINFMT_AOUT is not set ++# CONFIG_BINFMT_MISC is not set ++CONFIG_COREDUMP=y ++ ++# ++# Power management options ++# ++# CONFIG_SUSPEND is not set ++CONFIG_PM_RUNTIME=y ++CONFIG_PM=y ++# CONFIG_PM_DEBUG is not set ++# CONFIG_APM_EMULATION is not set ++CONFIG_ARCH_HAS_OPP=y ++CONFIG_PM_OPP=y ++CONFIG_PM_CLK=y ++CONFIG_ARCH_SUSPEND_POSSIBLE=y ++# CONFIG_ARM_CPU_SUSPEND is not set ++CONFIG_NET=y ++ ++# ++# Networking options ++# ++CONFIG_PACKET=y ++# CONFIG_PACKET_DIAG is not set ++CONFIG_UNIX=y ++# CONFIG_UNIX_DIAG is not set ++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_NET_KEY is not set ++CONFIG_INET=y ++CONFIG_IP_MULTICAST=y ++# CONFIG_IP_ADVANCED_ROUTER is not set ++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 is not set ++# CONFIG_IP_MROUTE is not set ++# CONFIG_ARPD is not set ++# CONFIG_SYN_COOKIES is not set ++# CONFIG_NET_IPVTI is not set ++# CONFIG_INET_AH is not set ++# CONFIG_INET_ESP is not set ++# CONFIG_INET_IPCOMP is not set ++# CONFIG_INET_XFRM_TUNNEL is not set ++CONFIG_INET_TUNNEL=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=y ++CONFIG_INET_TCP_DIAG=y ++# CONFIG_INET_UDP_DIAG is not set ++# CONFIG_TCP_CONG_ADVANCED is not set ++CONFIG_TCP_CONG_CUBIC=y ++CONFIG_DEFAULT_TCP_CONG="cubic" ++# CONFIG_TCP_MD5SIG is not set ++CONFIG_IPV6=m ++# CONFIG_IPV6_PRIVACY is not set ++# CONFIG_IPV6_ROUTER_PREF is not set ++# CONFIG_IPV6_OPTIMISTIC_DAD is not set ++# CONFIG_INET6_AH is not set ++# CONFIG_INET6_ESP is not set ++# CONFIG_INET6_IPCOMP is not set ++# CONFIG_IPV6_MIP6 is not set ++# CONFIG_INET6_XFRM_TUNNEL is not set ++# CONFIG_INET6_TUNNEL is not set ++CONFIG_INET6_XFRM_MODE_TRANSPORT=m ++CONFIG_INET6_XFRM_MODE_TUNNEL=m ++CONFIG_INET6_XFRM_MODE_BEET=m ++# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set ++CONFIG_IPV6_SIT=m ++# CONFIG_IPV6_SIT_6RD is not set ++CONFIG_IPV6_NDISC_NODETYPE=y ++# CONFIG_IPV6_TUNNEL is not set ++# CONFIG_IPV6_GRE is not set ++# CONFIG_IPV6_MULTIPLE_TABLES is not set ++# CONFIG_IPV6_MROUTE is not set ++# CONFIG_NETWORK_SECMARK is not set ++# CONFIG_NETWORK_PHY_TIMESTAMPING is not set ++# CONFIG_NETFILTER is not set ++# CONFIG_IP_DCCP is not set ++# CONFIG_IP_SCTP is not set ++# CONFIG_RDS is not set ++# CONFIG_TIPC is not set ++# CONFIG_ATM is not set ++# CONFIG_L2TP is not set ++# CONFIG_BRIDGE is not set ++CONFIG_HAVE_NET_DSA=y ++CONFIG_VLAN_8021Q=m ++# CONFIG_VLAN_8021Q_GVRP is not set ++# CONFIG_DECNET is not set ++# 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_WAN_ROUTER is not set ++# CONFIG_PHONET is not set ++# CONFIG_IEEE802154 is not set ++# CONFIG_NET_SCHED is not set ++# CONFIG_DCB is not set ++# CONFIG_BATMAN_ADV is not set ++# CONFIG_OPENVSWITCH is not set ++CONFIG_RPS=y ++CONFIG_RFS_ACCEL=y ++CONFIG_XPS=y ++CONFIG_BQL=y ++# CONFIG_BPF_JIT is not set ++ ++# ++# Network testing ++# ++# CONFIG_NET_PKTGEN is not set ++# CONFIG_HAMRADIO is not set ++# CONFIG_CAN is not set ++# CONFIG_IRDA is not set ++# CONFIG_BT is not set ++# CONFIG_AF_RXRPC is not set ++CONFIG_WIRELESS=y ++# CONFIG_CFG80211 is not set ++# CONFIG_LIB80211 is not set ++ ++# ++# CFG80211 needs to be enabled for MAC80211 ++# ++# CONFIG_WIMAX is not set ++# CONFIG_RFKILL is not set ++# CONFIG_NET_9P is not set ++# CONFIG_CAIF is not set ++# CONFIG_CEPH_LIB is not set ++# CONFIG_NFC is not set ++CONFIG_HAVE_BPF_JIT=y ++ ++# ++# Device Drivers ++# ++ ++# ++# Generic Driver Options ++# ++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" ++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_GENERIC_CPU_DEVICES is not set ++# CONFIG_DMA_SHARED_BUFFER is not set ++CONFIG_CMA=y ++# CONFIG_CMA_DEBUG is not set ++ ++# ++# Default contiguous memory area size: ++# ++CONFIG_CMA_SIZE_MBYTES=16 ++CONFIG_CMA_SIZE_SEL_MBYTES=y ++# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set ++# CONFIG_CMA_SIZE_SEL_MIN is not set ++# CONFIG_CMA_SIZE_SEL_MAX is not set ++CONFIG_CMA_ALIGNMENT=8 ++CONFIG_CMA_AREAS=7 ++ ++# ++# Bus devices ++# ++CONFIG_CONNECTOR=y ++CONFIG_PROC_EVENTS=y ++CONFIG_MTD=y ++# CONFIG_MTD_TESTS is not set ++# CONFIG_MTD_REDBOOT_PARTS is not set ++CONFIG_MTD_CMDLINE_PARTS=y ++# CONFIG_MTD_AFS_PARTS is not set ++CONFIG_MTD_OF_PARTS=y ++# CONFIG_MTD_AR7_PARTS is not set ++ ++# ++# User Modules And Translation Layers ++# ++CONFIG_MTD_CHAR=y ++CONFIG_MTD_BLKDEVS=y ++CONFIG_MTD_BLOCK=y ++# CONFIG_FTL is not set ++# CONFIG_NFTL is not set ++# CONFIG_INFTL is not set ++# CONFIG_RFD_FTL is not set ++# CONFIG_SSFDC is not set ++# CONFIG_SM_FTL is not set ++# CONFIG_MTD_OOPS is not set ++# CONFIG_MTD_SWAP is not set ++ ++# ++# RAM/ROM/Flash chip drivers ++# ++CONFIG_MTD_CFI=y ++# CONFIG_MTD_JEDECPROBE is not set ++CONFIG_MTD_GEN_PROBE=y ++# CONFIG_MTD_CFI_ADV_OPTIONS is not set ++CONFIG_MTD_MAP_BANK_WIDTH_1=y ++CONFIG_MTD_MAP_BANK_WIDTH_2=y ++CONFIG_MTD_MAP_BANK_WIDTH_4=y ++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set ++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set ++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set ++CONFIG_MTD_CFI_I1=y ++CONFIG_MTD_CFI_I2=y ++# CONFIG_MTD_CFI_I4 is not set ++# CONFIG_MTD_CFI_I8 is not set ++# CONFIG_MTD_CFI_INTELEXT is not set ++CONFIG_MTD_CFI_AMDSTD=y ++# CONFIG_MTD_CFI_STAA is not set ++CONFIG_MTD_CFI_UTIL=y ++# 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_PHYSMAP=y ++# CONFIG_MTD_PHYSMAP_COMPAT is not set ++CONFIG_MTD_PHYSMAP_OF=y ++# CONFIG_MTD_INTEL_VR_NOR is not set ++# CONFIG_MTD_PLATRAM is not set ++ ++# ++# Self-contained MTD device drivers ++# ++# CONFIG_MTD_PMC551 is not set ++# CONFIG_MTD_DATAFLASH is not set ++CONFIG_MTD_M25P80=y ++# CONFIG_M25PXX_USE_FAST_READ 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_DOCG3 is not set ++CONFIG_MTD_NAND_ECC=y ++# CONFIG_MTD_NAND_ECC_SMC is not set ++CONFIG_MTD_NAND=y ++# 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_DENALI is not set ++# CONFIG_MTD_NAND_GPIO is not set ++CONFIG_MTD_NAND_IDS=y ++# CONFIG_MTD_NAND_RICOH is not set ++# CONFIG_MTD_NAND_DISKONCHIP is not set ++# CONFIG_MTD_NAND_DOCG4 is not set ++# CONFIG_MTD_NAND_CAFE is not set ++# CONFIG_MTD_NAND_NANDSIM is not set ++# CONFIG_MTD_NAND_PLATFORM is not set ++# CONFIG_MTD_ALAUDA is not set ++CONFIG_MTD_NAND_XILINX_PS=y ++# CONFIG_MTD_ONENAND is not set ++ ++# ++# LPDDR flash memory drivers ++# ++# CONFIG_MTD_LPDDR is not set ++# CONFIG_MTD_UBI is not set ++CONFIG_DTC=y ++CONFIG_OF=y ++ ++# ++# Device Tree and Open Firmware support ++# ++CONFIG_PROC_DEVICETREE=y ++# CONFIG_OF_SELFTEST is not set ++CONFIG_OF_FLATTREE=y ++CONFIG_OF_EARLY_FLATTREE=y ++CONFIG_OF_ADDRESS=y ++CONFIG_OF_IRQ=y ++CONFIG_OF_DEVICE=y ++CONFIG_OF_I2C=y ++CONFIG_OF_NET=y ++CONFIG_OF_MDIO=y ++CONFIG_OF_PCI=y ++CONFIG_OF_PCI_IRQ=y ++CONFIG_OF_MTD=y ++# CONFIG_PARPORT is not set ++CONFIG_BLK_DEV=y ++# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set ++# CONFIG_BLK_CPQ_DA is not set ++# CONFIG_BLK_CPQ_CISS_DA is not set ++# CONFIG_BLK_DEV_DAC960 is not set ++# CONFIG_BLK_DEV_UMEM is not set ++# CONFIG_BLK_DEV_COW_COMMON is not set ++CONFIG_BLK_DEV_LOOP=y ++CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 ++# CONFIG_BLK_DEV_CRYPTOLOOP is not set ++# CONFIG_BLK_DEV_DRBD is not set ++# CONFIG_BLK_DEV_NBD is not set ++# CONFIG_BLK_DEV_NVME is not set ++# CONFIG_BLK_DEV_SX8 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 is not set ++# CONFIG_ATA_OVER_ETH is not set ++# CONFIG_MG_DISK is not set ++# CONFIG_VIRTIO_BLK is not set ++# CONFIG_BLK_DEV_RBD is not set ++ ++# ++# Misc devices ++# ++# CONFIG_SENSORS_LIS3LV02D is not set ++# CONFIG_AD525X_DPOT is not set ++# CONFIG_ATMEL_PWM is not set ++# CONFIG_PHANTOM is not set ++# CONFIG_INTEL_MID_PTI is not set ++# CONFIG_SGI_IOC4 is not set ++# CONFIG_TIFM_CORE is not set ++# CONFIG_ICS932S401 is not set ++# CONFIG_ENCLOSURE_SERVICES is not set ++# CONFIG_HP_ILO is not set ++# CONFIG_APDS9802ALS is not set ++# CONFIG_ISL29003 is not set ++# CONFIG_ISL29020 is not set ++# CONFIG_SENSORS_TSL2550 is not set ++# CONFIG_SENSORS_BH1780 is not set ++# CONFIG_SENSORS_BH1770 is not set ++# CONFIG_SENSORS_APDS990X is not set ++# CONFIG_HMC6352 is not set ++# CONFIG_DS1682 is not set ++# CONFIG_TI_DAC7512 is not set ++# CONFIG_ARM_CHARLCD is not set ++# CONFIG_BMP085_I2C is not set ++# CONFIG_BMP085_SPI is not set ++# CONFIG_PCH_PHUB is not set ++# CONFIG_USB_SWITCH_FSA9480 is not set ++CONFIG_SI570=y ++# CONFIG_C2PORT is not set ++ ++# ++# EEPROM support ++# ++CONFIG_EEPROM_AT24=y ++CONFIG_EEPROM_AT25=y ++# CONFIG_EEPROM_LEGACY is not set ++# CONFIG_EEPROM_MAX6875 is not set ++# CONFIG_EEPROM_93CX6 is not set ++# CONFIG_EEPROM_93XX46 is not set ++# CONFIG_CB710_CORE is not set ++ ++# ++# Texas Instruments shared transport line discipline ++# ++# CONFIG_TI_ST is not set ++# CONFIG_SENSORS_LIS3_SPI is not set ++# CONFIG_SENSORS_LIS3_I2C is not set ++ ++# ++# Altera FPGA firmware download module ++# ++# CONFIG_ALTERA_STAPL is not set ++CONFIG_HAVE_IDE=y ++# CONFIG_IDE is not set ++ ++# ++# SCSI device support ++# ++CONFIG_SCSI_MOD=y ++# CONFIG_RAID_ATTRS is not set ++CONFIG_SCSI=y ++CONFIG_SCSI_DMA=y ++# CONFIG_SCSI_TGT is not set ++# CONFIG_SCSI_NETLINK is not set ++CONFIG_SCSI_PROC_FS=y ++ ++# ++# SCSI support type (disk, tape, CD-ROM) ++# ++CONFIG_BLK_DEV_SD=y ++# CONFIG_CHR_DEV_ST is not set ++# CONFIG_CHR_DEV_OSST is not set ++# CONFIG_BLK_DEV_SR is not set ++CONFIG_CHR_DEV_SG=y ++# CONFIG_CHR_DEV_SCH is not set ++CONFIG_SCSI_MULTI_LUN=y ++# CONFIG_SCSI_CONSTANTS is not set ++# CONFIG_SCSI_LOGGING is not set ++# CONFIG_SCSI_SCAN_ASYNC is not set ++ ++# ++# SCSI Transports ++# ++# CONFIG_SCSI_SPI_ATTRS is not set ++# CONFIG_SCSI_FC_ATTRS is not set ++# CONFIG_SCSI_ISCSI_ATTRS is not set ++# CONFIG_SCSI_SAS_ATTRS is not set ++# CONFIG_SCSI_SAS_LIBSAS is not set ++# CONFIG_SCSI_SRP_ATTRS is not set ++CONFIG_SCSI_LOWLEVEL=y ++# CONFIG_ISCSI_TCP is not set ++# CONFIG_ISCSI_BOOT_SYSFS is not set ++# CONFIG_SCSI_CXGB3_ISCSI is not set ++# CONFIG_SCSI_CXGB4_ISCSI is not set ++# CONFIG_SCSI_BNX2_ISCSI is not set ++# CONFIG_SCSI_BNX2X_FCOE is not set ++# CONFIG_BE2ISCSI is not set ++# CONFIG_BLK_DEV_3W_XXXX_RAID is not set ++# CONFIG_SCSI_HPSA is not set ++# CONFIG_SCSI_3W_9XXX is not set ++# CONFIG_SCSI_3W_SAS is not set ++# CONFIG_SCSI_ACARD is not set ++# CONFIG_SCSI_AACRAID is not set ++# CONFIG_SCSI_AIC7XXX is not set ++# CONFIG_SCSI_AIC7XXX_OLD is not set ++# CONFIG_SCSI_AIC79XX is not set ++# CONFIG_SCSI_AIC94XX is not set ++# CONFIG_SCSI_MVSAS is not set ++# CONFIG_SCSI_MVUMI is not set ++# CONFIG_SCSI_DPT_I2O is not set ++# CONFIG_SCSI_ADVANSYS is not set ++# CONFIG_SCSI_ARCMSR is not set ++# CONFIG_MEGARAID_NEWGEN is not set ++# CONFIG_MEGARAID_LEGACY is not set ++# CONFIG_MEGARAID_SAS is not set ++# CONFIG_SCSI_MPT2SAS is not set ++# CONFIG_SCSI_MPT3SAS is not set ++# CONFIG_SCSI_UFSHCD is not set ++# CONFIG_SCSI_HPTIOP is not set ++# CONFIG_LIBFC is not set ++# CONFIG_LIBFCOE is not set ++# CONFIG_FCOE is not set ++# CONFIG_SCSI_DMX3191D is not set ++# CONFIG_SCSI_FUTURE_DOMAIN is not set ++# CONFIG_SCSI_IPS is not set ++# CONFIG_SCSI_INITIO is not set ++# CONFIG_SCSI_INIA100 is not set ++# CONFIG_SCSI_STEX is not set ++# CONFIG_SCSI_SYM53C8XX_2 is not set ++# CONFIG_SCSI_QLOGIC_1280 is not set ++# CONFIG_SCSI_QLA_FC is not set ++# CONFIG_SCSI_QLA_ISCSI is not set ++# CONFIG_SCSI_LPFC is not set ++# CONFIG_SCSI_DC395x is not set ++# CONFIG_SCSI_DC390T is not set ++# CONFIG_SCSI_NSP32 is not set ++# CONFIG_SCSI_DEBUG is not set ++# CONFIG_SCSI_PMCRAID is not set ++# CONFIG_SCSI_PM8001 is not set ++# CONFIG_SCSI_SRP is not set ++# CONFIG_SCSI_BFA_FC is not set ++# CONFIG_SCSI_VIRTIO is not set ++# CONFIG_SCSI_CHELSIO_FCOE is not set ++# CONFIG_SCSI_DH is not set ++# CONFIG_SCSI_OSD_INITIATOR is not set ++CONFIG_HAVE_PATA_PLATFORM=y ++# CONFIG_ATA is not set ++# CONFIG_MD is not set ++# CONFIG_TARGET_CORE is not set ++# CONFIG_FUSION is not set ++ ++# ++# IEEE 1394 (FireWire) support ++# ++# CONFIG_FIREWIRE is not set ++# CONFIG_FIREWIRE_NOSY is not set ++# CONFIG_I2O is not set ++CONFIG_NETDEVICES=y ++CONFIG_NET_CORE=y ++# CONFIG_BONDING is not set ++# CONFIG_DUMMY is not set ++# CONFIG_EQUALIZER is not set ++# CONFIG_NET_FC is not set ++CONFIG_MII=y ++# CONFIG_NET_TEAM is not set ++# CONFIG_MACVLAN is not set ++# CONFIG_VXLAN is not set ++# CONFIG_NETCONSOLE is not set ++# CONFIG_NETPOLL is not set ++# CONFIG_NET_POLL_CONTROLLER is not set ++# CONFIG_TUN is not set ++# CONFIG_VETH is not set ++# CONFIG_VIRTIO_NET is not set ++# CONFIG_ARCNET is not set ++ ++# ++# CAIF transport drivers ++# ++ ++# ++# Distributed Switch Architecture drivers ++# ++# CONFIG_NET_DSA_MV88E6XXX is not set ++# CONFIG_NET_DSA_MV88E6060 is not set ++# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set ++# CONFIG_NET_DSA_MV88E6131 is not set ++# CONFIG_NET_DSA_MV88E6123_61_65 is not set ++CONFIG_ETHERNET=y ++# CONFIG_NET_VENDOR_3COM is not set ++# CONFIG_NET_VENDOR_ADAPTEC is not set ++# CONFIG_NET_VENDOR_ALTEON is not set ++# CONFIG_NET_VENDOR_AMD is not set ++# CONFIG_NET_VENDOR_ATHEROS is not set ++CONFIG_NET_CADENCE=y ++# CONFIG_ARM_AT91_ETHER is not set ++# CONFIG_MACB is not set ++CONFIG_NET_VENDOR_BROADCOM=y ++# CONFIG_B44 is not set ++# CONFIG_BNX2 is not set ++# CONFIG_CNIC is not set ++CONFIG_TIGON3=y ++# CONFIG_BNX2X is not set ++# CONFIG_NET_VENDOR_BROCADE is not set ++# CONFIG_NET_CALXEDA_XGMAC is not set ++# CONFIG_NET_VENDOR_CHELSIO is not set ++# CONFIG_NET_VENDOR_CIRRUS is not set ++# CONFIG_NET_VENDOR_CISCO is not set ++# CONFIG_DM9000 is not set ++# CONFIG_DNET is not set ++# CONFIG_NET_VENDOR_DEC is not set ++# CONFIG_NET_VENDOR_DLINK is not set ++# CONFIG_NET_VENDOR_EMULEX is not set ++# CONFIG_NET_VENDOR_EXAR is not set ++# CONFIG_NET_VENDOR_FARADAY is not set ++# CONFIG_NET_VENDOR_HP is not set ++CONFIG_NET_VENDOR_INTEL=y ++# CONFIG_E100 is not set ++# CONFIG_E1000 is not set ++CONFIG_E1000E=y ++# CONFIG_IGB is not set ++# CONFIG_IGBVF is not set ++# CONFIG_IXGB is not set ++# CONFIG_IXGBE is not set ++# CONFIG_IXGBEVF is not set ++CONFIG_NET_VENDOR_I825XX=y ++# CONFIG_IP1000 is not set ++# CONFIG_JME is not set ++# CONFIG_NET_VENDOR_MARVELL is not set ++# CONFIG_NET_VENDOR_MELLANOX is not set ++# CONFIG_NET_VENDOR_MICREL is not set ++# CONFIG_NET_VENDOR_MICROCHIP is not set ++# CONFIG_NET_VENDOR_MYRI is not set ++# CONFIG_FEALNX is not set ++# CONFIG_NET_VENDOR_NATSEMI is not set ++# CONFIG_NET_VENDOR_NVIDIA is not set ++# CONFIG_NET_VENDOR_OKI is not set ++# CONFIG_ETHOC is not set ++# CONFIG_NET_PACKET_ENGINE is not set ++# CONFIG_NET_VENDOR_QLOGIC is not set ++CONFIG_NET_VENDOR_REALTEK=y ++# CONFIG_8139CP is not set ++# CONFIG_8139TOO is not set ++CONFIG_R8169=y ++# CONFIG_NET_VENDOR_RDC is not set ++# CONFIG_NET_VENDOR_SEEQ is not set ++# CONFIG_NET_VENDOR_SILAN is not set ++# CONFIG_NET_VENDOR_SIS is not set ++# CONFIG_SFC is not set ++# CONFIG_NET_VENDOR_SMSC is not set ++# CONFIG_NET_VENDOR_STMICRO is not set ++# CONFIG_NET_VENDOR_SUN is not set ++# CONFIG_NET_VENDOR_TEHUTI is not set ++# CONFIG_NET_VENDOR_TI is not set ++# CONFIG_NET_VENDOR_VIA is not set ++# CONFIG_NET_VENDOR_WIZNET is not set ++CONFIG_NET_VENDOR_XILINX=y ++CONFIG_XILINX_EMACLITE=y ++CONFIG_XILINX_AXI_EMAC=y ++CONFIG_XILINX_PS_EMAC=y ++# CONFIG_XILINX_PS_EMAC_HWTSTAMP is not set ++# CONFIG_FDDI is not set ++# CONFIG_HIPPI is not set ++CONFIG_PHYLIB=y ++ ++# ++# MII PHY device drivers ++# ++# CONFIG_AT803X_PHY is not set ++# CONFIG_AMD_PHY is not set ++CONFIG_MARVELL_PHY=y ++# 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=y ++# CONFIG_SMSC_PHY is not set ++# CONFIG_BROADCOM_PHY is not set ++# CONFIG_BCM87XX_PHY is not set ++# 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 is not set ++# CONFIG_FIXED_PHY is not set ++CONFIG_MDIO_BITBANG=y ++# CONFIG_MDIO_GPIO is not set ++# CONFIG_MDIO_BUS_MUX_GPIO is not set ++# CONFIG_MDIO_BUS_MUX_MMIOREG is not set ++# CONFIG_MICREL_KS8995MA is not set ++# CONFIG_PPP is not set ++# CONFIG_SLIP is not set ++ ++# ++# USB Network Adapters ++# ++# CONFIG_USB_CATC is not set ++# CONFIG_USB_KAWETH is not set ++# CONFIG_USB_PEGASUS is not set ++# CONFIG_USB_RTL8150 is not set ++# CONFIG_USB_USBNET is not set ++# CONFIG_USB_IPHETH is not set ++CONFIG_WLAN=y ++# CONFIG_ATMEL is not set ++# CONFIG_PRISM54 is not set ++# CONFIG_USB_ZD1201 is not set ++# CONFIG_HOSTAP is not set ++# CONFIG_WL_TI is not set ++ ++# ++# Enable WiMAX (Networking options) to see the WiMAX drivers ++# ++# CONFIG_WAN is not set ++# CONFIG_VMXNET3 is not set ++# CONFIG_ISDN is not set ++ ++# ++# Input device support ++# ++CONFIG_INPUT=y ++# CONFIG_INPUT_FF_MEMLESS is not set ++# CONFIG_INPUT_POLLDEV is not set ++CONFIG_INPUT_SPARSEKMAP=y ++# CONFIG_INPUT_MATRIXKMAP 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=y ++ ++# ++# Input Device Drivers ++# ++CONFIG_INPUT_KEYBOARD=y ++# CONFIG_KEYBOARD_ADP5588 is not set ++# CONFIG_KEYBOARD_ADP5589 is not set ++CONFIG_KEYBOARD_ATKBD=y ++# CONFIG_KEYBOARD_QT1070 is not set ++# CONFIG_KEYBOARD_QT2160 is not set ++# CONFIG_KEYBOARD_LKKBD is not set ++# CONFIG_KEYBOARD_GPIO is not set ++# CONFIG_KEYBOARD_TCA6416 is not set ++# CONFIG_KEYBOARD_TCA8418 is not set ++# CONFIG_KEYBOARD_MATRIX is not set ++# CONFIG_KEYBOARD_LM8333 is not set ++# CONFIG_KEYBOARD_MAX7359 is not set ++# CONFIG_KEYBOARD_MCS is not set ++# CONFIG_KEYBOARD_MPR121 is not set ++# CONFIG_KEYBOARD_NEWTON is not set ++# CONFIG_KEYBOARD_OPENCORES is not set ++# CONFIG_KEYBOARD_SAMSUNG is not set ++# CONFIG_KEYBOARD_STOWAWAY is not set ++# CONFIG_KEYBOARD_SUNKBD 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_MOUSE_SYNAPTICS_USB is not set ++# CONFIG_INPUT_JOYSTICK is not set ++# CONFIG_INPUT_TABLET is not set ++# CONFIG_INPUT_TOUCHSCREEN is not set ++# CONFIG_INPUT_MISC is not set ++ ++# ++# Hardware I/O ports ++# ++CONFIG_SERIO=y ++CONFIG_SERIO_SERPORT=y ++# CONFIG_SERIO_AMBAKMI is not set ++# CONFIG_SERIO_PCIPS2 is not set ++CONFIG_SERIO_LIBPS2=y ++# CONFIG_SERIO_RAW is not set ++# CONFIG_SERIO_ALTERA_PS2 is not set ++# CONFIG_SERIO_PS2MULT is not set ++# CONFIG_SERIO_ARC_PS2 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_NOZOMI is not set ++# CONFIG_N_GSM is not set ++# CONFIG_TRACE_SINK is not set ++# CONFIG_DEVKMEM is not set ++ ++# ++# Serial drivers ++# ++# CONFIG_SERIAL_8250 is not set ++ ++# ++# Non-8250 serial port support ++# ++# CONFIG_SERIAL_AMBA_PL010 is not set ++# CONFIG_SERIAL_AMBA_PL011 is not set ++# CONFIG_SERIAL_MAX3100 is not set ++# CONFIG_SERIAL_MAX310X is not set ++# CONFIG_SERIAL_MFD_HSU is not set ++# CONFIG_SERIAL_UARTLITE is not set ++CONFIG_SERIAL_CORE=y ++CONFIG_SERIAL_CORE_CONSOLE=y ++# CONFIG_SERIAL_JSM is not set ++# CONFIG_SERIAL_SCCNXP is not set ++# CONFIG_SERIAL_TIMBERDALE is not set ++# CONFIG_SERIAL_ALTERA_JTAGUART is not set ++# CONFIG_SERIAL_ALTERA_UART is not set ++# CONFIG_SERIAL_IFX6X60 is not set ++# CONFIG_SERIAL_PCH_UART is not set ++CONFIG_SERIAL_XILINX_PS_UART=y ++CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y ++# CONFIG_SERIAL_ARC is not set ++# CONFIG_TTY_PRINTK is not set ++# CONFIG_HVC_DCC is not set ++# CONFIG_VIRTIO_CONSOLE is not set ++# CONFIG_IPMI_HANDLER is not set ++# CONFIG_HW_RANDOM is not set ++CONFIG_XILINX_DEVCFG=y ++# CONFIG_R3964 is not set ++# CONFIG_APPLICOM is not set ++# CONFIG_RAW_DRIVER is not set ++# CONFIG_TCG_TPM is not set ++CONFIG_DEVPORT=y ++CONFIG_I2C=y ++CONFIG_I2C_BOARDINFO=y ++CONFIG_I2C_COMPAT=y ++CONFIG_I2C_CHARDEV=y ++CONFIG_I2C_MUX=y ++ ++# ++# Multiplexer I2C Chip support ++# ++# CONFIG_I2C_MUX_GPIO is not set ++# CONFIG_I2C_MUX_PCA9541 is not set ++CONFIG_I2C_MUX_PCA954x=y ++CONFIG_I2C_HELPER_AUTO=y ++CONFIG_I2C_ALGOBIT=m ++ ++# ++# I2C Hardware Bus support ++# ++ ++# ++# PC SMBus host controller drivers ++# ++# CONFIG_I2C_ALI1535 is not set ++# CONFIG_I2C_ALI1563 is not set ++# CONFIG_I2C_ALI15X3 is not set ++# CONFIG_I2C_AMD756 is not set ++# CONFIG_I2C_AMD8111 is not set ++# CONFIG_I2C_I801 is not set ++# CONFIG_I2C_ISCH is not set ++# CONFIG_I2C_PIIX4 is not set ++# CONFIG_I2C_NFORCE2 is not set ++# CONFIG_I2C_SIS5595 is not set ++# CONFIG_I2C_SIS630 is not set ++# CONFIG_I2C_SIS96X is not set ++# CONFIG_I2C_VIA is not set ++# CONFIG_I2C_VIAPRO is not set ++ ++# ++# I2C system bus drivers (mostly embedded / system-on-chip) ++# ++# CONFIG_I2C_CBUS_GPIO is not set ++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set ++# CONFIG_I2C_DESIGNWARE_PCI is not set ++# CONFIG_I2C_EG20T is not set ++# CONFIG_I2C_GPIO is not set ++# CONFIG_I2C_INTEL_MID is not set ++# CONFIG_I2C_NOMADIK is not set ++# CONFIG_I2C_OCORES is not set ++# CONFIG_I2C_PCA_PLATFORM is not set ++# CONFIG_I2C_PXA_PCI is not set ++# CONFIG_I2C_SIMTEC is not set ++# CONFIG_I2C_VERSATILE is not set ++CONFIG_I2C_XILINX_PS=y ++# CONFIG_I2C_XILINX is not set ++ ++# ++# External I2C/SMBus adapter drivers ++# ++# CONFIG_I2C_DIOLAN_U2C is not set ++# 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_PL022 is not set ++# CONFIG_SPI_PXA2XX_PCI is not set ++# CONFIG_SPI_SC18IS602 is not set ++# CONFIG_SPI_TOPCLIFF_PCH is not set ++# CONFIG_SPI_XCOMM is not set ++# CONFIG_SPI_XILINX is not set ++CONFIG_SPI_XILINX_PS_QSPI=y ++CONFIG_SPI_XILINX_PS_SPI=y ++# CONFIG_SPI_DESIGNWARE is not set ++ ++# ++# SPI Protocol Masters ++# ++# CONFIG_SPI_SPIDEV is not set ++# CONFIG_SPI_TLE62X0 is not set ++# CONFIG_HSI is not set ++ ++# ++# PPS support ++# ++CONFIG_PPS=y ++# CONFIG_PPS_DEBUG is not set ++ ++# ++# PPS clients support ++# ++# CONFIG_PPS_CLIENT_KTIMER is not set ++# CONFIG_PPS_CLIENT_LDISC is not set ++# CONFIG_PPS_CLIENT_GPIO is not set ++ ++# ++# PPS generators support ++# ++ ++# ++# PTP clock support ++# ++CONFIG_PTP_1588_CLOCK=y ++ ++# ++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. ++# ++# CONFIG_PTP_1588_CLOCK_PCH is not set ++CONFIG_ARCH_REQUIRE_GPIOLIB=y ++CONFIG_GPIOLIB=y ++CONFIG_OF_GPIO=y ++# CONFIG_DEBUG_GPIO is not set ++CONFIG_GPIO_SYSFS=y ++ ++# ++# Memory mapped GPIO drivers: ++# ++# CONFIG_GPIO_GENERIC_PLATFORM is not set ++# CONFIG_GPIO_EM is not set ++# CONFIG_GPIO_PL061 is not set ++# CONFIG_GPIO_TS5500 is not set ++# CONFIG_GPIO_XILINX is not set ++CONFIG_GPIO_XILINX_PS=y ++# CONFIG_GPIO_VX855 is not set ++ ++# ++# I2C GPIO expanders: ++# ++# CONFIG_GPIO_MAX7300 is not set ++# CONFIG_GPIO_MAX732X is not set ++# CONFIG_GPIO_PCA953X_IRQ is not set ++# CONFIG_GPIO_PCF857X is not set ++# CONFIG_GPIO_SX150X is not set ++# CONFIG_GPIO_ADP5588 is not set ++# CONFIG_GPIO_ADNP is not set ++ ++# ++# PCI GPIO expanders: ++# ++# CONFIG_GPIO_BT8XX is not set ++# CONFIG_GPIO_AMD8111 is not set ++# CONFIG_GPIO_ML_IOH is not set ++# CONFIG_GPIO_RDC321X is not set ++ ++# ++# 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: ++# ++ ++# ++# USB GPIO expanders: ++# ++# CONFIG_W1 is not set ++# CONFIG_POWER_SUPPLY is not set ++# CONFIG_POWER_AVS is not set ++CONFIG_HWMON=y ++# CONFIG_HWMON_VID is not set ++# CONFIG_HWMON_DEBUG_CHIP is not set ++ ++# ++# Native drivers ++# ++# CONFIG_SENSORS_AD7314 is not set ++# 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_ADT7410 is not set ++# CONFIG_SENSORS_ADT7411 is not set ++# CONFIG_SENSORS_ADT7462 is not set ++# CONFIG_SENSORS_ADT7470 is not set ++# CONFIG_SENSORS_ADT7475 is not set ++# CONFIG_SENSORS_ASC7621 is not set ++# CONFIG_SENSORS_ATXP1 is not set ++# CONFIG_SENSORS_DS620 is not set ++# CONFIG_SENSORS_DS1621 is not set ++# CONFIG_SENSORS_I5K_AMB 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 is not set ++# CONFIG_SENSORS_HIH6130 is not set ++# CONFIG_SENSORS_IT87 is not set ++# CONFIG_SENSORS_JC42 is not set ++# 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_LM95245 is not set ++# CONFIG_SENSORS_MAX1111 is not set ++# CONFIG_SENSORS_MAX16065 is not set ++# CONFIG_SENSORS_MAX1619 is not set ++# CONFIG_SENSORS_MAX1668 is not set ++# CONFIG_SENSORS_MAX197 is not set ++# CONFIG_SENSORS_MAX6639 is not set ++# CONFIG_SENSORS_MAX6642 is not set ++# CONFIG_SENSORS_MAX6650 is not set ++# CONFIG_SENSORS_MCP3021 is not set ++# CONFIG_SENSORS_NTC_THERMISTOR 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_SIS5595 is not set ++# CONFIG_SENSORS_SMM665 is not set ++# CONFIG_SENSORS_DME1737 is not set ++# CONFIG_SENSORS_EMC1403 is not set ++# CONFIG_SENSORS_EMC2103 is not set ++# CONFIG_SENSORS_EMC6W201 is not set ++# CONFIG_SENSORS_SMSC47M1 is not set ++# CONFIG_SENSORS_SMSC47M192 is not set ++# CONFIG_SENSORS_SMSC47B397 is not set ++# CONFIG_SENSORS_SCH56XX_COMMON is not set ++# CONFIG_SENSORS_SCH5627 is not set ++# CONFIG_SENSORS_SCH5636 is not set ++# CONFIG_SENSORS_ADS1015 is not set ++# CONFIG_SENSORS_ADS7828 is not set ++# CONFIG_SENSORS_ADS7871 is not set ++# CONFIG_SENSORS_AMC6821 is not set ++# CONFIG_SENSORS_INA2XX is not set ++# CONFIG_SENSORS_THMC50 is not set ++# CONFIG_SENSORS_TMP102 is not set ++# CONFIG_SENSORS_TMP401 is not set ++# CONFIG_SENSORS_TMP421 is not set ++# CONFIG_SENSORS_VEXPRESS is not set ++# CONFIG_SENSORS_VIA686A is not set ++# CONFIG_SENSORS_VT1211 is not set ++# CONFIG_SENSORS_VT8231 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_SENSORS_XADCPS=y ++# CONFIG_THERMAL is not set ++CONFIG_WATCHDOG=y ++CONFIG_WATCHDOG_CORE=y ++# CONFIG_WATCHDOG_NOWAYOUT is not set ++ ++# ++# Watchdog Device Drivers ++# ++# CONFIG_SOFT_WATCHDOG is not set ++# CONFIG_ARM_SP805_WATCHDOG is not set ++# CONFIG_DW_WATCHDOG is not set ++CONFIG_MPCORE_WATCHDOG=y ++CONFIG_XILINX_PS_WATCHDOG=y ++# CONFIG_MAX63XX_WATCHDOG is not set ++# CONFIG_ALIM7101_WDT is not set ++# CONFIG_I6300ESB_WDT is not set ++ ++# ++# PCI-based Watchdog Cards ++# ++# CONFIG_PCIPCWATCHDOG is not set ++# CONFIG_WDTPCI is not set ++ ++# ++# USB-based Watchdog Cards ++# ++# CONFIG_USBPCWATCHDOG is not set ++CONFIG_SSB_POSSIBLE=y ++ ++# ++# Sonics Silicon Backplane ++# ++# CONFIG_SSB is not set ++CONFIG_BCMA_POSSIBLE=y ++ ++# ++# Broadcom specific AMBA ++# ++# CONFIG_BCMA is not set ++ ++# ++# Multifunction device drivers ++# ++# CONFIG_MFD_CORE is not set ++# CONFIG_MFD_88PM860X is not set ++# CONFIG_MFD_88PM800 is not set ++# CONFIG_MFD_88PM805 is not set ++# CONFIG_MFD_SM501 is not set ++# CONFIG_MFD_RTSX_PCI is not set ++# CONFIG_MFD_ASIC3 is not set ++# CONFIG_MFD_TI_AM335X_TSCADC is not set ++# CONFIG_HTC_EGPIO is not set ++# CONFIG_HTC_PASIC3 is not set ++# CONFIG_HTC_I2CPLD is not set ++# CONFIG_MFD_LM3533 is not set ++# CONFIG_TPS6105X is not set ++# CONFIG_TPS65010 is not set ++# CONFIG_TPS6507X is not set ++# CONFIG_MFD_TPS65217 is not set ++# CONFIG_MFD_TPS6586X is not set ++# CONFIG_MFD_TPS65910 is not set ++# CONFIG_MFD_TPS65912_I2C is not set ++# CONFIG_MFD_TPS65912_SPI is not set ++# CONFIG_MFD_TPS80031 is not set ++# CONFIG_TWL4030_CORE is not set ++# CONFIG_TWL6040_CORE is not set ++# 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_SMSC is not set ++# CONFIG_MFD_TC6387XB is not set ++# CONFIG_MFD_TC6393XB is not set ++# CONFIG_PMIC_DA903X is not set ++# CONFIG_MFD_DA9052_SPI is not set ++# CONFIG_MFD_DA9052_I2C is not set ++# CONFIG_MFD_DA9055 is not set ++# CONFIG_PMIC_ADP5520 is not set ++# CONFIG_MFD_LP8788 is not set ++# CONFIG_MFD_MAX77686 is not set ++# CONFIG_MFD_MAX77693 is not set ++# CONFIG_MFD_MAX8907 is not set ++# CONFIG_MFD_MAX8925 is not set ++# CONFIG_MFD_MAX8997 is not set ++# CONFIG_MFD_MAX8998 is not set ++# CONFIG_MFD_SEC_CORE is not set ++# CONFIG_MFD_ARIZONA_I2C is not set ++# CONFIG_MFD_ARIZONA_SPI 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_SPI is not set ++# CONFIG_MFD_MC13XXX_I2C is not set ++# CONFIG_ABX500_CORE is not set ++# CONFIG_EZX_PCAP is not set ++# CONFIG_MFD_TIMBERDALE is not set ++# CONFIG_LPC_SCH is not set ++# CONFIG_LPC_ICH is not set ++# CONFIG_MFD_RDC321X is not set ++# CONFIG_MFD_JANZ_CMODIO is not set ++# CONFIG_MFD_VX855 is not set ++# CONFIG_MFD_WL1273_CORE is not set ++# CONFIG_MFD_TPS65090 is not set ++# CONFIG_MFD_AAT2870_CORE is not set ++# CONFIG_MFD_RC5T583 is not set ++# CONFIG_MFD_SYSCON is not set ++# CONFIG_MFD_PALMAS is not set ++# CONFIG_MFD_VIPERBOARD is not set ++# CONFIG_MFD_RETU is not set ++# CONFIG_MFD_AS3711 is not set ++CONFIG_VEXPRESS_CONFIG=y ++# CONFIG_REGULATOR is not set ++CONFIG_MEDIA_SUPPORT=y ++ ++# ++# Multimedia core support ++# ++CONFIG_MEDIA_CAMERA_SUPPORT=y ++# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set ++# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set ++# CONFIG_MEDIA_RADIO_SUPPORT is not set ++# CONFIG_MEDIA_RC_SUPPORT is not set ++CONFIG_MEDIA_CONTROLLER=y ++CONFIG_VIDEO_DEV=y ++CONFIG_VIDEO_V4L2_SUBDEV_API=y ++CONFIG_VIDEO_V4L2=y ++# CONFIG_VIDEO_ADV_DEBUG is not set ++# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set ++ ++# ++# Media drivers ++# ++# CONFIG_MEDIA_USB_SUPPORT is not set ++# CONFIG_MEDIA_PCI_SUPPORT is not set ++CONFIG_V4L_PLATFORM_DRIVERS=y ++# CONFIG_VIDEO_CAFE_CCIC is not set ++# CONFIG_VIDEO_TIMBERDALE is not set ++# CONFIG_SOC_CAMERA is not set ++# CONFIG_V4L_MEM2MEM_DRIVERS is not set ++# CONFIG_V4L_TEST_DRIVERS is not set ++ ++# ++# Supported MMC/SDIO adapters ++# ++# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set ++ ++# ++# Media ancillary drivers (tuners, sensors, i2c, frontends) ++# ++ ++# ++# Encoders, decoders, sensors and other helper chips ++# ++ ++# ++# Audio decoders, processors and mixers ++# ++# 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 is not set ++# CONFIG_VIDEO_CS5345 is not set ++# CONFIG_VIDEO_CS53L32A is not set ++# CONFIG_VIDEO_TLV320AIC23B is not set ++# CONFIG_VIDEO_WM8775 is not set ++# 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 is not set ++# CONFIG_VIDEO_ADV7183 is not set ++CONFIG_VIDEO_ADV7604=y ++# 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_SAA7110 is not set ++# CONFIG_VIDEO_SAA711X 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_SAA717X is not set ++# CONFIG_VIDEO_CX25840 is not set ++ ++# ++# MPEG video encoders ++# ++# CONFIG_VIDEO_CX2341X is not set ++ ++# ++# 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_ADV7343 is not set ++# CONFIG_VIDEO_ADV7393 is not set ++CONFIG_VIDEO_ADV7511=y ++# CONFIG_VIDEO_AD9389B is not set ++# CONFIG_VIDEO_AK881X is not set ++ ++# ++# Camera sensor devices ++# ++# CONFIG_VIDEO_OV7670 is not set ++# CONFIG_VIDEO_VS6624 is not set ++# CONFIG_VIDEO_MT9M032 is not set ++# CONFIG_VIDEO_MT9P031 is not set ++# CONFIG_VIDEO_MT9T001 is not set ++# CONFIG_VIDEO_MT9V011 is not set ++# CONFIG_VIDEO_MT9V032 is not set ++# CONFIG_VIDEO_TCM825X is not set ++# CONFIG_VIDEO_SR030PC30 is not set ++# CONFIG_VIDEO_NOON010PC30 is not set ++# CONFIG_VIDEO_M5MOLS is not set ++# CONFIG_VIDEO_S5K6AA is not set ++# CONFIG_VIDEO_S5K4ECGX is not set ++# CONFIG_VIDEO_SMIAPP is not set ++ ++# ++# Flash devices ++# ++# CONFIG_VIDEO_ADP1653 is not set ++# CONFIG_VIDEO_AS3645A is not set ++ ++# ++# Video improvement chips ++# ++# CONFIG_VIDEO_UPD64031A is not set ++# CONFIG_VIDEO_UPD64083 is not set ++ ++# ++# Miscelaneous helper chips ++# ++# CONFIG_VIDEO_THS7303 is not set ++# CONFIG_VIDEO_M52790 is not set ++ ++# ++# Sensors used on soc_camera driver ++# ++ ++# ++# Customise DVB Frontends ++# ++# CONFIG_DVB_AU8522_V4L is not set ++# CONFIG_DVB_TUNER_DIB0070 is not set ++# CONFIG_DVB_TUNER_DIB0090 is not set ++ ++# ++# Tools to develop new frontends ++# ++# CONFIG_DVB_DUMMY_FE is not set ++ ++# ++# Graphics support ++# ++CONFIG_VGA_ARB=y ++CONFIG_VGA_ARB_MAX_GPUS=16 ++# CONFIG_DRM is not set ++# CONFIG_STUB_POULSBO is not set ++# CONFIG_VGASTATE is not set ++# CONFIG_VIDEO_OUTPUT_CONTROL is not set ++CONFIG_FB=y ++# CONFIG_FIRMWARE_EDID is not set ++# CONFIG_FB_DDC is not set ++# CONFIG_FB_BOOT_VESA_SUPPORT is not set ++CONFIG_FB_CFB_FILLRECT=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 is not set ++# CONFIG_FB_SYS_COPYAREA is not set ++# CONFIG_FB_SYS_IMAGEBLIT is not set ++# CONFIG_FB_FOREIGN_ENDIAN is not set ++# CONFIG_FB_SYS_FOPS is not set ++# CONFIG_FB_WMT_GE_ROPS is not set ++# CONFIG_FB_SVGALIB is not set ++# CONFIG_FB_MACMODES is not set ++# CONFIG_FB_BACKLIGHT is not set ++CONFIG_FB_MODE_HELPERS=y ++# CONFIG_FB_TILEBLITTING is not set ++ ++# ++# Frame buffer hardware drivers ++# ++# CONFIG_FB_CIRRUS is not set ++# CONFIG_FB_PM2 is not set ++# CONFIG_FB_ARMCLCD is not set ++# CONFIG_FB_CYBER2000 is not set ++# CONFIG_FB_ASILIANT is not set ++# CONFIG_FB_IMSTT is not set ++# CONFIG_FB_UVESA is not set ++# CONFIG_FB_S1D13XXX is not set ++# CONFIG_FB_NVIDIA is not set ++# CONFIG_FB_RIVA is not set ++# CONFIG_FB_I740 is not set ++# CONFIG_FB_MATROX is not set ++# CONFIG_FB_RADEON is not set ++# CONFIG_FB_ATY128 is not set ++# CONFIG_FB_ATY is not set ++# CONFIG_FB_S3 is not set ++# CONFIG_FB_SAVAGE is not set ++# CONFIG_FB_SIS is not set ++# CONFIG_FB_NEOMAGIC is not set ++# CONFIG_FB_KYRO is not set ++# CONFIG_FB_3DFX is not set ++# CONFIG_FB_VOODOO1 is not set ++# CONFIG_FB_VT8623 is not set ++# CONFIG_FB_TRIDENT is not set ++# CONFIG_FB_ARK is not set ++# CONFIG_FB_PM3 is not set ++# CONFIG_FB_CARMINE is not set ++# CONFIG_FB_SMSCUFX is not set ++# CONFIG_FB_UDL is not set ++# CONFIG_FB_XILINX is not set ++# CONFIG_FB_VIRTUAL is not set ++# CONFIG_FB_METRONOME is not set ++# CONFIG_FB_MB862XX is not set ++# CONFIG_FB_BROADSHEET is not set ++# CONFIG_FB_AUO_K190X is not set ++CONFIG_FB_XYLON=y ++# CONFIG_FB_XYLON_PLATFORM is not set ++CONFIG_FB_XYLON_OF=y ++CONFIG_FB_XYLON_PIXCLK=y ++# CONFIG_FB_XYLON_PIXCLK_ZYNQ_PS is not set ++# CONFIG_FB_XYLON_PIXCLK_LOGICLK is not set ++CONFIG_FB_XYLON_PIXCLK_SI570=y ++CONFIG_FB_XYLON_MISC=y ++CONFIG_FB_XYLON_MISC_ADV7511=y ++# CONFIG_EXYNOS_VIDEO is not set ++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set ++ ++# ++# Console display driver support ++# ++CONFIG_DUMMY_CONSOLE=y ++CONFIG_FRAMEBUFFER_CONSOLE=y ++# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set ++# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set ++CONFIG_FONTS=y ++CONFIG_FONT_8x8=y ++CONFIG_FONT_8x16=y ++# CONFIG_FONT_6x11 is not set ++# CONFIG_FONT_7x14 is not set ++# CONFIG_FONT_PEARL_8x8 is not set ++# CONFIG_FONT_ACORN_8x8 is not set ++# CONFIG_FONT_MINI_4x6 is not set ++# CONFIG_FONT_SUN8x16 is not set ++# CONFIG_FONT_SUN12x22 is not set ++# CONFIG_FONT_10x18 is not set ++# CONFIG_LOGO is not set ++# CONFIG_FB_SSD1307 is not set ++# CONFIG_SOUND is not set ++ ++# ++# HID support ++# ++CONFIG_HID=y ++# CONFIG_HIDRAW is not set ++# CONFIG_UHID is not set ++CONFIG_HID_GENERIC=y ++ ++# ++# Special HID drivers ++# ++# CONFIG_HID_A4TECH is not set ++# CONFIG_HID_ACRUX is not set ++# CONFIG_HID_APPLE is not set ++# CONFIG_HID_AUREAL is not set ++# CONFIG_HID_BELKIN is not set ++# CONFIG_HID_CHERRY is not set ++# CONFIG_HID_CHICONY is not set ++# CONFIG_HID_CYPRESS is not set ++# CONFIG_HID_DRAGONRISE is not set ++# CONFIG_HID_EMS_FF is not set ++# CONFIG_HID_EZKEY is not set ++# CONFIG_HID_HOLTEK is not set ++# CONFIG_HID_KEYTOUCH is not set ++# CONFIG_HID_KYE is not set ++# CONFIG_HID_UCLOGIC is not set ++# CONFIG_HID_WALTOP is not set ++# CONFIG_HID_GYRATION is not set ++# CONFIG_HID_TWINHAN is not set ++# CONFIG_HID_KENSINGTON is not set ++# CONFIG_HID_LCPOWER is not set ++# CONFIG_HID_LENOVO_TPKBD is not set ++# CONFIG_HID_LOGITECH is not set ++CONFIG_HID_MICROSOFT=y ++# CONFIG_HID_MONTEREY is not set ++# CONFIG_HID_MULTITOUCH is not set ++# CONFIG_HID_NTRIG is not set ++# CONFIG_HID_ORTEK is not set ++# CONFIG_HID_PANTHERLORD is not set ++# CONFIG_HID_PETALYNX is not set ++# CONFIG_HID_PICOLCD is not set ++# CONFIG_HID_PRIMAX is not set ++# CONFIG_HID_ROCCAT is not set ++# CONFIG_HID_SAITEK is not set ++# CONFIG_HID_SAMSUNG is not set ++# CONFIG_HID_SONY is not set ++# CONFIG_HID_SPEEDLINK is not set ++# CONFIG_HID_SUNPLUS is not set ++# CONFIG_HID_GREENASIA is not set ++# CONFIG_HID_SMARTJOYPLUS is not set ++# CONFIG_HID_TIVO is not set ++# CONFIG_HID_TOPSEED is not set ++# CONFIG_HID_THRUSTMASTER is not set ++# CONFIG_HID_ZEROPLUS is not set ++# CONFIG_HID_ZYDACRON is not set ++# CONFIG_HID_SENSOR_HUB is not set ++ ++# ++# USB HID support ++# ++CONFIG_USB_HID=y ++# CONFIG_HID_PID is not set ++# CONFIG_USB_HIDDEV is not set ++ ++# ++# I2C HID support ++# ++# CONFIG_I2C_HID is not set ++CONFIG_USB_ARCH_HAS_OHCI=y ++CONFIG_USB_ARCH_HAS_EHCI=y ++CONFIG_USB_ARCH_HAS_XHCI=y ++CONFIG_USB_SUPPORT=y ++CONFIG_USB_COMMON=y ++CONFIG_USB_ARCH_HAS_HCD=y ++CONFIG_USB=y ++# CONFIG_USB_DEBUG is not set ++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set ++ ++# ++# Miscellaneous USB options ++# ++# 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_DWC3 is not set ++# CONFIG_USB_MON is not set ++# CONFIG_USB_WUSB_CBAF is not set ++ ++# ++# USB Host Controller Drivers ++# ++# CONFIG_USB_C67X00_HCD is not set ++# CONFIG_USB_XHCI_HCD is not set ++CONFIG_USB_EHCI_HCD=y ++CONFIG_USB_EHCI_ROOT_HUB_TT=y ++# CONFIG_USB_EHCI_TT_NEWSCHED is not set ++CONFIG_USB_EHCI_PCI=y ++CONFIG_USB_XUSBPS_DR_OF=y ++CONFIG_USB_EHCI_XUSBPS=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_EHCI_HCD_PLATFORM is not set ++# CONFIG_USB_UHCI_HCD is not set ++# CONFIG_USB_SL811_HCD is not set ++# CONFIG_USB_R8A66597_HCD is not set ++# CONFIG_USB_MUSB_HDRC is not set ++# CONFIG_USB_CHIPIDEA is not set ++# CONFIG_USB_RENESAS_USBHS is not set ++ ++# ++# USB Device Class drivers ++# ++# CONFIG_USB_ACM is not set ++# CONFIG_USB_PRINTER is not set ++# CONFIG_USB_WDM is not set ++# CONFIG_USB_TMC is not set ++ ++# ++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may ++# ++ ++# ++# also be needed; see USB_STORAGE Help for more info ++# ++CONFIG_USB_STORAGE=y ++# CONFIG_USB_STORAGE_DEBUG is not set ++# CONFIG_USB_STORAGE_REALTEK is not set ++# CONFIG_USB_STORAGE_DATAFAB is not set ++# CONFIG_USB_STORAGE_FREECOM is not set ++# CONFIG_USB_STORAGE_ISD200 is not set ++# CONFIG_USB_STORAGE_USBAT is not set ++# CONFIG_USB_STORAGE_SDDR09 is not set ++# CONFIG_USB_STORAGE_SDDR55 is not set ++# CONFIG_USB_STORAGE_JUMPSHOT is not set ++# CONFIG_USB_STORAGE_ALAUDA is not set ++# CONFIG_USB_STORAGE_ONETOUCH is not set ++# CONFIG_USB_STORAGE_KARMA is not set ++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set ++# CONFIG_USB_STORAGE_ENE_UB6250 is not set ++ ++# ++# USB Imaging devices ++# ++# CONFIG_USB_MDC800 is not set ++# CONFIG_USB_MICROTEK is not set ++ ++# ++# USB port drivers ++# ++# CONFIG_USB_SERIAL is not set ++ ++# ++# USB Miscellaneous drivers ++# ++# CONFIG_USB_EMI62 is not set ++# CONFIG_USB_EMI26 is not set ++# CONFIG_USB_ADUTUX is not set ++# CONFIG_USB_SEVSEG is not set ++# CONFIG_USB_RIO500 is not set ++# CONFIG_USB_LEGOTOWER is not set ++# CONFIG_USB_LCD is not set ++# CONFIG_USB_LED is not set ++# CONFIG_USB_CYPRESS_CY7C63 is not set ++# CONFIG_USB_CYTHERM is not set ++# CONFIG_USB_IDMOUSE is not set ++# CONFIG_USB_FTDI_ELAN is not set ++# CONFIG_USB_APPLEDISPLAY is not set ++# CONFIG_USB_SISUSBVGA is not set ++# CONFIG_USB_LD is not set ++# CONFIG_USB_TRANCEVIBRATOR is not set ++# CONFIG_USB_IOWARRIOR is not set ++# CONFIG_USB_TEST is not set ++# CONFIG_USB_ISIGHTFW is not set ++# CONFIG_USB_YUREX is not set ++# CONFIG_USB_EZUSB_FX2 is not set ++ ++# ++# USB Physical Layer drivers ++# ++# CONFIG_USB_ISP1301 is not set ++# CONFIG_USB_RCAR_PHY is not set ++CONFIG_USB_GADGET=y ++# CONFIG_USB_GADGET_DEBUG is not set ++# CONFIG_USB_GADGET_DEBUG_FILES is not set ++# CONFIG_USB_GADGET_DEBUG_FS is not set ++CONFIG_USB_GADGET_VBUS_DRAW=2 ++CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 ++ ++# ++# USB Peripheral Controller ++# ++CONFIG_USB_GADGET_XUSBPS=y ++CONFIG_XUSBPS_ERRATA_DT654401=y ++CONFIG_USB_XUSBPS=y ++# CONFIG_USB_FUSB300 is not set ++# CONFIG_USB_R8A66597 is not set ++# CONFIG_USB_GADGET_XILINX is not set ++# CONFIG_USB_MV_UDC is not set ++# CONFIG_USB_M66592 is not set ++# CONFIG_USB_AMD5536UDC is not set ++# CONFIG_USB_NET2272 is not set ++# CONFIG_USB_NET2280 is not set ++# CONFIG_USB_GOKU is not set ++# CONFIG_USB_EG20T is not set ++# CONFIG_USB_DUMMY_HCD is not set ++CONFIG_USB_LIBCOMPOSITE=m ++CONFIG_USB_ZERO=m ++# CONFIG_USB_ZERO_HNPTEST is not set ++# CONFIG_USB_ETH is not set ++# CONFIG_USB_G_NCM is not set ++# CONFIG_USB_GADGETFS is not set ++# CONFIG_USB_FUNCTIONFS is not set ++# CONFIG_USB_MASS_STORAGE is not set ++# CONFIG_USB_G_SERIAL is not set ++# CONFIG_USB_G_PRINTER is not set ++# CONFIG_USB_CDC_COMPOSITE is not set ++# CONFIG_USB_G_ACM_MS is not set ++# CONFIG_USB_G_MULTI is not set ++# CONFIG_USB_G_HID is not set ++# CONFIG_USB_G_DBGP is not set ++# CONFIG_USB_G_WEBCAM is not set ++ ++# ++# OTG and related infrastructure ++# ++CONFIG_USB_OTG_UTILS=y ++# CONFIG_USB_GPIO_VBUS is not set ++CONFIG_USB_ULPI=y ++CONFIG_USB_ULPI_VIEWPORT=y ++# CONFIG_NOP_USB_XCEIV is not set ++CONFIG_USB_XUSBPS_OTG=y ++# CONFIG_UWB is not set ++CONFIG_MMC=y ++# CONFIG_MMC_DEBUG is not set ++# CONFIG_MMC_UNSAFE_RESUME is not set ++# 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 is not set ++# CONFIG_MMC_TEST is not set ++ ++# ++# MMC/SD/SDIO Host Controller Drivers ++# ++# CONFIG_MMC_ARMMMCI is not set ++CONFIG_MMC_SDHCI=y ++# CONFIG_MMC_SDHCI_PCI is not set ++CONFIG_MMC_SDHCI_PLTFM=y ++CONFIG_MMC_SDHCI_OF_XILINX_PS=y ++# CONFIG_MMC_SDHCI_PXAV3 is not set ++# CONFIG_MMC_SDHCI_PXAV2 is not set ++# CONFIG_MMC_TIFM_SD is not set ++# CONFIG_MMC_CB710 is not set ++# CONFIG_MMC_VIA_SDMMC is not set ++# CONFIG_MMC_DW is not set ++# CONFIG_MMC_VUB300 is not set ++# CONFIG_MMC_USHC is not set ++# CONFIG_MEMSTICK is not set ++# CONFIG_NEW_LEDS is not set ++# CONFIG_ACCESSIBILITY is not set ++# CONFIG_INFINIBAND is not set ++# CONFIG_EDAC 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 is not set ++# 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_PCF8523 is not set ++CONFIG_RTC_DRV_PCF8563=y ++# CONFIG_RTC_DRV_PCF8583 is not set ++# CONFIG_RTC_DRV_M41T80 is not set ++# CONFIG_RTC_DRV_BQ32K is not set ++# 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 ++# CONFIG_RTC_DRV_EM3027 is not set ++# CONFIG_RTC_DRV_RV3029C2 is not set ++ ++# ++# SPI RTC drivers ++# ++# CONFIG_RTC_DRV_M41T93 is not set ++# 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 ++# CONFIG_RTC_DRV_DS2404 is not set ++ ++# ++# on-CPU RTC drivers ++# ++# CONFIG_RTC_DRV_PL030 is not set ++# CONFIG_RTC_DRV_PL031 is not set ++# CONFIG_RTC_DRV_SNVS is not set ++CONFIG_DMADEVICES=y ++# CONFIG_DMADEVICES_DEBUG is not set ++ ++# ++# DMA Devices ++# ++CONFIG_XILINX_DMA_ENGINES=y ++CONFIG_XILINX_AXIDMA=y ++# CONFIG_XILINX_DMATEST is not set ++CONFIG_XILINX_AXIVDMA=y ++# CONFIG_XILINX_VDMATEST is not set ++CONFIG_XILINX_AXICDMA=y ++# CONFIG_XILINX_CDMATEST is not set ++# CONFIG_AMBA_PL08X is not set ++# CONFIG_DW_DMAC is not set ++# CONFIG_TIMB_DMA is not set ++CONFIG_PL330_DMA=y ++ ++# ++# DMA Clients ++# ++# CONFIG_NET_DMA is not set ++# CONFIG_ASYNC_TX_DMA is not set ++# CONFIG_DMATEST is not set ++# CONFIG_AUXDISPLAY is not set ++CONFIG_UIO=y ++# CONFIG_UIO_CIF is not set ++CONFIG_UIO_PDRV_GENIRQ=y ++# CONFIG_UIO_DMEM_GENIRQ is not set ++# CONFIG_UIO_AEC is not set ++# CONFIG_UIO_SERCOS3 is not set ++# CONFIG_UIO_PCI_GENERIC is not set ++# CONFIG_UIO_NETX is not set ++CONFIG_VIRTIO=m ++ ++# ++# Virtio drivers ++# ++# CONFIG_VIRTIO_PCI is not set ++# CONFIG_VIRTIO_BALLOON is not set ++# CONFIG_VIRTIO_MMIO is not set ++ ++# ++# Microsoft Hyper-V guest support ++# ++CONFIG_STAGING=y ++# CONFIG_ET131X is not set ++# CONFIG_USBIP_CORE is not set ++# CONFIG_ECHO is not set ++# CONFIG_ASUS_OLED is not set ++# CONFIG_R8187SE is not set ++# CONFIG_RTL8192U is not set ++# CONFIG_RTLLIB is not set ++# CONFIG_R8712U is not set ++# CONFIG_RTS5139 is not set ++# CONFIG_TRANZPORT is not set ++# CONFIG_VT6655 is not set ++# CONFIG_VT6656 is not set ++# CONFIG_DX_SEP is not set ++# CONFIG_ZSMALLOC is not set ++# CONFIG_FB_SM7XX is not set ++# CONFIG_CRYSTALHD is not set ++# CONFIG_FB_XGI is not set ++# CONFIG_USB_ENESTORAGE is not set ++# CONFIG_BCM_WIMAX is not set ++# CONFIG_FT1000 is not set ++ ++# ++# Speakup console speech ++# ++# CONFIG_SPEAKUP is not set ++# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set ++# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set ++# CONFIG_STAGING_MEDIA is not set ++ ++# ++# Android ++# ++# CONFIG_ANDROID is not set ++# CONFIG_USB_WPAN_HCD is not set ++# CONFIG_USB_G_CCG is not set ++# CONFIG_WIMAX_GDM72XX is not set ++CONFIG_NET_VENDOR_SILICOM=y ++# CONFIG_SBYPASS is not set ++# CONFIG_BPCTL is not set ++# CONFIG_CED1401 is not set ++# CONFIG_DGRP is not set ++CONFIG_XILINX_VIDEO_IP=y ++CONFIG_XILINX_VDMA_WRAPPER=y ++CONFIG_VIDEO_IMAGEON=m ++CONFIG_CLKDEV_LOOKUP=y ++CONFIG_HAVE_CLK_PREPARE=y ++CONFIG_COMMON_CLK=y ++ ++# ++# Common Clock Framework ++# ++CONFIG_COMMON_CLK_DEBUG=y ++CONFIG_COMMON_CLK_VERSATILE=y ++ ++# ++# Hardware Spinlock drivers ++# ++CONFIG_CLKSRC_MMIO=y ++CONFIG_IOMMU_SUPPORT=y ++CONFIG_OF_IOMMU=y ++ ++# ++# Remoteproc drivers (EXPERIMENTAL) ++# ++CONFIG_REMOTEPROC=m ++# CONFIG_STE_MODEM_RPROC is not set ++CONFIG_ZYNQ_REMOTEPROC=m ++CONFIG_MB_REMOTEPROC=m ++ ++# ++# Rpmsg drivers (EXPERIMENTAL) ++# ++CONFIG_RPMSG=m ++# CONFIG_RPMSG_SERVER_SAMPLE is not set ++# CONFIG_RPMSG_OMX is not set ++# CONFIG_RPMSG_FREERTOS_STAT is not set ++# CONFIG_VIRT_DRIVERS is not set ++# CONFIG_PM_DEVFREQ is not set ++# CONFIG_EXTCON is not set ++CONFIG_MEMORY=y ++CONFIG_ZYNQ_SMC=y ++# CONFIG_IIO is not set ++# CONFIG_VME_BUS is not set ++# CONFIG_PWM is not set ++# CONFIG_PMODS is not set ++# CONFIG_IPACK_BUS is not set ++ ++# ++# File systems ++# ++CONFIG_DCACHE_WORD_ACCESS=y ++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=y ++# CONFIG_EXT3_FS_POSIX_ACL is not set ++# CONFIG_EXT3_FS_SECURITY is not set ++CONFIG_EXT4_FS=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 is not set ++# CONFIG_JFS_FS is not set ++# CONFIG_XFS_FS is not set ++# CONFIG_GFS2_FS is not set ++# CONFIG_BTRFS_FS is not set ++# CONFIG_NILFS2_FS is not set ++# CONFIG_FS_POSIX_ACL is not set ++CONFIG_FILE_LOCKING=y ++CONFIG_FSNOTIFY=y ++# CONFIG_DNOTIFY is not set ++CONFIG_INOTIFY_USER=y ++# CONFIG_FANOTIFY is not set ++# CONFIG_QUOTA is not set ++# CONFIG_QUOTACTL is not set ++# CONFIG_AUTOFS4_FS is not set ++# CONFIG_FUSE_FS is not set ++ ++# ++# Caches ++# ++# CONFIG_FSCACHE is not set ++ ++# ++# CD-ROM/DVD Filesystems ++# ++# CONFIG_ISO9660_FS is not set ++# CONFIG_UDF_FS is not set ++ ++# ++# DOS/FAT/NT Filesystems ++# ++CONFIG_FAT_FS=y ++CONFIG_MSDOS_FS=y ++CONFIG_VFAT_FS=y ++CONFIG_FAT_DEFAULT_CODEPAGE=437 ++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" ++# CONFIG_NTFS_FS is not set ++ ++# ++# Pseudo filesystems ++# ++CONFIG_PROC_FS=y ++CONFIG_PROC_SYSCTL=y ++CONFIG_PROC_PAGE_MONITOR=y ++CONFIG_SYSFS=y ++CONFIG_TMPFS=y ++# CONFIG_TMPFS_POSIX_ACL is not set ++# CONFIG_TMPFS_XATTR is not set ++# CONFIG_HUGETLB_PAGE is not set ++# CONFIG_CONFIGFS_FS is not set ++CONFIG_MISC_FILESYSTEMS=y ++# CONFIG_ADFS_FS is not set ++# CONFIG_AFFS_FS is not set ++# CONFIG_HFS_FS is not set ++# CONFIG_HFSPLUS_FS is not set ++# CONFIG_BEFS_FS is not set ++# CONFIG_BFS_FS is not set ++# CONFIG_EFS_FS is not set ++CONFIG_JFFS2_FS=y ++CONFIG_JFFS2_FS_DEBUG=0 ++CONFIG_JFFS2_FS_WRITEBUFFER=y ++# CONFIG_JFFS2_FS_WBUF_VERIFY is not set ++CONFIG_JFFS2_SUMMARY=y ++# CONFIG_JFFS2_FS_XATTR is not set ++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set ++CONFIG_JFFS2_ZLIB=y ++# CONFIG_JFFS2_LZO is not set ++CONFIG_JFFS2_RTIME=y ++# CONFIG_JFFS2_RUBIN is not set ++# CONFIG_LOGFS is not set ++# CONFIG_CRAMFS is not set ++# CONFIG_SQUASHFS is not set ++# CONFIG_VXFS_FS is not set ++# CONFIG_MINIX_FS is not set ++# CONFIG_OMFS_FS is not set ++# CONFIG_HPFS_FS is not set ++# CONFIG_QNX4FS_FS is not set ++# CONFIG_QNX6FS_FS is not set ++# CONFIG_ROMFS_FS is not set ++# CONFIG_PSTORE is not set ++# CONFIG_SYSV_FS is not set ++# CONFIG_UFS_FS is not set ++# CONFIG_F2FS_FS is not set ++CONFIG_NETWORK_FILESYSTEMS=y ++CONFIG_NFS_FS=y ++CONFIG_NFS_V2=y ++CONFIG_NFS_V3=y ++# CONFIG_NFS_V3_ACL is not set ++# CONFIG_NFS_V4 is not set ++# CONFIG_NFS_SWAP is not set ++CONFIG_ROOT_NFS=y ++# CONFIG_NFSD is not set ++CONFIG_LOCKD=y ++CONFIG_LOCKD_V4=y ++CONFIG_NFS_COMMON=y ++CONFIG_SUNRPC=y ++# CONFIG_SUNRPC_DEBUG is not set ++# CONFIG_CEPH_FS is not set ++# CONFIG_CIFS is not set ++# CONFIG_NCP_FS is not set ++# CONFIG_CODA_FS is not set ++# CONFIG_AFS_FS is not set ++CONFIG_NLS=y ++CONFIG_NLS_DEFAULT="iso8859-1" ++CONFIG_NLS_CODEPAGE_437=y ++# CONFIG_NLS_CODEPAGE_737 is not set ++# CONFIG_NLS_CODEPAGE_775 is not set ++# CONFIG_NLS_CODEPAGE_850 is not set ++# CONFIG_NLS_CODEPAGE_852 is not set ++# CONFIG_NLS_CODEPAGE_855 is not set ++# CONFIG_NLS_CODEPAGE_857 is not set ++# CONFIG_NLS_CODEPAGE_860 is not set ++# CONFIG_NLS_CODEPAGE_861 is not set ++# CONFIG_NLS_CODEPAGE_862 is not set ++# CONFIG_NLS_CODEPAGE_863 is not set ++# CONFIG_NLS_CODEPAGE_864 is not set ++# CONFIG_NLS_CODEPAGE_865 is not set ++# CONFIG_NLS_CODEPAGE_866 is not set ++# CONFIG_NLS_CODEPAGE_869 is not set ++# CONFIG_NLS_CODEPAGE_936 is not set ++# CONFIG_NLS_CODEPAGE_950 is not set ++# CONFIG_NLS_CODEPAGE_932 is not set ++# CONFIG_NLS_CODEPAGE_949 is not set ++# CONFIG_NLS_CODEPAGE_874 is not set ++# CONFIG_NLS_ISO8859_8 is not set ++# CONFIG_NLS_CODEPAGE_1250 is not set ++# CONFIG_NLS_CODEPAGE_1251 is not set ++CONFIG_NLS_ASCII=y ++CONFIG_NLS_ISO8859_1=y ++# CONFIG_NLS_ISO8859_2 is not set ++# CONFIG_NLS_ISO8859_3 is not set ++# CONFIG_NLS_ISO8859_4 is not set ++# CONFIG_NLS_ISO8859_5 is not set ++# CONFIG_NLS_ISO8859_6 is not set ++# CONFIG_NLS_ISO8859_7 is not set ++# CONFIG_NLS_ISO8859_9 is not set ++# CONFIG_NLS_ISO8859_13 is not set ++# CONFIG_NLS_ISO8859_14 is not set ++# CONFIG_NLS_ISO8859_15 is not set ++# CONFIG_NLS_KOI8_R is not set ++# CONFIG_NLS_KOI8_U is not set ++# CONFIG_NLS_MAC_ROMAN is not set ++# CONFIG_NLS_MAC_CELTIC is not set ++# CONFIG_NLS_MAC_CENTEURO is not set ++# CONFIG_NLS_MAC_CROATIAN is not set ++# CONFIG_NLS_MAC_CYRILLIC is not set ++# CONFIG_NLS_MAC_GAELIC is not set ++# CONFIG_NLS_MAC_GREEK is not set ++# CONFIG_NLS_MAC_ICELAND is not set ++# CONFIG_NLS_MAC_INUIT is not set ++# CONFIG_NLS_MAC_ROMANIAN is not set ++# CONFIG_NLS_MAC_TURKISH is not set ++# CONFIG_NLS_UTF8 is not set ++ ++# ++# Kernel hacking ++# ++# CONFIG_PRINTK_TIME is not set ++CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 ++# CONFIG_ENABLE_WARN_DEPRECATED is not set ++# CONFIG_ENABLE_MUST_CHECK is not set ++CONFIG_FRAME_WARN=1024 ++# CONFIG_MAGIC_SYSRQ is not set ++# CONFIG_STRIP_ASM_SYMS is not set ++# CONFIG_READABLE_ASM 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_PANIC_ON_OOPS is not set ++CONFIG_PANIC_ON_OOPS_VALUE=0 ++# CONFIG_DETECT_HUNG_TASK is not set ++# CONFIG_SCHED_DEBUG is not set ++# CONFIG_SCHEDSTATS is not set ++CONFIG_TIMER_STATS=y ++# CONFIG_DEBUG_OBJECTS is not set ++# CONFIG_DEBUG_SLAB is not set ++CONFIG_HAVE_DEBUG_KMEMLEAK=y ++# CONFIG_DEBUG_KMEMLEAK is not set ++# CONFIG_DEBUG_PREEMPT is not set ++# CONFIG_DEBUG_RT_MUTEXES is not set ++# CONFIG_RT_MUTEX_TESTER is not set ++# CONFIG_DEBUG_SPINLOCK is not set ++# CONFIG_DEBUG_MUTEXES is not set ++# CONFIG_DEBUG_LOCK_ALLOC is not set ++# CONFIG_PROVE_LOCKING is not set ++# CONFIG_PROVE_RCU_DELAY is not set ++# CONFIG_SPARSE_RCU_POINTER is not set ++# CONFIG_LOCK_STAT is not set ++# CONFIG_DEBUG_ATOMIC_SLEEP is not set ++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set ++# CONFIG_DEBUG_STACK_USAGE is not set ++# CONFIG_DEBUG_KOBJECT is not set ++# CONFIG_DEBUG_HIGHMEM 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_TIMEOUT=60 ++# CONFIG_RCU_CPU_STALL_VERBOSE is not set ++# CONFIG_RCU_CPU_STALL_INFO is not set ++# CONFIG_RCU_TRACE 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_DEBUG_PER_CPU_MAPS is not set ++# CONFIG_LKDTM is not set ++# CONFIG_NOTIFIER_ERROR_INJECTION is not set ++# CONFIG_FAULT_INJECTION 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_SYSCALL_TRACEPOINTS=y ++CONFIG_HAVE_C_RECORDMCOUNT=y ++CONFIG_TRACING_SUPPORT=y ++# CONFIG_FTRACE is not set ++# CONFIG_RBTREE_TEST is not set ++# CONFIG_INTERVAL_TREE_TEST is not set ++CONFIG_DYNAMIC_DEBUG=y ++# CONFIG_DMA_API_DEBUG is not set ++# CONFIG_ATOMIC64_SELFTEST 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_LL=y ++# CONFIG_DEBUG_ZYNQ_UART0 is not set ++CONFIG_DEBUG_ZYNQ_UART1=y ++# CONFIG_DEBUG_VEXPRESS_UART0_DETECT is not set ++# CONFIG_DEBUG_VEXPRESS_UART0_CA9 is not set ++# CONFIG_DEBUG_VEXPRESS_UART0_RS1 is not set ++# CONFIG_DEBUG_ICEDCC is not set ++# CONFIG_DEBUG_SEMIHOSTING is not set ++CONFIG_DEBUG_LL_INCLUDE="debug/zynq.S" ++CONFIG_EARLY_PRINTK=y ++# CONFIG_OC_ETM is not set ++# CONFIG_PID_IN_CONTEXTIDR is not set ++ ++# ++# Security options ++# ++# CONFIG_KEYS is not set ++# CONFIG_SECURITY_DMESG_RESTRICT is not set ++# CONFIG_SECURITY is not set ++# CONFIG_SECURITYFS is not set ++CONFIG_DEFAULT_SECURITY_DAC=y ++CONFIG_DEFAULT_SECURITY="" ++CONFIG_CRYPTO=y ++ ++# ++# Crypto core or helper ++# ++# CONFIG_CRYPTO_FIPS is not set ++CONFIG_CRYPTO_ALGAPI=y ++CONFIG_CRYPTO_ALGAPI2=y ++CONFIG_CRYPTO_HASH=y ++CONFIG_CRYPTO_HASH2=y ++CONFIG_CRYPTO_RNG=m ++CONFIG_CRYPTO_RNG2=m ++# CONFIG_CRYPTO_MANAGER is not set ++# CONFIG_CRYPTO_MANAGER2 is not set ++# CONFIG_CRYPTO_USER is not set ++# CONFIG_CRYPTO_GF128MUL is not set ++# CONFIG_CRYPTO_NULL is not set ++# CONFIG_CRYPTO_PCRYPT is not set ++# CONFIG_CRYPTO_CRYPTD is not set ++# CONFIG_CRYPTO_AUTHENC is not set ++# CONFIG_CRYPTO_TEST is not set ++ ++# ++# Authenticated Encryption with Associated Data ++# ++# CONFIG_CRYPTO_CCM is not set ++# CONFIG_CRYPTO_GCM is not set ++# CONFIG_CRYPTO_SEQIV is not set ++ ++# ++# Block modes ++# ++# CONFIG_CRYPTO_CBC is not set ++# CONFIG_CRYPTO_CTR is not set ++# CONFIG_CRYPTO_CTS is not set ++# CONFIG_CRYPTO_ECB is not set ++# CONFIG_CRYPTO_LRW is not set ++# CONFIG_CRYPTO_PCBC is not set ++# CONFIG_CRYPTO_XTS is not set ++ ++# ++# Hash modes ++# ++# CONFIG_CRYPTO_HMAC is not set ++# CONFIG_CRYPTO_XCBC is not set ++# CONFIG_CRYPTO_VMAC is not set ++ ++# ++# Digest ++# ++CONFIG_CRYPTO_CRC32C=y ++# CONFIG_CRYPTO_GHASH is not set ++# CONFIG_CRYPTO_MD4 is not set ++# CONFIG_CRYPTO_MD5 is not set ++# CONFIG_CRYPTO_MICHAEL_MIC is not set ++# CONFIG_CRYPTO_RMD128 is not set ++# CONFIG_CRYPTO_RMD160 is not set ++# CONFIG_CRYPTO_RMD256 is not set ++# CONFIG_CRYPTO_RMD320 is not set ++# CONFIG_CRYPTO_SHA1 is not set ++# CONFIG_CRYPTO_SHA1_ARM is not set ++# CONFIG_CRYPTO_SHA256 is not set ++# CONFIG_CRYPTO_SHA512 is not set ++# CONFIG_CRYPTO_TGR192 is not set ++# CONFIG_CRYPTO_WP512 is not set ++ ++# ++# Ciphers ++# ++CONFIG_CRYPTO_AES=y ++# CONFIG_CRYPTO_AES_ARM is not set ++# CONFIG_CRYPTO_ANUBIS is not set ++# CONFIG_CRYPTO_ARC4 is not set ++# CONFIG_CRYPTO_BLOWFISH is not set ++# CONFIG_CRYPTO_CAMELLIA is not set ++# CONFIG_CRYPTO_CAST5 is not set ++# CONFIG_CRYPTO_CAST6 is not set ++# CONFIG_CRYPTO_DES is not set ++# CONFIG_CRYPTO_FCRYPT is not set ++# CONFIG_CRYPTO_KHAZAD is not set ++# CONFIG_CRYPTO_SALSA20 is not set ++# CONFIG_CRYPTO_SEED is not set ++# CONFIG_CRYPTO_SERPENT is not set ++# CONFIG_CRYPTO_TEA is not set ++# CONFIG_CRYPTO_TWOFISH is not set ++ ++# ++# Compression ++# ++# CONFIG_CRYPTO_DEFLATE is not set ++# CONFIG_CRYPTO_ZLIB is not set ++# CONFIG_CRYPTO_LZO is not set ++ ++# ++# Random Number Generation ++# ++CONFIG_CRYPTO_ANSI_CPRNG=m ++# CONFIG_CRYPTO_USER_API_HASH is not set ++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set ++CONFIG_CRYPTO_HW=y ++# CONFIG_CRYPTO_DEV_HIFN_795X is not set ++# CONFIG_BINARY_PRINTF is not set ++ ++# ++# Library routines ++# ++CONFIG_BITREVERSE=y ++CONFIG_GENERIC_STRNCPY_FROM_USER=y ++CONFIG_GENERIC_STRNLEN_USER=y ++CONFIG_GENERIC_PCI_IOMAP=y ++CONFIG_GENERIC_IO=y ++CONFIG_PERCPU_RWSEM=y ++# CONFIG_CRC_CCITT is not set ++CONFIG_CRC16=y ++# CONFIG_CRC_T10DIF is not set ++# CONFIG_CRC_ITU_T is not set ++CONFIG_CRC32=y ++# CONFIG_CRC32_SELFTEST is not set ++CONFIG_CRC32_SLICEBY8=y ++# CONFIG_CRC32_SLICEBY4 is not set ++# CONFIG_CRC32_SARWATE is not set ++# CONFIG_CRC32_BIT is not set ++# CONFIG_CRC7 is not set ++# CONFIG_LIBCRC32C is not set ++# CONFIG_CRC8 is not set ++CONFIG_ZLIB_INFLATE=y ++CONFIG_ZLIB_DEFLATE=y ++# CONFIG_XZ_DEC is not set ++# CONFIG_XZ_DEC_BCJ is not set ++CONFIG_DECOMPRESS_GZIP=y ++CONFIG_HAS_IOMEM=y ++CONFIG_HAS_DMA=y ++CONFIG_CPU_RMAP=y ++CONFIG_DQL=y ++CONFIG_NLATTR=y ++CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y ++# CONFIG_AVERAGE is not set ++# CONFIG_CORDIC is not set ++# CONFIG_DDR is not set +diff --git a/arch/arm/configs/xilinx_zynq_defconfig b/arch/arm/configs/xilinx_zynq_defconfig +index 58c226e..95d4d3e 100644 +--- a/arch/arm/configs/xilinx_zynq_defconfig ++++ b/arch/arm/configs/xilinx_zynq_defconfig +@@ -344,12 +344,16 @@ CONFIG_MULTI_IRQ_HANDLER=y + CONFIG_PL310_ERRATA_588369=y + CONFIG_ARM_ERRATA_720789=y + CONFIG_PL310_ERRATA_727915=y ++CONFIG_ARM_ERRATA_742230=y ++CONFIG_ARM_ERRATA_742231=y ++CONFIG_ARM_ERRATA_743622=y ++CONFIG_ARM_ERRATA_751472=y + CONFIG_PL310_ERRATA_753970=y +-# CONFIG_ARM_ERRATA_754322 is not set +-# CONFIG_ARM_ERRATA_754327 is not set +-# CONFIG_ARM_ERRATA_764369 is not set ++CONFIG_ARM_ERRATA_754322=y ++CONFIG_ARM_ERRATA_754327=y ++CONFIG_ARM_ERRATA_764369=y + CONFIG_PL310_ERRATA_769419=y +-# CONFIG_ARM_ERRATA_775420 is not set ++CONFIG_ARM_ERRATA_775420=y + CONFIG_ARM_GIC=y + CONFIG_ICST=y + +@@ -1574,6 +1578,7 @@ CONFIG_XILINX_PS_WATCHDOG=y + # CONFIG_MAX63XX_WATCHDOG is not set + # CONFIG_ALIM7101_WDT is not set + # CONFIG_I6300ESB_WDT is not set ++CONFIG_XILINX_WATCHDOG=y + + # + # PCI-based Watchdog Cards +@@ -2177,7 +2182,7 @@ CONFIG_PL330_DMA=y + # + # CONFIG_NET_DMA is not set + # CONFIG_ASYNC_TX_DMA is not set +-CONFIG_DMATEST=y ++# CONFIG_DMATEST is not set + # CONFIG_AUXDISPLAY is not set + CONFIG_UIO=y + # CONFIG_UIO_CIF is not set +diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h +index 26e9ce4..c094749 100644 +--- a/arch/arm/include/asm/pgtable.h ++++ b/arch/arm/include/asm/pgtable.h +@@ -61,15 +61,6 @@ extern void __pgd_error(const char *file, int line, pgd_t); + #define FIRST_USER_ADDRESS PAGE_SIZE + + /* +- * Use TASK_SIZE as the ceiling argument for free_pgtables() and +- * free_pgd_range() to avoid freeing the modules pmd when LPAE is enabled (pmd +- * page shared between user and kernel). +- */ +-#ifdef CONFIG_ARM_LPAE +-#define USER_PGTABLES_CEILING TASK_SIZE +-#endif +- +-/* + * The pgprot_* and protection_map entries will be fixed up in runtime + * to include the cachable and bufferable bits based on memory policy, + * as well as any architecture dependent bits like global/ASID and SMP +diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S +index a58dd49..a6c301e 100644 +--- a/arch/arm/kernel/entry-common.S ++++ b/arch/arm/kernel/entry-common.S +@@ -472,8 +472,7 @@ __cr_alignment: + * With EABI a couple syscalls are obsolete and defined as sys_ni_syscall. + */ + #define ABI(native, compat) native +- +-#if defined(CONFIG_AEABI) && !defined(CONFIG_OABI_COMPAT) ++#ifdef CONFIG_AEABI + #define OBSOLETE(syscall) sys_ni_syscall + #else + #define OBSOLETE(syscall) syscall +diff --git a/arch/arm/lib/memset.S b/arch/arm/lib/memset.S +index 94b0650..d912e73 100644 +--- a/arch/arm/lib/memset.S ++++ b/arch/arm/lib/memset.S +@@ -14,15 +14,31 @@ + + .text + .align 5 ++ .word 0 ++ ++1: subs r2, r2, #4 @ 1 do we have enough ++ blt 5f @ 1 bytes to align with? ++ cmp r3, #2 @ 1 ++ strltb r1, [ip], #1 @ 1 ++ strleb r1, [ip], #1 @ 1 ++ strb r1, [ip], #1 @ 1 ++ add r2, r2, r3 @ 1 (r2 = r2 - (4 - r3)) ++/* ++ * The pointer is now aligned and the length is adjusted. Try doing the ++ * memset again. ++ */ + + ENTRY(memset) +- ands r3, r0, #3 @ 1 unaligned? +- mov ip, r0 @ preserve r0 as return value +- bne 6f @ 1 ++/* ++ * Preserve the contents of r0 for the return value. ++ */ ++ mov ip, r0 ++ ands r3, ip, #3 @ 1 unaligned? ++ bne 1b @ 1 + /* + * we know that the pointer in ip is aligned to a word boundary. + */ +-1: orr r1, r1, r1, lsl #8 ++ orr r1, r1, r1, lsl #8 + orr r1, r1, r1, lsl #16 + mov r3, r1 + cmp r2, #16 +@@ -111,13 +127,4 @@ ENTRY(memset) + tst r2, #1 + strneb r1, [ip], #1 + mov pc, lr +- +-6: subs r2, r2, #4 @ 1 do we have enough +- blt 5b @ 1 bytes to align with? +- cmp r3, #2 @ 1 +- strltb r1, [ip], #1 @ 1 +- strleb r1, [ip], #1 @ 1 +- strb r1, [ip], #1 @ 1 +- add r2, r2, r3 @ 1 (r2 = r2 - (4 - r3)) +- b 1b + ENDPROC(memset) +diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c +index 6b4608d..4b67847 100644 +--- a/arch/arm/mach-at91/setup.c ++++ b/arch/arm/mach-at91/setup.c +@@ -333,7 +333,7 @@ static void at91_dt_rstc(void) + + of_id = of_match_node(rstc_ids, np); + if (!of_id) +- panic("AT91: rtsc no restart function available\n"); ++ panic("AT91: rtsc no restart function availlable\n"); + + arm_pm_restart = of_id->data; + +diff --git a/arch/arm/mach-imx/headsmp.S b/arch/arm/mach-imx/headsmp.S +index 7e49deb..921fc15 100644 +--- a/arch/arm/mach-imx/headsmp.S ++++ b/arch/arm/mach-imx/headsmp.S +@@ -17,53 +17,6 @@ + + .section ".text.head", "ax" + +-/* +- * The secondary kernel init calls v7_flush_dcache_all before it enables +- * the L1; however, the L1 comes out of reset in an undefined state, so +- * the clean + invalidate performed by v7_flush_dcache_all causes a bunch +- * of cache lines with uninitialized data and uninitialized tags to get +- * written out to memory, which does really unpleasant things to the main +- * processor. We fix this by performing an invalidate, rather than a +- * clean + invalidate, before jumping into the kernel. +- * +- * This funciton is cloned from arch/arm/mach-tegra/headsmp.S, and needs +- * to be called for both secondary cores startup and primary core resume +- * procedures. Ideally, it should be moved into arch/arm/mm/cache-v7.S. +- */ +-ENTRY(v7_invalidate_l1) +- mov r0, #0 +- mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache +- mcr p15, 2, r0, c0, c0, 0 +- mrc p15, 1, r0, c0, c0, 0 +- +- ldr r1, =0x7fff +- and r2, r1, r0, lsr #13 +- +- ldr r1, =0x3ff +- +- and r3, r1, r0, lsr #3 @ NumWays - 1 +- add r2, r2, #1 @ NumSets +- +- and r0, r0, #0x7 +- add r0, r0, #4 @ SetShift +- +- clz r1, r3 @ WayShift +- add r4, r3, #1 @ NumWays +-1: sub r2, r2, #1 @ NumSets-- +- mov r3, r4 @ Temp = NumWays +-2: subs r3, r3, #1 @ Temp-- +- mov r5, r3, lsl r1 +- mov r6, r2, lsl r0 +- orr r5, r5, r6 @ Reg = (Temp<= CPUFREQ_MIN_FREQ_HZ) + ret |= opp_add(dev, tmp, 0); + } +- freq = clk_round_rate(cpuclk, CPUFREQ_MIN_FREQ_HZ); ++ freq = xilinx_calc_opp_freq(cpuclk, CPUFREQ_MIN_FREQ_HZ); + if (freq >= CPUFREQ_MIN_FREQ_HZ && IS_ERR(opp_find_freq_exact(dev, freq, + 1))) + ret |= opp_add(dev, freq, 0); +@@ -156,11 +135,11 @@ static int __init xilinx_opp_init(void) + + return ret; + } +-device_initcall(xilinx_opp_init); ++device_initcall(zynq_opp_init); + #endif + + #ifdef CONFIG_CACHE_L2X0 +-static int __init xilinx_l2c_init(void) ++static int __init zynq_l2c_init(void) + { + /* 64KB way size, 8-way associativity, parity disabled, + * prefetching option */ +@@ -170,19 +149,20 @@ static int __init xilinx_l2c_init(void) + return l2x0_of_init(0x72060000, 0xF0F0FFFF); + #endif + } +-early_initcall(xilinx_l2c_init); ++early_initcall(zynq_l2c_init); + #endif + + /** + * xilinx_irq_init() - Interrupt controller initialization for the GIC. + */ +-static void __init xilinx_irq_init(void) ++static void __init zynq_irq_init(void) + { + of_irq_init(zynq_dt_irq_match); ++ gic_arch_extn.flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND; + } + + #ifdef CONFIG_XILINX_L1_PREFETCH +-static void __init xilinx_data_prefetch_enable(void *info) ++static void __init zynq_data_prefetch_enable(void *info) + { + /* + * Enable prefetching in aux control register. L2 prefetch must +@@ -195,45 +175,76 @@ static void __init xilinx_data_prefetch_enable(void *info) + } + #endif + +-static void __init xilinx_init_late(void) ++static void __init zynq_init_late(void) + { + zynq_pm_late_init(); + + #ifdef CONFIG_XILINX_L1_PREFETCH +- on_each_cpu(xilinx_data_prefetch_enable, NULL, 0); ++ on_each_cpu(zynq_data_prefetch_enable, NULL, 0); + #endif + } + + /** +- * xilinx_init_machine() - System specific initialization, intended to be +- * called from board specific initialization. ++ * zynq_init_machine - System specific initialization, intended to be ++ * called from board specific initialization. + */ +-static void __init xilinx_init_machine(void) ++static void __init zynq_init_machine(void) + { + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + } + +-static void xilinx_system_reset(char mode, const char *cmd) ++ ++static struct map_desc zynq_cortex_a9_scu_map __initdata = { ++ .length = SZ_256, ++ .type = MT_DEVICE, ++}; ++ ++static void __init zynq_scu_map_io(void) ++{ ++ unsigned long base; ++ ++ /* FIXME will be replaced by scu_get_base(void) in 3.8 */ ++ asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (base)); ++ ++ zynq_cortex_a9_scu_map.pfn = __phys_to_pfn(base); ++ /* Expected address is in vmalloc area that's why simple assign here */ ++ zynq_cortex_a9_scu_map.virtual = base; ++ iotable_init(&zynq_cortex_a9_scu_map, 1); ++ scu_base = (void __iomem *)base; ++ BUG_ON(!scu_base); ++} ++ ++/** ++ * zynq_map_io - Create memory mappings needed for early I/O. ++ */ ++static void __init zynq_map_io(void) ++{ ++ debug_ll_io_init(); ++ zynq_scu_map_io(); ++} ++ ++static void zynq_system_reset(char mode, const char *cmd) + { +- xslcr_system_reset(); ++ zynq_slcr_system_reset(); + } + +-static const char * const xilinx_dt_match[] = { ++static const char * const zynq_dt_match[] = { + "xlnx,zynq-zc702", + "xlnx,zynq-zc706", + "xlnx,zynq-zc770", ++ "xlnx,zynq-7000", + NULL + }; + + MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform") + .smp = smp_ops(zynq_smp_ops), +- .map_io = xilinx_map_io, +- .init_irq = xilinx_irq_init, ++ .map_io = zynq_map_io, ++ .init_irq = zynq_irq_init, + .handle_irq = gic_handle_irq, +- .init_machine = xilinx_init_machine, +- .init_late = xilinx_init_late, ++ .init_machine = zynq_init_machine, ++ .init_late = zynq_init_late, + .timer = &xttcps_sys_timer, +- .dt_compat = xilinx_dt_match, +- .reserve = xilinx_memory_init, +- .restart = xilinx_system_reset, ++ .dt_compat = zynq_dt_match, ++ .reserve = zynq_memory_init, ++ .restart = zynq_system_reset, + MACHINE_END +diff --git a/arch/arm/mach-zynq/common.h b/arch/arm/mach-zynq/common.h +index fa732df..e53cccd 100644 +--- a/arch/arm/mach-zynq/common.h ++++ b/arch/arm/mach-zynq/common.h +@@ -19,25 +19,35 @@ + + void __init xttcps_timer_init_old(void); + void __init xttcpss_timer_init(void); +-void platform_device_init(void); + ++void zynq_secondary_startup(void); ++ ++extern int zynq_slcr_init(void); ++extern void zynq_slcr_system_reset(void); ++extern void zynq_slcr_cpu_stop(int cpu); ++extern void zynq_slcr_cpu_start(int cpu); ++ ++#ifdef CONFIG_SMP ++extern void secondary_startup(void); ++extern char zynq_secondary_trampoline; ++extern char zynq_secondary_trampoline_jump; ++extern char zynq_secondary_trampoline_end; + extern int __cpuinit zynq_cpun_start(u32 address, int cpu); ++extern struct smp_operations zynq_smp_ops __initdata; ++#endif + + extern void xslcr_write(u32 val, u32 offset); + extern u32 xslcr_read(u32 offset); + +-extern int xslcr_init(void); +-extern void xslcr_system_reset(void); +- + extern void xslcr_init_preload_fpga(void); + extern void xslcr_init_postload_fpga(void); + +-/* multiplatform use core.h for this purpose */ +-extern void secondary_startup(void); +- + extern void __iomem *zynq_slcr_base; + extern void __iomem *scu_base; + ++/* Hotplug */ ++extern void zynq_platform_cpu_die(unsigned int cpu); ++ + #ifdef CONFIG_SUSPEND + int zynq_pm_late_init(void); + #else +@@ -50,9 +60,6 @@ static inline int zynq_pm_late_init(void) + extern unsigned int zynq_sys_suspend_sz; + int zynq_sys_suspend(void __iomem *ddrc_base, void __iomem *slcr_base); + +-extern void platform_cpu_die(unsigned int cpu); +-extern struct smp_operations zynq_smp_ops; +- + #define IRQ_XILINX_MSI_0 128 + + #endif +diff --git a/arch/arm/mach-zynq/headsmp.S b/arch/arm/mach-zynq/headsmp.S +new file mode 100644 +index 0000000..d20a079 +--- /dev/null ++++ b/arch/arm/mach-zynq/headsmp.S +@@ -0,0 +1,28 @@ ++/* ++ * Copyright (c) 2013 Steffen Trumtrar ++ * Copyright (c) 2012-2013 Xilinx ++ * ++ * 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 ++#include ++ ++ __CPUINIT ++ ++ENTRY(zynq_secondary_trampoline) ++ ldr r0, [pc] ++ bx r0 ++.globl zynq_secondary_trampoline_jump ++zynq_secondary_trampoline_jump: ++ /* Space for jumping address */ ++ .word /* cpu 1 */ ++.globl zynq_secondary_trampoline_end ++zynq_secondary_trampoline_end: ++ENDPROC(zynq_secondary_trampoline) ++ ++ENTRY(zynq_secondary_startup) ++ bl v7_invalidate_l1 ++ b secondary_startup ++ENDPROC(zynq_secondary_startup) +diff --git a/arch/arm/mach-zynq/hotplug.c b/arch/arm/mach-zynq/hotplug.c +index 22b1084..5052c70 100644 +--- a/arch/arm/mach-zynq/hotplug.c ++++ b/arch/arm/mach-zynq/hotplug.c +@@ -1,8 +1,10 @@ + /* +- * linux/arch/arm/mach-realview/hotplug.c ++ * Copyright (C) 2012-2013 Xilinx + * +- * Copyright (C) 2002 ARM Ltd. +- * All Rights Reserved ++ * based on linux/arch/arm/mach-realview/hotplug.c ++ * ++ * Copyright (C) 2002 ARM Ltd. ++ * All Rights Reserved + * + * 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 +@@ -14,8 +16,9 @@ + + #include + #include ++#include "common.h" + +-static inline void cpu_enter_lowpower(void) ++static inline void zynq_cpu_enter_lowpower(void) + { + unsigned int v; + +@@ -37,79 +40,20 @@ static inline void cpu_enter_lowpower(void) + : "cc"); + } + +-static inline void cpu_leave_lowpower(void) +-{ +- unsigned int v; +- +- asm volatile( +- " mrc p15, 0, %0, c1, c0, 0\n" +- " orr %0, %0, %1\n" +- " mcr p15, 0, %0, c1, c0, 0\n" +- " mrc p15, 0, %0, c1, c0, 1\n" +- " orr %0, %0, #0x40\n" +- " mcr p15, 0, %0, c1, c0, 1\n" +- : "=&r" (v) +- : "Ir" (CR_C) +- : "cc"); +-} +- +-static inline void platform_do_lowpower(unsigned int cpu, int *spurious) +-{ +- /* +- * there is no power-control hardware on this platform, so all +- * we can do is put the core into WFI; this is safe as the calling +- * code will have already disabled interrupts +- */ +- for (;;) { +- dsb(); +- wfi(); +- +- /* +- * Getting here, means that we have come out of WFI without +- * having been woken up - this shouldn't happen +- * +- * Just note it happening - when we're woken, we can report +- * its occurrence. +- */ +- (*spurious)++; +- } +-} +- +-int platform_cpu_kill(unsigned int cpu) +-{ +- return 1; +-} +- + /* + * platform-specific code to shutdown a CPU + * + * Called with IRQs disabled + */ +-void platform_cpu_die(unsigned int cpu) ++void zynq_platform_cpu_die(unsigned int cpu) + { +- int spurious = 0; +- +- /* +- * we're ready for shutdown now, so do it +- */ +- cpu_enter_lowpower(); +- platform_do_lowpower(cpu, &spurious); ++ zynq_cpu_enter_lowpower(); + + /* +- * bring this CPU back into the world of cache +- * coherency, and then restore interrupts +- */ +- cpu_leave_lowpower(); +- +- if (spurious) +- pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious); +-} +- +-int platform_cpu_disable(unsigned int cpu) +-{ +- /* +- * we don't allow CPU 0 to be shutdown (it is still too special +- * e.g. clock tick interrupts) ++ * there is no power-control hardware on this platform, so all ++ * we can do is put the core into WFI; this is safe as the calling ++ * code will have already disabled interrupts + */ +- return cpu == 0 ? -EPERM : 0; ++ for (;;) ++ cpu_do_idle(); + } +diff --git a/arch/arm/mach-zynq/platsmp.c b/arch/arm/mach-zynq/platsmp.c +index ef05183..a83fb65 100644 +--- a/arch/arm/mach-zynq/platsmp.c ++++ b/arch/arm/mach-zynq/platsmp.c +@@ -2,7 +2,7 @@ + * This file contains Xilinx specific SMP code, used to start up + * the second processor. + * +- * Copyright (C) 2011 Xilinx ++ * Copyright (C) 2011-2013 Xilinx + * + * based on linux/arch/arm/mach-realview/platsmp.c + * +@@ -27,14 +27,6 @@ + #include + #include "common.h" + +-static DEFINE_SPINLOCK(boot_lock); +- +-/* Store pointer to ioremap area which points to address 0x0 */ +-static u8 __iomem *zero; +- +-static unsigned int mem_backup[3]; +-static unsigned int mem_backup_done; +- + /* + * Store number of cores in the system + * Because of scu_get_core_count() must be in __init section and can't +@@ -55,67 +47,56 @@ static void __cpuinit zynq_secondary_init(unsigned int cpu) + * for us: do so + */ + gic_secondary_init(0); +- +- /* Indicate to the primary core that the secondary is up and running. +- * Let the write buffer drain. +- */ +- +- /* Restore memory content */ +- if (mem_backup_done) { +- __raw_writel(mem_backup[0], zero + 0x0); +- __raw_writel(mem_backup[1], zero + 0x4); +- __raw_writel(mem_backup[2], zero + 0x8); +- } +- +- +- /* +- * Synchronise with the boot thread. +- */ +- spin_lock(&boot_lock); +- spin_unlock(&boot_lock); + } + + int __cpuinit zynq_cpun_start(u32 address, int cpu) + { +- if (cpu > ncores) { ++ u32 trampoline_code_size = &zynq_secondary_trampoline_end - ++ &zynq_secondary_trampoline; ++ ++ if (cpu >= ncores) { + pr_warn("CPU No. is not available in the system\n"); + return -1; + } + +- mem_backup_done = 0; +- + /* MS: Expectation that SLCR are directly map and accessible */ + /* Not possible to jump to non aligned address */ +- if (!(address & 3) && (!address || (address >= 0xC))) { +- /* stop CLK and reset CPUn */ +- xslcr_write(0x11 << cpu, 0x244); +- +- /* +- * This is elegant way how to jump to any address +- * 0x0: Load address at 0x8 to r0 +- * 0x4: Jump by mov instruction +- * 0x8: Jumping address +- */ ++ if (!(address & 3) && (!address || (address >= trampoline_code_size))) { ++ /* Store pointer to ioremap area which points to address 0x0 */ ++ static u8 __iomem *zero; ++ u32 trampoline_size = &zynq_secondary_trampoline_jump - ++ &zynq_secondary_trampoline; ++ ++ zynq_slcr_cpu_stop(cpu); + if (address) { +- if (!zero) { +- pr_warn("BOOTUP jump vectors is not mapped!\n"); +- return -1; ++ if (__pa(PAGE_OFFSET)) { ++ zero = ioremap(0, trampoline_code_size); ++ if (!zero) { ++ pr_warn("BOOTUP jump vectors not accessible\n"); ++ return -1; ++ } ++ } else { ++ zero = (__force u8 __iomem *)PAGE_OFFSET; + } +- mem_backup[0] = __raw_readl(zero + 0x0); +- mem_backup[1] = __raw_readl(zero + 0x4); +- mem_backup[2] = __raw_readl(zero + 0x8); +- mem_backup_done = 1; +- __raw_writel(0xe59f0000, zero + 0x0);/* 0:ldr r0, [8] */ +- __raw_writel(0xe1a0f000, zero + 0x4);/* 4:mov pc, r0 */ +- __raw_writel(address, zero + 0x8);/* 8:.word address */ +- } + +- flush_cache_all(); +- outer_flush_all(); +- wmb(); +- +- xslcr_write(0x10 << cpu, 0x244); /* enable CPUn */ +- xslcr_write(0x0 << cpu, 0x244); /* enable CLK for CPUn */ ++ /* ++ * This is elegant way how to jump to any address ++ * 0x0: Load address at 0x8 to r0 ++ * 0x4: Jump by mov instruction ++ * 0x8: Jumping address ++ */ ++ memcpy((__force void *)zero, &zynq_secondary_trampoline, ++ trampoline_size); ++ writel(address, zero + trampoline_size); ++ ++ flush_cache_all(); ++ outer_flush_range(0, trampoline_code_size); ++ smp_wmb(); ++ ++ if (__pa(PAGE_OFFSET)) ++ iounmap(zero); ++ } ++ zynq_slcr_cpu_start(cpu); + + return 0; + } +@@ -129,27 +110,7 @@ EXPORT_SYMBOL(zynq_cpun_start); + static int __cpuinit zynq_boot_secondary(unsigned int cpu, + struct task_struct *idle) + { +- int ret; +- +- /* +- * set synchronisation state between this boot processor +- * and the secondary one +- */ +- spin_lock(&boot_lock); +- +- ret = zynq_cpun_start(virt_to_phys(secondary_startup), cpu); +- if (ret) { +- spin_unlock(&boot_lock); +- return -1; +- } +- +- /* +- * now the secondary core is starting up let it run its +- * calibrations, then wait for it to finish +- */ +- spin_unlock(&boot_lock); +- +- return 0; ++ return zynq_cpun_start(virt_to_phys(zynq_secondary_startup), cpu); + } + + /* +@@ -173,22 +134,6 @@ static void __init zynq_smp_prepare_cpus(unsigned int max_cpus) + int i; + + /* +- * Remap the first three addresses at zero which are used +- * for 32bit long jump for SMP. Look at zynq_cpun_start() +- */ +-#if defined(CONFIG_PHYS_OFFSET) && (CONFIG_PHYS_OFFSET != 0) +- zero = ioremap(0, 12); +- if (!zero) { +- pr_warn("!!!! BOOTUP jump vectors can't be used !!!!\n"); +- while (1) +- ; +- } +-#else +- /* The first three addresses at zero are already mapped */ +- zero = (__force u8 __iomem *)CONFIG_PAGE_OFFSET; +-#endif +- +- /* + * Initialise the present map, which describes the set of CPUs + * actually populated at the present time. + */ +@@ -198,12 +143,21 @@ static void __init zynq_smp_prepare_cpus(unsigned int max_cpus) + scu_enable(scu_base); + } + ++#ifdef CONFIG_HOTPLUG_CPU ++static int zynq_cpu_kill(unsigned cpu) ++{ ++ zynq_slcr_cpu_stop(cpu); ++ return 1; ++} ++#endif ++ + struct smp_operations zynq_smp_ops __initdata = { + .smp_init_cpus = zynq_smp_init_cpus, + .smp_prepare_cpus = zynq_smp_prepare_cpus, + .smp_secondary_init = zynq_secondary_init, + .smp_boot_secondary = zynq_boot_secondary, + #ifdef CONFIG_HOTPLUG_CPU +- .cpu_die = platform_cpu_die, ++ .cpu_die = zynq_platform_cpu_die, ++ .cpu_kill = zynq_cpu_kill, + #endif + }; +diff --git a/arch/arm/mach-zynq/pm.c b/arch/arm/mach-zynq/pm.c +index c3bc657..a888f99 100644 +--- a/arch/arm/mach-zynq/pm.c ++++ b/arch/arm/mach-zynq/pm.c +@@ -20,6 +20,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -44,10 +45,19 @@ + #define SCU_STBY_EN_MASK BIT(5) + #define TOPSW_CLK_CTRL_DIS_MASK BIT(0) + +-static struct clk *cpupll; + static void __iomem *ddrc_base; + static void __iomem *ocm_base; + ++static int zynq_pm_prepare_late(void) ++{ ++ return zynq_clk_suspend_early(); ++} ++ ++static void zynq_pm_wake(void) ++{ ++ zynq_clk_resume_late(); ++} ++ + static int zynq_pm_suspend(unsigned long arg) + { + u32 reg; +@@ -113,23 +123,6 @@ static int zynq_pm_suspend(unsigned long arg) + do_ddrpll_bypass = 0; + } + +- /* +- * at this point PLLs are supposed to be bypassed: +- * +- * DDRPLL: Is bypassed without further sanity checking in the suspend +- * routine which is called below and executed from OCM. +- * +- * IOPLL/ARMPLL: By now all clock consumers should have released their +- * clock resulting in the PLLs to be bypassed. To account for timers and +- * similar which run in the CPU clock domain we call a disable on the +- * CPU clock's PLL to bypass it. +- * +- * A wake up device would prevent its source PLL from +- * being bypassed, unless its the DDRPLL. +- */ +- if (!IS_ERR(cpupll)) +- clk_disable(cpupll); +- + /* Transfer to suspend code in OCM */ + if (do_ddrpll_bypass) { + /* +@@ -146,9 +139,6 @@ static int zynq_pm_suspend(unsigned long arg) + wfi(); + } + +- if (!IS_ERR(cpupll)) +- clk_enable(cpupll); +- + /* Restore original OCM contents */ + if (do_ddrpll_bypass) { + memcpy((__force void *)ocm_base, ocm_swap_area, +@@ -207,7 +197,9 @@ static int zynq_pm_enter(suspend_state_t suspend_state) + } + + static const struct platform_suspend_ops zynq_pm_ops = { ++ .prepare_late = zynq_pm_prepare_late, + .enter = zynq_pm_enter, ++ .wake = zynq_pm_wake, + .valid = suspend_valid_only_mem, + }; + +@@ -266,15 +258,6 @@ static void __iomem *zynq_pm_remap_ocm(void) + + int __init zynq_pm_late_init(void) + { +- cpupll = clk_get_sys("CPU_6OR4X_CLK", NULL); +- if (!IS_ERR(cpupll)) { +- cpupll = clk_get_parent(cpupll); +- if (!IS_ERR(cpupll)) +- cpupll = clk_get_parent(cpupll); +- } +- if (IS_ERR(cpupll)) +- pr_warn("%s: CPUPLL not found.\n", __func__); +- + ddrc_base = zynq_pm_ioremap("xlnx,ps7-ddrc"); + if (!ddrc_base) + pr_warn("%s: Unable to map DDRC IO memory.\n", __func__); +diff --git a/arch/arm/mach-zynq/slcr.c b/arch/arm/mach-zynq/slcr.c +index 50a46afa..3c688da 100644 +--- a/arch/arm/mach-zynq/slcr.c ++++ b/arch/arm/mach-zynq/slcr.c +@@ -1,7 +1,7 @@ + /* + * Xilinx SLCR driver + * +- * Copyright (c) 2011 Xilinx Inc. ++ * Copyright (c) 2011-2013 Xilinx Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License +@@ -33,19 +33,6 @@ + + #define XSLCR_LOCK 0x4 /* SLCR lock register */ + #define XSLCR_UNLOCK 0x8 /* SCLR unlock register */ +-#define XSLCR_APER_CLK_CTRL_OFFSET 0x12C /* AMBA Peripheral Clk Control */ +-#define XSLCR_USB0_CLK_CTRL_OFFSET 0x130 /* USB 0 ULPI Clock Control */ +-#define XSLCR_USB1_CLK_CTRL_OFFSET 0x134 /* USB 1 ULPI Clock Control */ +-#define XSLCR_EMAC0_RCLK_CTRL_OFFSET 0x138 /* EMAC0 RX Clock Control */ +-#define XSLCR_EMAC1_RCLK_CTRL_OFFSET 0x13C /* EMAC1 RX Clock Control */ +-#define XSLCR_EMAC0_CLK_CTRL_OFFSET 0x140 /* EMAC0 Reference Clk Control */ +-#define XSLCR_EMAC1_CLK_CTRL_OFFSET 0x144 /* EMAC1 Reference Clk Control */ +-#define XSLCR_SMC_CLK_CTRL_OFFSET 0x148 /* SMC Reference Clock Control */ +-#define XSLCR_QSPI_CLK_CTRL_OFFSET 0x14C /* QSPI Reference Clock Control */ +-#define XSLCR_SDIO_CLK_CTRL_OFFSET 0x150 /* SDIO Reference Clock Control */ +-#define XSLCR_UART_CLK_CTRL_OFFSET 0x154 /* UART Reference Clock Control */ +-#define XSLCR_SPI_CLK_CTRL_OFFSET 0x158 /* SPI Reference Clock Control */ +-#define XSLCR_CAN_CLK_CTRL_OFFSET 0x15C /* CAN Reference Clock Control */ + #define XSLCR_PSS_RST_CTRL_OFFSET 0x200 /* PSS Software Reset Control */ + #define XSLCR_DDR_RST_CTRL_OFFSET 0x204 /* DDR Software Reset Control */ + #define XSLCR_AMBA_RST_CTRL_OFFSET 0x208 /* AMBA Software Reset Control */ +@@ -68,26 +55,6 @@ + #define XSLCR_MIO_PIN_00_OFFSET 0x700 /* MIO PIN0 control register */ + #define XSLCR_LVL_SHFTR_EN_OFFSET 0x900 /* Level Shifters Enable */ + +-/* Bit masks for AMBA Peripheral Clock Control register */ +-#define XSLCR_APER_CLK_CTRL_DMA0_MASK 0x00000001 /* DMA0 AMBA Clock active */ +-#define XSLCR_APER_CLK_CTRL_USB0_MASK 0x00000004 /* USB0 AMBA Clock active */ +-#define XSLCR_APER_CLK_CTRL_USB1_MASK 0x00000008 /* USB1 AMBA Clock active */ +-#define XSLCR_APER_CLK_CTRL_EMAC0_MASK 0x00000040 /* EMAC0 AMBA Clock active */ +-#define XSLCR_APER_CLK_CTRL_EMAC1_MASK 0x00000080 /* EMAC1 AMBA Clock active */ +-#define XSLCR_APER_CLK_CTRL_SDI0_MASK 0x00000400 /* SDIO0 AMBA Clock active */ +-#define XSLCR_APER_CLK_CTRL_SDI1_MASK 0x00000800 /* SDIO1 AMBA Clock active */ +-#define XSLCR_APER_CLK_CTRL_SPI0_MASK 0x00004000 /* SPI0 AMBA Clock active */ +-#define XSLCR_APER_CLK_CTRL_SPI1_MASK 0x00008000 /* SPI1 AMBA Clock active */ +-#define XSLCR_APER_CLK_CTRL_CAN0_MASK 0x00010000 /* CAN0 AMBA Clock active */ +-#define XSLCR_APER_CLK_CTRL_CAN1_MASK 0x00020000 /* CAN1 AMBA Clock active */ +-#define XSLCR_APER_CLK_CTRL_I2C0_MASK 0x00040000 /* I2C0 AMBA Clock active */ +-#define XSLCR_APER_CLK_CTRL_I2C1_MASK 0x00080000 /* I2C1 AMBA Clock active */ +-#define XSLCR_APER_CLK_CTRL_UART0_MASK 0x00100000 /* UART0 AMBA Clock active */ +-#define XSLCR_APER_CLK_CTRL_UART1_MASK 0x00200000 /* UART1 AMBA Clock active */ +-#define XSLCR_APER_CLK_CTRL_GPIO_MASK 0x00400000 /* GPIO AMBA Clock active */ +-#define XSLCR_APER_CLK_CTRL_QSPI_MASK 0x00800000 /* QSPI AMBA Clock active */ +-#define XSLCR_APER_CLK_CTRL_SMC_MASK 0x01000000 /* SMC AMBA Clock active */ +- + #define XSLCR_MIO_L0_SHIFT 1 + #define XSLCR_MIO_L1_SHIFT 2 + #define XSLCR_MIO_L2_SHIFT 3 +@@ -160,6 +127,15 @@ + #define xslcr_writereg(offset, val) __raw_writel(val, offset) + #define xslcr_readreg(offset) __raw_readl(offset) + ++ ++#define SLCR_PS_RST_CTRL_OFFSET 0x200 /* PS Software Reset Control */ ++ ++#define SLCR_A9_CPU_CLKSTOP 0x10 ++#define SLCR_A9_CPU_RST 0x1 ++ ++#define SLCR_A9_CPU_RST_CTRL 0x244 /* CPU Software Reset Control */ ++#define SLCR_REBOOT_STATUS 0x258 /* PS Reboot Status */ ++ + void __iomem *zynq_slcr_base; + + /** +@@ -182,18 +158,12 @@ static struct xslcr *slcr; + * @max_sets: Max pin sets for this periph + * @numpins: Number of pins for this periph + * @enable_val: Enable value to assign a MIO pin to this periph +- * @amba_clk_mask: AMBA peripheral clock enable mask for this periph +- * @periph_clk_reg: Clock enable register offset for the periph +- * @periph_clk_mask: Clock enable mask for the periph + */ + struct xslcr_mio { + const int *set_pins; + int max_sets; + int numpins; + u32 enable_val; +- u32 amba_clk_mask; +- u32 periph_clk_reg; +- u32 periph_clk_mask; + }; + + /** +@@ -299,11 +269,6 @@ static const char * const mio_periph_name[] = { + "uart1", + }; + +-/* Each bit in this array is a flag that indicates whether a mio peripheral +- * is assigned. The order of bits in this array is same as the order of +- * peripheral names in the array mio_periph_name */ +-static u32 periph_status[2] = {0, 0}; +- + /* Each element in the following array holds the active pinset of a MIO + * peripheral. The order of peripherals in this array is same as the order of + * peripheral names in the array mio_periph_name */ +@@ -674,8 +639,8 @@ static const int uart1_pins[] = { + 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52 + }; + +-/* The following array contains required info for enabling MIO peripherals and +- * their clocks. The order of the structures in this array is same as the order ++/* The following array contains required info for enabling MIO peripherals. ++ * The order of the structures in this array is same as the order + * of peripheral names in the array mio_periph_name */ + static const struct xslcr_mio mio_periphs[] = { + { +@@ -683,794 +648,537 @@ static const struct xslcr_mio mio_periphs[] = { + ARRAY_SIZE(emac0_pins), + XSLCR_MIO_NUM_EMAC_PINS, + XSLCR_MIO_PIN_EMAC_ENABLE, +- XSLCR_APER_CLK_CTRL_EMAC0_MASK, +- XSLCR_EMAC0_CLK_CTRL_OFFSET, +- 0x01, + }, + { + emac1_pins, + ARRAY_SIZE(emac1_pins), + XSLCR_MIO_NUM_EMAC_PINS, + XSLCR_MIO_PIN_EMAC_ENABLE, +- XSLCR_APER_CLK_CTRL_EMAC1_MASK, +- XSLCR_EMAC1_CLK_CTRL_OFFSET, +- 0x01, + }, + { + qspi0_pins, + ARRAY_SIZE(qspi0_pins), + XSLCR_MIO_NUM_QSPI_PINS, + XSLCR_MIO_PIN_QSPI_ENABLE, +- XSLCR_APER_CLK_CTRL_QSPI_MASK, +- XSLCR_QSPI_CLK_CTRL_OFFSET, +- 0x01, + }, + { + qspi0_sel_pins, + ARRAY_SIZE(qspi0_sel_pins), + XSLCR_MIO_NUM_QSPI_SEL_PINS, + XSLCR_MIO_PIN_QSPI_ENABLE, +- 0x00, +- 0x00, +- 0x00, + }, + { + qspi1_pins, + ARRAY_SIZE(qspi1_pins), + XSLCR_MIO_NUM_QSPI_PINS, + XSLCR_MIO_PIN_QSPI_ENABLE, +- XSLCR_APER_CLK_CTRL_QSPI_MASK, +- XSLCR_QSPI_CLK_CTRL_OFFSET, +- 0x01, + }, + { + qspi1_sel_pins, + ARRAY_SIZE(qspi1_sel_pins), + XSLCR_MIO_NUM_QSPI_SEL_PINS, + XSLCR_MIO_PIN_QSPI_ENABLE, +- 0x00, +- 0x00, +- 0x00, + }, + { qspi_foc_pins, + ARRAY_SIZE(qspi_foc_pins), + XSLCR_MIO_NUM_QSPI_FOC_PINS, + XSLCR_MIO_PIN_QSPI_ENABLE, +- 0x00, +- 0x00, +- 0x00, + }, + { + trace_data2_pins, + ARRAY_SIZE(trace_data2_pins), + XSLCR_MIO_NUM_TRACE_DATA2_PINS, + XSLCR_MIO_PIN_TRACE_PORT_ENABLE, +- 0x00, +- 0x00, +- 0x00, + }, + { + trace_data4_pins, + ARRAY_SIZE(trace_data4_pins), + XSLCR_MIO_NUM_TRACE_DATA4_PINS, + XSLCR_MIO_PIN_TRACE_PORT_ENABLE, +- 0x00, +- 0x00, +- 0x00, + }, + { + trace_data8_pins, + ARRAY_SIZE(trace_data8_pins), + XSLCR_MIO_NUM_TRACE_DATA8_PINS, + XSLCR_MIO_PIN_TRACE_PORT_ENABLE, +- 0x00, +- 0x00, +- 0x00, + }, + { + trace_data16_pins, + ARRAY_SIZE(trace_data16_pins), + XSLCR_MIO_NUM_TRACE_DATA4_PINS, + XSLCR_MIO_PIN_TRACE_PORT_ENABLE, +- 0x00, +- 0x00, +- 0x00, + }, + { + usb0_pins, + ARRAY_SIZE(usb0_pins), + XSLCR_MIO_NUM_USB_PINS, + XSLCR_MIO_PIN_USB_ENABLE, +- XSLCR_APER_CLK_CTRL_USB0_MASK, +- XSLCR_USB0_CLK_CTRL_OFFSET, +- 0x01, + }, + { + usb1_pins, + ARRAY_SIZE(usb1_pins), + XSLCR_MIO_NUM_USB_PINS, + XSLCR_MIO_PIN_USB_ENABLE, +- XSLCR_APER_CLK_CTRL_USB1_MASK, +- XSLCR_USB1_CLK_CTRL_OFFSET, +- 0x01, + }, + { + smc_a25_pins, + ARRAY_SIZE(smc_a25_pins), + XSLCR_MIO_NUM_SMC_A25_PINS, + XSLCR_MIO_PIN_SRAM_NOR_ENABLE, +- 0x00, +- 0x00, +- 0x00, + }, + { + smc_cs_pins, + ARRAY_SIZE(smc_cs_pins), + XSLCR_MIO_NUM_SMC_CS_PINS, + XSLCR_MIO_PIN_SRAM_NOR_ENABLE, +- 0x00, +- 0x00, +- 0x00, + }, + { + sram_nor_pins, + ARRAY_SIZE(sram_nor_pins), + XSLCR_MIO_NUM_SRAM_NOR_PINS, + XSLCR_MIO_PIN_SRAM_NOR_ENABLE, +- XSLCR_APER_CLK_CTRL_SMC_MASK, +- XSLCR_SMC_CLK_CTRL_OFFSET, +- 0x01, + }, + { + nand_pins, + ARRAY_SIZE(nand_pins), + XSLCR_MIO_NUM_NAND_PINS, + XSLCR_MIO_PIN_NAND_ENABLE, +- XSLCR_APER_CLK_CTRL_SMC_MASK, +- XSLCR_SMC_CLK_CTRL_OFFSET, +- 0x01, + }, + { + nand_cs_pins, + ARRAY_SIZE(nand_cs_pins), + XSLCR_MIO_NUM_NAND_CS_PINS, + XSLCR_MIO_PIN_NAND_ENABLE, +- 0x00, +- 0x00, +- 0x00, + }, + { + gpio00_pins, + ARRAY_SIZE(gpio00_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio01_pins, + ARRAY_SIZE(gpio01_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio02_pins, + ARRAY_SIZE(gpio02_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio03_pins, + ARRAY_SIZE(gpio03_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio04_pins, + ARRAY_SIZE(gpio04_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio05_pins, + ARRAY_SIZE(gpio05_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio06_pins, + ARRAY_SIZE(gpio06_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio07_pins, + ARRAY_SIZE(gpio07_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio08_pins, + ARRAY_SIZE(gpio08_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio09_pins, + ARRAY_SIZE(gpio09_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio10_pins, + ARRAY_SIZE(gpio10_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio11_pins, + ARRAY_SIZE(gpio11_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio12_pins, + ARRAY_SIZE(gpio12_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio13_pins, + ARRAY_SIZE(gpio13_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio14_pins, + ARRAY_SIZE(gpio14_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio15_pins, + ARRAY_SIZE(gpio15_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio16_pins, + ARRAY_SIZE(gpio16_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio17_pins, + ARRAY_SIZE(gpio17_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio18_pins, + ARRAY_SIZE(gpio18_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio19_pins, + ARRAY_SIZE(gpio19_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio20_pins, + ARRAY_SIZE(gpio20_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio21_pins, + ARRAY_SIZE(gpio21_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio22_pins, + ARRAY_SIZE(gpio22_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio23_pins, + ARRAY_SIZE(gpio23_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio24_pins, + ARRAY_SIZE(gpio24_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio25_pins, + ARRAY_SIZE(gpio25_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio26_pins, + ARRAY_SIZE(gpio26_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio27_pins, + ARRAY_SIZE(gpio27_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio28_pins, + ARRAY_SIZE(gpio28_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio29_pins, + ARRAY_SIZE(gpio29_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio30_pins, + ARRAY_SIZE(gpio30_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio31_pins, + ARRAY_SIZE(gpio31_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio32_pins, + ARRAY_SIZE(gpio32_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio33_pins, + ARRAY_SIZE(gpio33_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio34_pins, + ARRAY_SIZE(gpio34_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio35_pins, + ARRAY_SIZE(gpio35_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio36_pins, + ARRAY_SIZE(gpio36_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio37_pins, + ARRAY_SIZE(gpio37_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio38_pins, + ARRAY_SIZE(gpio38_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio39_pins, + ARRAY_SIZE(gpio39_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio40_pins, + ARRAY_SIZE(gpio40_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio41_pins, + ARRAY_SIZE(gpio41_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio42_pins, + ARRAY_SIZE(gpio42_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio43_pins, + ARRAY_SIZE(gpio43_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio44_pins, + ARRAY_SIZE(gpio44_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio45_pins, + ARRAY_SIZE(gpio45_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio46_pins, + ARRAY_SIZE(gpio46_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio47_pins, + ARRAY_SIZE(gpio47_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio48_pins, + ARRAY_SIZE(gpio48_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio49_pins, + ARRAY_SIZE(gpio49_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio50_pins, + ARRAY_SIZE(gpio50_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio51_pins, + ARRAY_SIZE(gpio51_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio52_pins, + ARRAY_SIZE(gpio52_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + gpio53_pins, + ARRAY_SIZE(gpio53_pins), + XSLCR_MIO_NUM_GPIO_PINS, + XSLCR_MIO_PIN_GPIO_ENABLE, +- XSLCR_APER_CLK_CTRL_GPIO_MASK, +- 0x00, +- 0x00, + }, + { + can0_pins, + ARRAY_SIZE(can0_pins), + XSLCR_MIO_NUM_CAN_PINS, + XSLCR_MIO_PIN_CAN_ENABLE, +- XSLCR_APER_CLK_CTRL_CAN0_MASK, +- XSLCR_CAN_CLK_CTRL_OFFSET, +- 0x01, + }, + { + can1_pins, + ARRAY_SIZE(can1_pins), + XSLCR_MIO_NUM_CAN_PINS, + XSLCR_MIO_PIN_CAN_ENABLE, +- XSLCR_APER_CLK_CTRL_CAN1_MASK, +- XSLCR_CAN_CLK_CTRL_OFFSET, +- 0x02, + }, + { + iic0_pins, + ARRAY_SIZE(iic0_pins), + XSLCR_MIO_NUM_IIC_PINS, + XSLCR_MIO_PIN_IIC_ENABLE, +- XSLCR_APER_CLK_CTRL_I2C0_MASK, +- 0x00, +- 0x00, + }, + { + iic1_pins, + ARRAY_SIZE(iic1_pins), + XSLCR_MIO_NUM_IIC_PINS, + XSLCR_MIO_PIN_IIC_ENABLE, +- XSLCR_APER_CLK_CTRL_I2C1_MASK, +- 0x00, +- 0x00, + }, + { + jtag0_pins, + ARRAY_SIZE(jtag0_pins), + XSLCR_MIO_NUM_JTAG_PINS, + XSLCR_MIO_PIN_JTAG_ENABLE, +- 0x00, +- 0x00, +- 0x00, + }, + { + wdt_pins, + ARRAY_SIZE(wdt_pins), + XSLCR_MIO_NUM_WDT_PINS, + XSLCR_MIO_PIN_WDT_ENABLE, +- 0x00, +- 0x00, +- 0x00, + }, + { + mdio0_pins, + ARRAY_SIZE(mdio0_pins), + XSLCR_MIO_NUM_MDIO_PINS, + XSLCR_MIO_PIN_MDIO0_ENABLE, +- 0x00, +- 0x00, +- 0x00, + }, + { + sdio0_pins, + ARRAY_SIZE(sdio0_pins), + XSLCR_MIO_NUM_SDIO_PINS, + XSLCR_MIO_PIN_SDIO_ENABLE, +- XSLCR_APER_CLK_CTRL_SDI0_MASK, +- XSLCR_SDIO_CLK_CTRL_OFFSET, +- 0x01, + }, + { + sdio1_pins, + ARRAY_SIZE(sdio1_pins), + XSLCR_MIO_NUM_SDIO_PINS, + XSLCR_MIO_PIN_SDIO_ENABLE, +- XSLCR_APER_CLK_CTRL_SDI1_MASK, +- XSLCR_SDIO_CLK_CTRL_OFFSET, +- 0x02, + }, + { + mdio1_pins, + ARRAY_SIZE(mdio1_pins), + XSLCR_MIO_NUM_MDIO_PINS, + XSLCR_MIO_PIN_MDIO1_ENABLE, +- 0x00, +- 0x00, +- 0x00, + }, + { + spi0_pins, + ARRAY_SIZE(spi0_pins), + XSLCR_MIO_NUM_SPI_PINS, + XSLCR_MIO_PIN_SPI_ENABLE, +- XSLCR_APER_CLK_CTRL_SPI0_MASK, +- XSLCR_SPI_CLK_CTRL_OFFSET, +- 0x01, + }, + { + spi1_pins, + ARRAY_SIZE(spi1_pins), + XSLCR_MIO_NUM_SPI_PINS, + XSLCR_MIO_PIN_SPI_ENABLE, +- XSLCR_APER_CLK_CTRL_SPI0_MASK, +- XSLCR_SPI_CLK_CTRL_OFFSET, +- 0x02, + }, + { + ttc0_pins, + ARRAY_SIZE(ttc0_pins), + XSLCR_MIO_NUM_TTC_PINS, + XSLCR_MIO_PIN_TTC_ENABLE, +- 0x00, +- 0x00, +- 0x00, + }, + { + ttc1_pins, + ARRAY_SIZE(ttc1_pins), + XSLCR_MIO_NUM_TTC_PINS, + XSLCR_MIO_PIN_TTC_ENABLE, +- 0x00, +- 0x00, +- 0x00, + }, + { + uart0_pins, + ARRAY_SIZE(uart0_pins), + XSLCR_MIO_NUM_UART_PINS, + XSLCR_MIO_PIN_UART_ENABLE, +- XSLCR_APER_CLK_CTRL_UART0_MASK, +- XSLCR_UART_CLK_CTRL_OFFSET, +- 0x01, + }, + { + uart1_pins, + ARRAY_SIZE(uart1_pins), + XSLCR_MIO_NUM_UART_PINS, + XSLCR_MIO_PIN_UART_ENABLE, +- XSLCR_APER_CLK_CTRL_UART1_MASK, +- XSLCR_UART_CLK_CTRL_OFFSET, +- 0x02, + }, + }; + ++/* ++ * Each bit in this array is a flag that indicates whether a mio peripheral ++ * is assigned. The order of bits in this array is same as the order of ++ * peripheral names in the array mio_periph_name ++ */ ++static u32 periph_status[DIV_ROUND_UP(ARRAY_SIZE(mio_periphs), 32)]; ++ + /* Peripherals that can be reset thru SLCR */ + static const char * const reset_periph_name[] = { + "pss", +@@ -1592,10 +1300,10 @@ static const struct xslcr_periph_reset reset_info[] = { + }; + + /** +- * xslcr_system_reset - Reset the entire system. ++ * zynq_slcr_system_reset - Reset the entire system. + * + **/ +-void xslcr_system_reset(void) ++void zynq_slcr_system_reset(void) + { + u32 reboot; + +@@ -1731,74 +1439,6 @@ static int xslcr_mio_isavailable(u32 pin) + } + + /** +- * xslcr_enable_mio_clock - Enable the clocks for a MIO peripheral. +- * +- * @mio_periph id used to look up the data needed to enable clocks for this +- * peripheral. +- * +- * This function enables the AMBA clock and the peripheral clock for a +- * peripheral. It also enables Rx clocks in case of EMAC0/EMAC1. +- **/ +-static void xslcr_enable_mio_clock(int mio_periph) +-{ +- const struct xslcr_mio *mio_ptr; +- u32 clk_reg; +- +- mio_ptr = &mio_periphs[mio_periph]; +- +- /* enable AMBA clock and peripheral clock */ +- clk_reg = xslcr_readreg(slcr->regs + XSLCR_APER_CLK_CTRL_OFFSET); +- clk_reg |= mio_ptr->amba_clk_mask; +- xslcr_writereg((slcr->regs + XSLCR_APER_CLK_CTRL_OFFSET), clk_reg); +- +- clk_reg = xslcr_readreg(slcr->regs + mio_ptr->periph_clk_reg); +- clk_reg |= mio_ptr->periph_clk_mask; +- xslcr_writereg((slcr->regs + mio_ptr->periph_clk_reg), clk_reg); +- +- /* enable Rx clocks for EMAC0 and EMAC1 */ +- if (mio_periph == MIO_EMAC0) +- xslcr_writereg((slcr->regs + XSLCR_EMAC0_RCLK_CTRL_OFFSET), +- 0x01); +- else if (mio_periph == MIO_EMAC1) +- xslcr_writereg((slcr->regs + XSLCR_EMAC1_RCLK_CTRL_OFFSET), +- 0x01); +-} +- +-/** +- * xslcr_disable_mio_clock - Disable the clocks for a MIO peripheral. +- * +- * @mio_periph id used to look up the data needed to disable clocks for this +- * peripheral. +- * +- * This function disables the AMBA clock and the peripheral clock for a +- * peripheral. It also disables Rx clocks in case of EMAC0/EMAC1. +- **/ +-static void xslcr_disable_mio_clock(int mio_periph) +-{ +- const struct xslcr_mio *mio_ptr; +- u32 clk_reg; +- +- mio_ptr = &mio_periphs[mio_periph]; +- +- /* disable AMBA clock and peripheral clock */ +- clk_reg = xslcr_readreg(slcr->regs + XSLCR_APER_CLK_CTRL_OFFSET); +- clk_reg &= ~(mio_ptr->amba_clk_mask); +- xslcr_writereg((slcr->regs + XSLCR_APER_CLK_CTRL_OFFSET), clk_reg); +- +- clk_reg = xslcr_readreg(slcr->regs + mio_ptr->periph_clk_reg); +- clk_reg &= ~(mio_ptr->periph_clk_mask); +- xslcr_writereg((slcr->regs + mio_ptr->periph_clk_reg), clk_reg); +- +- /* disable Rx clocks for EMAC0 and EMAC1 */ +- if (mio_periph == MIO_EMAC0) +- xslcr_writereg((slcr->regs + XSLCR_EMAC0_RCLK_CTRL_OFFSET), +- 0x00); +- else if (mio_periph == MIO_EMAC1) +- xslcr_writereg((slcr->regs + XSLCR_EMAC1_RCLK_CTRL_OFFSET), +- 0x00); +-} +- +-/** + * xslcr_enable_mio_peripheral - Enable a MIO peripheral. + * + * @mio: id used to lookup the data needed to enable the peripheral. +@@ -1847,10 +1487,6 @@ static int xslcr_enable_mio_peripheral(int mio) + xslcr_writereg((slcr->regs + ((pin + i) * 4) + + XSLCR_MIO_PIN_00_OFFSET), mio_ptr->enable_val); + +- /* all the pins in the pinset are configured for this peripheral. +- * enable clocks */ +- xslcr_enable_mio_clock(mio); +- + /* mark that the peripheral has been enabled */ + xslcr_set_bit(periph_status, mio); + spin_unlock_irqrestore(&slcr->io_lock, flags); +@@ -1921,9 +1557,6 @@ static int xslcr_disable_mio_peripheral(int mio) + XSLCR_MIO_PIN_XX_TRI_ENABLE); + } + +- /* all the pins in the set are released. disable clocks */ +- xslcr_disable_mio_clock(mio); +- + /* mark that the peripheral has been disabled */ + xslcr_clear_bit(periph_status, mio); + spin_unlock_irqrestore(&slcr->io_lock, flags); +@@ -2031,57 +1664,6 @@ static ssize_t xslcr_store_pinset(struct device *dev, + static DEVICE_ATTR(pinset, 0644, NULL, xslcr_store_pinset); + + /** +- * xslcr_config_mio_clock - Enable/disable the clocks for a MIO peripheral. +- * +- * @dev: pointer to this device. +- * @attr: pointer to the device attribute descriptor. +- * @buf: pointer to the buffer with user data. +- * @size: size of the buf. +- * +- * This function parses the user buffer and enables/disables the clocks of a MIO +- * peripheral specified by the user. +- * +- * return: negative error if invalid arguments are specified or size of the buf +- * if the clocks are enabled/disabled successfully. +- **/ +-static ssize_t xslcr_config_mio_clock(struct device *dev, +- struct device_attribute *attr, +- const char *buf, size_t size) +-{ +- unsigned long flags, en; +- int mio, ret; +- +- /* check if a valid peripheral is specified */ +- for (mio = 0; mio < ARRAY_SIZE(mio_periph_name); mio++) { +- if (sysfs_streq(dev_name(dev), mio_periph_name[mio]) == 1) +- break; +- } +- +- if (mio == ARRAY_SIZE(mio_periph_name)) { +- dev_err(dev, "Invalid peripheral specified\n"); +- return -EINVAL; +- } +- +- ret = kstrtoul(buf, 10, &en); +- if ((ret) || (en > 1)) { +- dev_err(dev, "Invalid user argument\n"); +- return -EINVAL; +- } +- +- /* enable/disable the clocks */ +- spin_lock_irqsave(&slcr->io_lock, flags); +- if (en == 1) +- xslcr_enable_mio_clock(mio); +- else if (en == 0) +- xslcr_disable_mio_clock(mio); +- +- spin_unlock_irqrestore(&slcr->io_lock, flags); +- return size; +-} +- +-static DEVICE_ATTR(clock, 0644, NULL, xslcr_config_mio_clock); +- +-/** + * xslcr_get_periph_status - Get the current status of a MIO peripheral. + * + * @dev: pointer to this device. +@@ -2215,7 +1797,6 @@ static DEVICE_ATTR(mio_pin_status, 0644, show_mio_pin_status, NULL); + static const struct attribute *xslcr_mio_attrs[] = { + &dev_attr_enable_pinset.attr, + &dev_attr_pinset.attr, +- &dev_attr_clock.attr, + &dev_attr_status.attr, + NULL, + }; +@@ -2469,12 +2050,37 @@ static int __init xslcr_arch_init(void) + module_init(xslcr_arch_init); + + /** +- * xslcr_init() ++ * zynq_slcr_cpu_start - Start cpu ++ * @cpu: cpu number ++ */ ++void zynq_slcr_cpu_start(int cpu) ++{ ++ u32 reg = readl(zynq_slcr_base + SLCR_A9_CPU_RST_CTRL); ++ ++ reg &= ~(SLCR_A9_CPU_RST << cpu); ++ writel(reg, zynq_slcr_base + SLCR_A9_CPU_RST_CTRL); ++ reg &= ~(SLCR_A9_CPU_CLKSTOP << cpu); ++ writel(reg, zynq_slcr_base + SLCR_A9_CPU_RST_CTRL); ++} ++ ++/** ++ * zynq_slcr_cpu_stop - Stop cpu ++ * @cpu: cpu number ++ */ ++void zynq_slcr_cpu_stop(int cpu) ++{ ++ u32 reg = readl(zynq_slcr_base + SLCR_A9_CPU_RST_CTRL); ++ reg |= (SLCR_A9_CPU_CLKSTOP | SLCR_A9_CPU_RST) << cpu; ++ writel(reg, zynq_slcr_base + SLCR_A9_CPU_RST_CTRL); ++} ++ ++/** ++ * zynq_slcr_init + * Returns 0 on success, negative errno otherwise. + * + * Called early during boot from platform code to remap SLCR area. + */ +-int __init xslcr_init(void) ++int __init zynq_slcr_init(void) + { + struct device_node *np; + +diff --git a/arch/arm/mach-zynq/timer.c b/arch/arm/mach-zynq/timer.c +index 9bef11c..909b0d3 100644 +--- a/arch/arm/mach-zynq/timer.c ++++ b/arch/arm/mach-zynq/timer.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + #include "common.h" + +@@ -50,6 +51,7 @@ + #define XTTCPS_ISR_OFFSET 0x54 /* Interrupt Status Reg, RO */ + #define XTTCPS_IER_OFFSET 0x60 /* Interrupt Enable Reg, RW */ + ++#define XTTCPS_CLK_CNTRL_CSRC_MASK (1 << 5) /* clock source */ + #define XTTCPS_CNT_CNTRL_DISABLE_MASK 0x1 + + /* +@@ -95,6 +97,8 @@ struct xttcps_timer_clockevent { + #define to_xttcps_timer_clkevent(x) \ + container_of(x, struct xttcps_timer_clockevent, ce) + ++static void __iomem *sched_clock_val_reg; ++ + /** + * xttcps_set_interval - Set the timer interval value + * +@@ -156,6 +160,11 @@ static cycle_t __xttc_clocksource_read(struct clocksource *cs) + XTTCPS_COUNT_VAL_OFFSET); + } + ++static u32 xttc_sched_clock_read(void) ++{ ++ return __raw_readl(sched_clock_val_reg); ++} ++ + /** + * xttcps_set_next_event - Sets the time interval for next event + * +@@ -295,6 +304,9 @@ static void __init zynq_ttc_setup_clocksource(struct clk *clk, + if (WARN_ON(err)) + return; + ++ sched_clock_val_reg = base + XTTCPS_COUNT_VAL_OFFSET; ++ setup_sched_clock(xttc_sched_clock_read , 16, ++ clk_get_rate(ttccs->xttc.clk) / PRESCALE); + } + + static int xttcps_rate_change_clockevent_cb(struct notifier_block *nb, +@@ -392,7 +404,9 @@ static void __init xttcps_timer_init(struct device_node *timer) + { + unsigned int irq; + void __iomem *timer_baseaddr; +- struct clk *clk; ++ struct clk *clk_cs; ++ struct clk *clk_ce; ++ int clksel; + + /* + * Get the 1st Triple Timer Counter (TTC) block from the device tree +@@ -411,14 +425,24 @@ static void __init xttcps_timer_init(struct device_node *timer) + BUG(); + } + +- clk = clk_get_sys("CPU_1X_CLK", NULL); +- if (IS_ERR(clk)) { +- pr_err("ERROR: timer input clock not found\n"); ++ clksel = __raw_readl(timer_baseaddr + XTTCPS_CLK_CNTRL_OFFSET); ++ clksel = !!(clksel & XTTCPS_CLK_CNTRL_CSRC_MASK); ++ clk_cs = of_clk_get(timer, clksel); ++ if (IS_ERR(clk_cs)) { ++ pr_err("ERROR: clock source input clock not found\n"); ++ BUG(); ++ } ++ ++ clksel = __raw_readl(timer_baseaddr + XTTCPS_CLK_CNTRL_OFFSET + 4); ++ clksel = !!(clksel & XTTCPS_CLK_CNTRL_CSRC_MASK); ++ clk_ce = of_clk_get(timer, clksel); ++ if (IS_ERR(clk_ce)) { ++ pr_err("ERROR: clock event input clock not found\n"); + BUG(); + } + +- zynq_ttc_setup_clocksource(clk, timer_baseaddr); +- zynq_ttc_setup_clockevent(clk, timer_baseaddr + 4, irq); ++ zynq_ttc_setup_clocksource(clk_cs, timer_baseaddr); ++ zynq_ttc_setup_clockevent(clk_ce, timer_baseaddr + 4, irq); + + #ifdef CONFIG_HAVE_ARM_TWD + twd_local_timer_of_register(); +diff --git a/arch/arm/mach-zynq/xaxipcie.c b/arch/arm/mach-zynq/xaxipcie.c +index 81bfc5d..c6c567e 100644 +--- a/arch/arm/mach-zynq/xaxipcie.c ++++ b/arch/arm/mach-zynq/xaxipcie.c +@@ -34,9 +34,7 @@ + #include + #include + #include +-#include + #include +-#include + #include + #include + +diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S +index 7539ec2..15451ee 100644 +--- a/arch/arm/mm/cache-v7.S ++++ b/arch/arm/mm/cache-v7.S +@@ -19,6 +19,52 @@ + #include "proc-macros.S" + + /* ++ * The secondary kernel init calls v7_flush_dcache_all before it enables ++ * the L1; however, the L1 comes out of reset in an undefined state, so ++ * the clean + invalidate performed by v7_flush_dcache_all causes a bunch ++ * of cache lines with uninitialized data and uninitialized tags to get ++ * written out to memory, which does really unpleasant things to the main ++ * processor. We fix this by performing an invalidate, rather than a ++ * clean + invalidate, before jumping into the kernel. ++ * ++ * This function is cloned from arch/arm/mach-tegra/headsmp.S, and needs ++ * to be called for both secondary cores startup and primary core resume ++ * procedures. ++ */ ++ENTRY(v7_invalidate_l1) ++ mov r0, #0 ++ mcr p15, 2, r0, c0, c0, 0 ++ mrc p15, 1, r0, c0, c0, 0 ++ ++ ldr r1, =0x7fff ++ and r2, r1, r0, lsr #13 ++ ++ ldr r1, =0x3ff ++ ++ and r3, r1, r0, lsr #3 @ NumWays - 1 ++ add r2, r2, #1 @ NumSets ++ ++ and r0, r0, #0x7 ++ add r0, r0, #4 @ SetShift ++ ++ clz r1, r3 @ WayShift ++ add r4, r3, #1 @ NumWays ++1: sub r2, r2, #1 @ NumSets-- ++ mov r3, r4 @ Temp = NumWays ++2: subs r3, r3, #1 @ Temp-- ++ mov r5, r3, lsl r1 ++ mov r6, r2, lsl r0 ++ orr r5, r5, r6 @ Reg = (Temp< + #include + +-#include +- + /* + * 'what should we do if we get a hw irq event on an illegal vector'. + * each architecture has to answer this themselves. +@@ -85,12 +83,6 @@ bool is_affinity_mask_valid(const struct cpumask *cpumask) + + #endif /* CONFIG_SMP */ + +-int __init arch_early_irq_init(void) +-{ +- ia64_mca_irq_init(); +- return 0; +-} +- + #ifdef CONFIG_HOTPLUG_CPU + unsigned int vectors_in_migration[NR_IRQS]; + +diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c +index d7396db..65bf9cd 100644 +--- a/arch/ia64/kernel/mca.c ++++ b/arch/ia64/kernel/mca.c +@@ -2074,16 +2074,22 @@ ia64_mca_init(void) + printk(KERN_INFO "MCA related initialization done\n"); + } + +- + /* +- * These pieces cannot be done in ia64_mca_init() because it is called before +- * early_irq_init() which would wipe out our percpu irq registrations. But we +- * cannot leave them until ia64_mca_late_init() because by then all the other +- * processors have been brought online and have set their own CMC vectors to +- * point at a non-existant action. Called from arch_early_irq_init(). ++ * ia64_mca_late_init ++ * ++ * Opportunity to setup things that require initialization later ++ * than ia64_mca_init. Setup a timer to poll for CPEs if the ++ * platform doesn't support an interrupt driven mechanism. ++ * ++ * Inputs : None ++ * Outputs : Status + */ +-void __init ia64_mca_irq_init(void) ++static int __init ++ia64_mca_late_init(void) + { ++ if (!mca_init) ++ return 0; ++ + /* + * Configure the CMCI/P vector and handler. Interrupts for CMC are + * per-processor, so AP CMC interrupts are setup in smp_callin() (smpboot.c). +@@ -2102,23 +2108,6 @@ void __init ia64_mca_irq_init(void) + /* Setup the CPEI/P handler */ + register_percpu_irq(IA64_CPEP_VECTOR, &mca_cpep_irqaction); + #endif +-} +- +-/* +- * ia64_mca_late_init +- * +- * Opportunity to setup things that require initialization later +- * than ia64_mca_init. Setup a timer to poll for CPEs if the +- * platform doesn't support an interrupt driven mechanism. +- * +- * Inputs : None +- * Outputs : Status +- */ +-static int __init +-ia64_mca_late_init(void) +-{ +- if (!mca_init) +- return 0; + + register_hotcpu_notifier(&mca_cpu_notifier); + +diff --git a/arch/ia64/kvm/vtlb.c b/arch/ia64/kvm/vtlb.c +index a7869f8..4332f7e 100644 +--- a/arch/ia64/kvm/vtlb.c ++++ b/arch/ia64/kvm/vtlb.c +@@ -256,7 +256,7 @@ u64 guest_vhpt_lookup(u64 iha, u64 *pte) + "srlz.d;;" + "ssm psr.i;;" + "srlz.d;;" +- : "=&r"(ret) : "r"(iha), "r"(pte) : "memory"); ++ : "=r"(ret) : "r"(iha), "r"(pte):"memory"); + + return ret; + } +diff --git a/arch/microblaze/configs/mmu_defconfig b/arch/microblaze/configs/mmu_defconfig +index d2b097a..3649a8b 100644 +--- a/arch/microblaze/configs/mmu_defconfig ++++ b/arch/microblaze/configs/mmu_defconfig +@@ -17,7 +17,6 @@ CONFIG_MODULE_UNLOAD=y + # CONFIG_BLK_DEV_BSG is not set + CONFIG_PARTITION_ADVANCED=y + # CONFIG_EFI_PARTITION is not set +-CONFIG_OPT_LIB_ASM=y + CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR=1 + CONFIG_XILINX_MICROBLAZE0_USE_PCMP_INSTR=1 + CONFIG_XILINX_MICROBLAZE0_USE_BARREL=1 +diff --git a/arch/microblaze/include/asm/io.h b/arch/microblaze/include/asm/io.h +index 4fbfdc1..8cb8a85 100644 +--- a/arch/microblaze/include/asm/io.h ++++ b/arch/microblaze/include/asm/io.h +@@ -150,7 +150,7 @@ static inline void writel(unsigned int v, volatile void __iomem *addr) + #define page_to_bus(page) (page_to_phys(page)) + #define bus_to_virt(addr) (phys_to_virt(addr)) + +-extern void iounmap(void *addr); ++extern void iounmap(void __iomem *addr); + /*extern void *__ioremap(phys_addr_t address, unsigned long size, + unsigned long flags);*/ + extern void __iomem *ioremap(phys_addr_t address, unsigned long size); +diff --git a/arch/microblaze/include/asm/pci.h b/arch/microblaze/include/asm/pci.h +index 41cc841..d52abb6 100644 +--- a/arch/microblaze/include/asm/pci.h ++++ b/arch/microblaze/include/asm/pci.h +@@ -153,7 +153,5 @@ extern void __init xilinx_pci_init(void); + static inline void __init xilinx_pci_init(void) { return; } + #endif + +-#include +- + #endif /* __KERNEL__ */ + #endif /* __ASM_MICROBLAZE_PCI_H */ +diff --git a/arch/microblaze/kernel/cpu/cache.c b/arch/microblaze/kernel/cpu/cache.c +index 4b7d8a3..4254514b 100644 +--- a/arch/microblaze/kernel/cpu/cache.c ++++ b/arch/microblaze/kernel/cpu/cache.c +@@ -17,82 +17,70 @@ + + static inline void __enable_icache_msr(void) + { +- __asm__ __volatile__ (" msrset r0, %0; \ +- nop; " \ ++ __asm__ __volatile__ (" msrset r0, %0;" \ ++ "nop;" \ + : : "i" (MSR_ICE) : "memory"); + } + + static inline void __disable_icache_msr(void) + { +- __asm__ __volatile__ (" msrclr r0, %0; \ +- nop; " \ ++ __asm__ __volatile__ (" msrclr r0, %0;" \ ++ "nop;" \ + : : "i" (MSR_ICE) : "memory"); + } + + static inline void __enable_dcache_msr(void) + { +- __asm__ __volatile__ (" msrset r0, %0; \ +- nop; " \ +- : \ +- : "i" (MSR_DCE) \ +- : "memory"); ++ __asm__ __volatile__ (" msrset r0, %0;" \ ++ "nop;" \ ++ : : "i" (MSR_DCE) : "memory"); + } + + static inline void __disable_dcache_msr(void) + { +- __asm__ __volatile__ (" msrclr r0, %0; \ +- nop; " \ +- : \ +- : "i" (MSR_DCE) \ +- : "memory"); ++ __asm__ __volatile__ (" msrclr r0, %0;" \ ++ "nop; " \ ++ : : "i" (MSR_DCE) : "memory"); + } + + static inline void __enable_icache_nomsr(void) + { +- __asm__ __volatile__ (" mfs r12, rmsr; \ +- nop; \ +- ori r12, r12, %0; \ +- mts rmsr, r12; \ +- nop; " \ +- : \ +- : "i" (MSR_ICE) \ +- : "memory", "r12"); ++ __asm__ __volatile__ (" mfs r12, rmsr;" \ ++ "nop;" \ ++ "ori r12, r12, %0;" \ ++ "mts rmsr, r12;" \ ++ "nop;" \ ++ : : "i" (MSR_ICE) : "memory", "r12"); + } + + static inline void __disable_icache_nomsr(void) + { +- __asm__ __volatile__ (" mfs r12, rmsr; \ +- nop; \ +- andi r12, r12, ~%0; \ +- mts rmsr, r12; \ +- nop; " \ +- : \ +- : "i" (MSR_ICE) \ +- : "memory", "r12"); ++ __asm__ __volatile__ (" mfs r12, rmsr;" \ ++ "nop;" \ ++ "andi r12, r12, ~%0;" \ ++ "mts rmsr, r12;" \ ++ "nop;" \ ++ : : "i" (MSR_ICE) : "memory", "r12"); + } + + static inline void __enable_dcache_nomsr(void) + { +- __asm__ __volatile__ (" mfs r12, rmsr; \ +- nop; \ +- ori r12, r12, %0; \ +- mts rmsr, r12; \ +- nop; " \ +- : \ +- : "i" (MSR_DCE) \ +- : "memory", "r12"); ++ __asm__ __volatile__ (" mfs r12, rmsr;" \ ++ "nop;" \ ++ "ori r12, r12, %0;" \ ++ "mts rmsr, r12;" \ ++ "nop;" \ ++ : : "i" (MSR_DCE) : "memory", "r12"); + } + + static inline void __disable_dcache_nomsr(void) + { +- __asm__ __volatile__ (" mfs r12, rmsr; \ +- nop; \ +- andi r12, r12, ~%0; \ +- mts rmsr, r12; \ +- nop; " \ +- : \ +- : "i" (MSR_DCE) \ +- : "memory", "r12"); ++ __asm__ __volatile__ (" mfs r12, rmsr;" \ ++ "nop;" \ ++ "andi r12, r12, ~%0;" \ ++ "mts rmsr, r12;" \ ++ "nop;" \ ++ : : "i" (MSR_DCE) : "memory", "r12"); + } + + +@@ -106,7 +94,7 @@ do { \ + int align = ~(cache_line_length - 1); \ + end = min(start + cache_size, end); \ + start &= align; \ +-} while (0); ++} while (0) + + /* + * Helper macro to loop over the specified cache_size/line_length and +@@ -118,12 +106,12 @@ do { \ + int step = -line_length; \ + WARN_ON(step >= 0); \ + \ +- __asm__ __volatile__ (" 1: " #op " %0, r0; \ +- bgtid %0, 1b; \ +- addk %0, %0, %1; \ +- " : : "r" (len), "r" (step) \ ++ __asm__ __volatile__ (" 1: " #op " %0, r0;" \ ++ "bgtid %0, 1b;" \ ++ "addk %0, %0, %1;" \ ++ : : "r" (len), "r" (step) \ + : "memory"); \ +-} while (0); ++} while (0) + + /* Used for wdc.flush/clear which can use rB for offset which is not possible + * to use for simple wdc or wic. +@@ -142,12 +130,12 @@ do { \ + count = end - start; \ + WARN_ON(count < 0); \ + \ +- __asm__ __volatile__ (" 1: " #op " %0, %1; \ +- bgtid %1, 1b; \ +- addk %1, %1, %2; \ +- " : : "r" (start), "r" (count), \ ++ __asm__ __volatile__ (" 1: " #op " %0, %1;" \ ++ "bgtid %1, 1b;" \ ++ "addk %1, %1, %2;" \ ++ : : "r" (start), "r" (count), \ + "r" (step) : "memory"); \ +-} while (0); ++} while (0) + + /* It is used only first parameter for OP - for wic, wdc */ + #define CACHE_RANGE_LOOP_1(start, end, line_length, op) \ +@@ -157,13 +145,13 @@ do { \ + end = ((end & align) == end) ? end - line_length : end & align; \ + WARN_ON(end - start < 0); \ + \ +- __asm__ __volatile__ (" 1: " #op " %1, r0; \ +- cmpu %0, %1, %2; \ +- bgtid %0, 1b; \ +- addk %1, %1, %3; \ +- " : : "r" (temp), "r" (start), "r" (end),\ ++ __asm__ __volatile__ (" 1: " #op " %1, r0;" \ ++ "cmpu %0, %1, %2;" \ ++ "bgtid %0, 1b;" \ ++ "addk %1, %1, %3;" \ ++ : : "r" (temp), "r" (start), "r" (end), \ + "r" (line_length) : "memory"); \ +-} while (0); ++} while (0) + + #define ASM_LOOP + +@@ -352,7 +340,7 @@ static void __invalidate_dcache_all_noirq_wt(void) + #endif + pr_debug("%s\n", __func__); + #ifdef ASM_LOOP +- CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc) ++ CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc); + #else + for (i = 0; i < cpuinfo.dcache_size; + i += cpuinfo.dcache_line_length) +@@ -361,7 +349,8 @@ static void __invalidate_dcache_all_noirq_wt(void) + #endif + } + +-/* FIXME It is blindly invalidation as is expected ++/* ++ * FIXME It is blindly invalidation as is expected + * but can't be called on noMMU in microblaze_cache_init below + * + * MS: noMMU kernel won't boot if simple wdc is used +@@ -375,7 +364,7 @@ static void __invalidate_dcache_all_wb(void) + pr_debug("%s\n", __func__); + #ifdef ASM_LOOP + CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, +- wdc) ++ wdc); + #else + for (i = 0; i < cpuinfo.dcache_size; + i += cpuinfo.dcache_line_length) +@@ -616,49 +605,48 @@ static const struct scache wt_nomsr_noirq = { + #define CPUVER_7_20_A 0x0c + #define CPUVER_7_20_D 0x0f + +-#define INFO(s) printk(KERN_INFO "cache: " s "\n"); +- + void microblaze_cache_init(void) + { + if (cpuinfo.use_instr & PVR2_USE_MSR_INSTR) { + if (cpuinfo.dcache_wb) { +- INFO("wb_msr"); ++ pr_info("wb_msr\n"); + mbc = (struct scache *)&wb_msr; + if (cpuinfo.ver_code <= CPUVER_7_20_D) { + /* MS: problem with signal handling - hw bug */ +- INFO("WB won't work properly"); ++ pr_info("WB won't work properly\n"); + } + } else { + if (cpuinfo.ver_code >= CPUVER_7_20_A) { +- INFO("wt_msr_noirq"); ++ pr_info("wt_msr_noirq\n"); + mbc = (struct scache *)&wt_msr_noirq; + } else { +- INFO("wt_msr"); ++ pr_info("wt_msr\n"); + mbc = (struct scache *)&wt_msr; + } + } + } else { + if (cpuinfo.dcache_wb) { +- INFO("wb_nomsr"); ++ pr_info("wb_nomsr\n"); + mbc = (struct scache *)&wb_nomsr; + if (cpuinfo.ver_code <= CPUVER_7_20_D) { + /* MS: problem with signal handling - hw bug */ +- INFO("WB won't work properly"); ++ pr_info("WB won't work properly\n"); + } + } else { + if (cpuinfo.ver_code >= CPUVER_7_20_A) { +- INFO("wt_nomsr_noirq"); ++ pr_info("wt_nomsr_noirq\n"); + mbc = (struct scache *)&wt_nomsr_noirq; + } else { +- INFO("wt_nomsr"); ++ pr_info("wt_nomsr\n"); + mbc = (struct scache *)&wt_nomsr; + } + } + } +-/* FIXME Invalidation is done in U-BOOT +- * WT cache: Data is already written to main memory +- * WB cache: Discard data on noMMU which caused that kernel doesn't boot +- */ ++ /* ++ * FIXME Invalidation is done in U-BOOT ++ * WT cache: Data is already written to main memory ++ * WB cache: Discard data on noMMU which caused that kernel doesn't boot ++ */ + /* invalidate_dcache(); */ + enable_dcache(); + +diff --git a/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c b/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c +index 916aaed..ee46894 100644 +--- a/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c ++++ b/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c +@@ -27,7 +27,7 @@ + early_printk("ERROR: Microblaze " x "-different for PVR and DTS\n"); + #else + #define err_printk(x) \ +- printk(KERN_INFO "ERROR: Microblaze " x "-different for PVR and DTS\n"); ++ pr_info("ERROR: Microblaze " x "-different for PVR and DTS\n"); + #endif + + void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu) +@@ -38,12 +38,11 @@ void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu) + + CI(ver_code, VERSION); + if (!ci->ver_code) { +- printk(KERN_ERR "ERROR: MB has broken PVR regs " +- "-> use DTS setting\n"); ++ pr_err("ERROR: MB has broken PVR regs -> use DTS setting\n"); + return; + } + +- temp = PVR_USE_BARREL(pvr) | PVR_USE_MSR_INSTR(pvr) |\ ++ temp = PVR_USE_BARREL(pvr) | PVR_USE_MSR_INSTR(pvr) | + PVR_USE_PCMP_INSTR(pvr) | PVR_USE_DIV(pvr); + if (ci->use_instr != temp) + err_printk("BARREL, MSR, PCMP or DIV"); +@@ -59,13 +58,13 @@ void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu) + err_printk("HW_FPU"); + ci->use_fpu = temp; + +- ci->use_exc = PVR_OPCODE_0x0_ILLEGAL(pvr) |\ +- PVR_UNALIGNED_EXCEPTION(pvr) |\ +- PVR_ILL_OPCODE_EXCEPTION(pvr) |\ +- PVR_IOPB_BUS_EXCEPTION(pvr) |\ +- PVR_DOPB_BUS_EXCEPTION(pvr) |\ +- PVR_DIV_ZERO_EXCEPTION(pvr) |\ +- PVR_FPU_EXCEPTION(pvr) |\ ++ ci->use_exc = PVR_OPCODE_0x0_ILLEGAL(pvr) | ++ PVR_UNALIGNED_EXCEPTION(pvr) | ++ PVR_ILL_OPCODE_EXCEPTION(pvr) | ++ PVR_IOPB_BUS_EXCEPTION(pvr) | ++ PVR_DOPB_BUS_EXCEPTION(pvr) | ++ PVR_DIV_ZERO_EXCEPTION(pvr) | ++ PVR_FPU_EXCEPTION(pvr) | + PVR_FSL_EXCEPTION(pvr); + + CI(pvr_user1, USER1); +diff --git a/arch/microblaze/kernel/cpu/cpuinfo.c b/arch/microblaze/kernel/cpu/cpuinfo.c +index 3ffd337..410398f 100644 +--- a/arch/microblaze/kernel/cpu/cpuinfo.c ++++ b/arch/microblaze/kernel/cpu/cpuinfo.c +@@ -73,31 +73,30 @@ void __init setup_cpuinfo(void) + + cpu = (struct device_node *) of_find_node_by_type(NULL, "cpu"); + if (!cpu) +- printk(KERN_ERR "You don't have cpu!!!\n"); ++ pr_err("You don't have cpu!!!\n"); + +- printk(KERN_INFO "%s: initialising\n", __func__); ++ pr_info("%s: initialising\n", __func__); + + switch (cpu_has_pvr()) { + case 0: +- printk(KERN_WARNING +- "%s: No PVR support. Using static CPU info from FDT\n", ++ pr_warn("%s: No PVR support. Using static CPU info from FDT\n", + __func__); + set_cpuinfo_static(&cpuinfo, cpu); + break; + /* FIXME I found weird behavior with MB 7.00.a/b 7.10.a + * please do not use FULL PVR with MMU */ + case 1: +- printk(KERN_INFO "%s: Using full CPU PVR support\n", ++ pr_info("%s: Using full CPU PVR support\n", + __func__); + set_cpuinfo_static(&cpuinfo, cpu); + set_cpuinfo_pvr_full(&cpuinfo, cpu); + break; + default: +- printk(KERN_WARNING "%s: Unsupported PVR setting\n", __func__); ++ pr_warn("%s: Unsupported PVR setting\n", __func__); + set_cpuinfo_static(&cpuinfo, cpu); + } + + if (cpuinfo.mmu_privins) +- printk(KERN_WARNING "%s: Stream instructions enabled" ++ pr_warn("%s: Stream instructions enabled" + " - USERSPACE CAN LOCK THIS KERNEL!\n", __func__); + } +diff --git a/arch/microblaze/kernel/cpu/pvr.c b/arch/microblaze/kernel/cpu/pvr.c +index 3a749d5..8d0dc6d 100644 +--- a/arch/microblaze/kernel/cpu/pvr.c ++++ b/arch/microblaze/kernel/cpu/pvr.c +@@ -27,7 +27,7 @@ + tmp = 0x0; /* Prevent warning about unused */ \ + __asm__ __volatile__ ( \ + "mfs %0, rpvr" #pvrid ";" \ +- : "=r" (tmp) : : "memory"); \ ++ : "=r" (tmp) : : "memory"); \ + val = tmp; \ + } + +diff --git a/arch/microblaze/kernel/dma.c b/arch/microblaze/kernel/dma.c +index a2bfa2c..da68d00 100644 +--- a/arch/microblaze/kernel/dma.c ++++ b/arch/microblaze/kernel/dma.c +@@ -11,7 +11,7 @@ + #include + #include + #include +-#include ++#include + + /* + * Generic direct DMA implementation +@@ -197,8 +197,8 @@ EXPORT_SYMBOL(dma_direct_ops); + + static int __init dma_init(void) + { +- dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES); ++ dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES); + +- return 0; ++ return 0; + } + fs_initcall(dma_init); +diff --git a/arch/microblaze/kernel/early_printk.c b/arch/microblaze/kernel/early_printk.c +index aba1f9a..60dcacc 100644 +--- a/arch/microblaze/kernel/early_printk.c ++++ b/arch/microblaze/kernel/early_printk.c +@@ -140,20 +140,20 @@ int __init setup_early_printk(char *opt) + switch (version) { + #ifdef CONFIG_SERIAL_UARTLITE_CONSOLE + case UARTLITE: +- printk(KERN_INFO "Early console on uartlite " +- "at 0x%08x\n", base_addr); ++ pr_info("Early console on uartlite at 0x%08x\n", ++ base_addr); + early_console = &early_serial_uartlite_console; + break; + #endif + #ifdef CONFIG_SERIAL_8250_CONSOLE + case UART16550: +- printk(KERN_INFO "Early console on uart16650 " +- "at 0x%08x\n", base_addr); ++ pr_info("Early console on uart16650 at 0x%08x\n", ++ base_addr); + early_console = &early_serial_uart16550_console; + break; + #endif + default: +- printk(KERN_INFO "Unsupported early console %d\n", ++ pr_info("Unsupported early console %d\n", + version); + return 1; + } +@@ -171,10 +171,9 @@ void __init remap_early_printk(void) + { + if (!early_console_initialized || !early_console) + return; +- printk(KERN_INFO "early_printk_console remapping from 0x%x to ", +- base_addr); ++ pr_info("early_printk_console remapping from 0x%x to ", base_addr); + base_addr = (u32) ioremap(base_addr, PAGE_SIZE); +- printk(KERN_CONT "0x%x\n", base_addr); ++ pr_cont("0x%x\n", base_addr); + + #ifdef CONFIG_MMU + /* +@@ -197,7 +196,7 @@ void __init disable_early_printk(void) + { + if (!early_console_initialized || !early_console) + return; +- printk(KERN_WARNING "disabling early console\n"); ++ pr_warn("disabling early console\n"); + unregister_console(early_console); + early_console_initialized = 0; + } +diff --git a/arch/microblaze/kernel/exceptions.c b/arch/microblaze/kernel/exceptions.c +index 6348dc8..42dd12a 100644 +--- a/arch/microblaze/kernel/exceptions.c ++++ b/arch/microblaze/kernel/exceptions.c +@@ -13,11 +13,11 @@ + * This file handles the architecture-dependent parts of hardware exceptions + */ + ++#include + #include + #include + #include + #include +-#include + + #include + #include /* For KM CPU var */ +@@ -40,7 +40,7 @@ void die(const char *str, struct pt_regs *fp, long err) + { + console_verbose(); + spin_lock_irq(&die_lock); +- printk(KERN_WARNING "Oops: %s, sig: %ld\n", str, err); ++ pr_warn("Oops: %s, sig: %ld\n", str, err); + show_regs(fp); + spin_unlock_irq(&die_lock); + /* do_exit() should take care of panic'ing from an interrupt +@@ -61,9 +61,9 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) + { + siginfo_t info; + +- if (kernel_mode(regs)) { ++ if (kernel_mode(regs)) + die("Exception in kernel mode", regs, signr); +- } ++ + info.si_signo = signr; + info.si_errno = 0; + info.si_code = code; +@@ -79,8 +79,7 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type, + #endif + + #if 0 +- printk(KERN_WARNING "Exception %02x in %s mode, FSR=%08x PC=%08x " \ +- "ESR=%08x\n", ++ pr_warn("Exception %02x in %s mode, FSR=%08x PC=%08x ESR=%08x\n", + type, user_mode(regs) ? "user" : "kernel", fsr, + (unsigned int) regs->pc, (unsigned int) regs->esr); + #endif +@@ -92,8 +91,7 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type, + _exception(SIGILL, regs, ILL_ILLOPC, addr); + return; + } +- printk(KERN_WARNING "Illegal opcode exception " \ +- "in kernel mode.\n"); ++ pr_warn("Illegal opcode exception in kernel mode.\n"); + die("opcode exception", regs, SIGBUS); + break; + case MICROBLAZE_IBUS_EXCEPTION: +@@ -102,8 +100,7 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type, + _exception(SIGBUS, regs, BUS_ADRERR, addr); + return; + } +- printk(KERN_WARNING "Instruction bus error exception " \ +- "in kernel mode.\n"); ++ pr_warn("Instruction bus error exception in kernel mode.\n"); + die("bus exception", regs, SIGBUS); + break; + case MICROBLAZE_DBUS_EXCEPTION: +@@ -112,8 +109,7 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type, + _exception(SIGBUS, regs, BUS_ADRERR, addr); + return; + } +- printk(KERN_WARNING "Data bus error exception " \ +- "in kernel mode.\n"); ++ pr_warn("Data bus error exception in kernel mode.\n"); + die("bus exception", regs, SIGBUS); + break; + case MICROBLAZE_DIV_ZERO_EXCEPTION: +@@ -122,8 +118,7 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type, + _exception(SIGFPE, regs, FPE_INTDIV, addr); + return; + } +- printk(KERN_WARNING "Divide by zero exception " \ +- "in kernel mode.\n"); ++ pr_warn("Divide by zero exception in kernel mode.\n"); + die("Divide by zero exception", regs, SIGBUS); + break; + case MICROBLAZE_FPU_EXCEPTION: +@@ -151,8 +146,8 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type, + #endif + default: + /* FIXME what to do in unexpected exception */ +- printk(KERN_WARNING "Unexpected exception %02x " +- "PC=%08x in %s mode\n", type, (unsigned int) addr, ++ pr_warn("Unexpected exception %02x PC=%08x in %s mode\n", ++ type, (unsigned int) addr, + kernel_mode(regs) ? "kernel" : "user"); + } + return; +diff --git a/arch/microblaze/kernel/ftrace.c b/arch/microblaze/kernel/ftrace.c +index 357d56a..e8a5e9c 100644 +--- a/arch/microblaze/kernel/ftrace.c ++++ b/arch/microblaze/kernel/ftrace.c +@@ -35,18 +35,18 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr) + * happen. This tool is too much intrusive to + * ignore such a protection. + */ +- asm volatile(" 1: lwi %0, %2, 0; \ +- 2: swi %3, %2, 0; \ +- addik %1, r0, 0; \ +- 3: \ +- .section .fixup, \"ax\"; \ +- 4: brid 3b; \ +- addik %1, r0, 1; \ +- .previous; \ +- .section __ex_table,\"a\"; \ +- .word 1b,4b; \ +- .word 2b,4b; \ +- .previous;" \ ++ asm volatile(" 1: lwi %0, %2, 0;" \ ++ "2: swi %3, %2, 0;" \ ++ " addik %1, r0, 0;" \ ++ "3:" \ ++ " .section .fixup, \"ax\";" \ ++ "4: brid 3b;" \ ++ " addik %1, r0, 1;" \ ++ " .previous;" \ ++ " .section __ex_table,\"a\";" \ ++ " .word 1b,4b;" \ ++ " .word 2b,4b;" \ ++ " .previous;" \ + : "=&r" (old), "=r" (faulted) + : "r" (parent), "r" (return_hooker) + ); +@@ -81,16 +81,16 @@ static int ftrace_modify_code(unsigned long addr, unsigned int value) + { + int faulted = 0; + +- __asm__ __volatile__(" 1: swi %2, %1, 0; \ +- addik %0, r0, 0; \ +- 2: \ +- .section .fixup, \"ax\"; \ +- 3: brid 2b; \ +- addik %0, r0, 1; \ +- .previous; \ +- .section __ex_table,\"a\"; \ +- .word 1b,3b; \ +- .previous;" \ ++ __asm__ __volatile__(" 1: swi %2, %1, 0;" \ ++ " addik %0, r0, 0;" \ ++ "2:" \ ++ " .section .fixup, \"ax\";" \ ++ "3: brid 2b;" \ ++ " addik %0, r0, 1;" \ ++ " .previous;" \ ++ " .section __ex_table,\"a\";" \ ++ " .word 1b,3b;" \ ++ " .previous;" \ + : "=r" (faulted) + : "r" (addr), "r" (value) + ); +diff --git a/arch/microblaze/kernel/head.S b/arch/microblaze/kernel/head.S +index a8ce682..fcc797f 100644 +--- a/arch/microblaze/kernel/head.S ++++ b/arch/microblaze/kernel/head.S +@@ -120,7 +120,7 @@ _copy_command_line: + /* r2=r5+r6 - r5 contain pointer to command line */ + lbu r2, r5, r11 + beqid r2, skip /* Skip if no data */ +- sb r2, r4, r11 /* addr[r4+r6]= r2*/ ++ sb r2, r4, r11 /* addr[r4+r6]= r2 */ + addik r11, r11, 1 /* increment counting */ + bgtid r3, _copy_command_line /* loop for all entries */ + addik r3, r3, -1 /* decrement loop */ +@@ -136,7 +136,7 @@ skip: + ori r3, r0, (LMB_SIZE - 4) + _copy_bram: + lw r7, r0, r11 /* r7 = r0 + r6 */ +- sw r7, r4, r11 /* addr[r4 + r6] = r7*/ ++ sw r7, r4, r11 /* addr[r4 + r6] = r7 */ + addik r11, r11, 4 /* increment counting */ + bgtid r3, _copy_bram /* loop for all entries */ + addik r3, r3, -4 /* descrement loop */ +diff --git a/arch/microblaze/kernel/heartbeat.c b/arch/microblaze/kernel/heartbeat.c +index 154756f..1879a05 100644 +--- a/arch/microblaze/kernel/heartbeat.c ++++ b/arch/microblaze/kernel/heartbeat.c +@@ -61,7 +61,7 @@ void setup_heartbeat(void) + if (gpio) { + base_addr = be32_to_cpup(of_get_property(gpio, "reg", NULL)); + base_addr = (unsigned long) ioremap(base_addr, PAGE_SIZE); +- printk(KERN_NOTICE "Heartbeat GPIO at 0x%x\n", base_addr); ++ pr_notice("Heartbeat GPIO at 0x%x\n", base_addr); + + /* GPIO is configured as output */ + prop = (int *) of_get_property(gpio, "xlnx,is-bidir", NULL); +diff --git a/arch/microblaze/kernel/intc.c b/arch/microblaze/kernel/intc.c +index 9422699..d85fa3a 100644 +--- a/arch/microblaze/kernel/intc.c ++++ b/arch/microblaze/kernel/intc.c +@@ -147,12 +147,12 @@ void __init init_IRQ(void) + intr_mask = + be32_to_cpup(of_get_property(intc, "xlnx,kind-of-intr", NULL)); + if (intr_mask > (u32)((1ULL << nr_irq) - 1)) +- printk(KERN_INFO " ERROR: Mismatch in kind-of-intr param\n"); ++ pr_info(" ERROR: Mismatch in kind-of-intr param\n"); + + #ifdef CONFIG_SELFMOD_INTC + selfmod_function((int *) arr_func, intc_baseaddr); + #endif +- printk(KERN_INFO "%s #0 at 0x%08x, num_irq=%d, edge=0x%x\n", ++ pr_info("%s #0 at 0x%08x, num_irq=%d, edge=0x%x\n", + intc->name, intc_baseaddr, nr_irq, intr_mask); + + /* +diff --git a/arch/microblaze/kernel/kgdb.c b/arch/microblaze/kernel/kgdb.c +index 09a5e82..8adc9244 100644 +--- a/arch/microblaze/kernel/kgdb.c ++++ b/arch/microblaze/kernel/kgdb.c +@@ -141,7 +141,7 @@ void kgdb_arch_exit(void) + /* + * Global data + */ +-struct kgdb_arch arch_kgdb_ops = { ++const struct kgdb_arch arch_kgdb_ops = { + #ifdef __MICROBLAZEEL__ + .gdb_bpt_instr = {0x18, 0x00, 0x0c, 0xba}, /* brki r16, 0x18 */ + #else +diff --git a/arch/microblaze/kernel/microblaze_ksyms.c b/arch/microblaze/kernel/microblaze_ksyms.c +index 2b25bcf..9f1d02c4 100644 +--- a/arch/microblaze/kernel/microblaze_ksyms.c ++++ b/arch/microblaze/kernel/microblaze_ksyms.c +@@ -7,7 +7,7 @@ + * published by the Free Software Foundation. + */ + +-#include ++#include + #include + #include + #include +diff --git a/arch/microblaze/kernel/module.c b/arch/microblaze/kernel/module.c +index f39257a..182e6be 100644 +--- a/arch/microblaze/kernel/module.c ++++ b/arch/microblaze/kernel/module.c +@@ -7,7 +7,7 @@ + * published by the Free Software Foundation. + */ + +-#include ++#include + #include + #include + #include +@@ -108,8 +108,7 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab, + break; + + default: +- printk(KERN_ERR "module %s: " +- "Unknown relocation: %u\n", ++ pr_err("module %s: Unknown relocation: %u\n", + module->name, + ELF32_R_TYPE(rela[i].r_info)); + return -ENOEXEC; +diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c +index a5b74f7..246d4c1 100644 +--- a/arch/microblaze/kernel/process.c ++++ b/arch/microblaze/kernel/process.c +@@ -8,36 +8,36 @@ + * for more details. + */ + +-#include ++#include + #include + #include + #include + #include + #include + #include +-#include /* for USER_DS macros */ ++#include /* for USER_DS macros */ + #include + + void show_regs(struct pt_regs *regs) + { +- printk(KERN_INFO " Registers dump: mode=%X\r\n", regs->pt_mode); +- printk(KERN_INFO " r1=%08lX, r2=%08lX, r3=%08lX, r4=%08lX\n", ++ pr_info(" Registers dump: mode=%X\r\n", regs->pt_mode); ++ pr_info(" r1=%08lX, r2=%08lX, r3=%08lX, r4=%08lX\n", + regs->r1, regs->r2, regs->r3, regs->r4); +- printk(KERN_INFO " r5=%08lX, r6=%08lX, r7=%08lX, r8=%08lX\n", ++ pr_info(" r5=%08lX, r6=%08lX, r7=%08lX, r8=%08lX\n", + regs->r5, regs->r6, regs->r7, regs->r8); +- printk(KERN_INFO " r9=%08lX, r10=%08lX, r11=%08lX, r12=%08lX\n", ++ pr_info(" r9=%08lX, r10=%08lX, r11=%08lX, r12=%08lX\n", + regs->r9, regs->r10, regs->r11, regs->r12); +- printk(KERN_INFO " r13=%08lX, r14=%08lX, r15=%08lX, r16=%08lX\n", ++ pr_info(" r13=%08lX, r14=%08lX, r15=%08lX, r16=%08lX\n", + regs->r13, regs->r14, regs->r15, regs->r16); +- printk(KERN_INFO " r17=%08lX, r18=%08lX, r19=%08lX, r20=%08lX\n", ++ pr_info(" r17=%08lX, r18=%08lX, r19=%08lX, r20=%08lX\n", + regs->r17, regs->r18, regs->r19, regs->r20); +- printk(KERN_INFO " r21=%08lX, r22=%08lX, r23=%08lX, r24=%08lX\n", ++ pr_info(" r21=%08lX, r22=%08lX, r23=%08lX, r24=%08lX\n", + regs->r21, regs->r22, regs->r23, regs->r24); +- printk(KERN_INFO " r25=%08lX, r26=%08lX, r27=%08lX, r28=%08lX\n", ++ pr_info(" r25=%08lX, r26=%08lX, r27=%08lX, r28=%08lX\n", + regs->r25, regs->r26, regs->r27, regs->r28); +- printk(KERN_INFO " r29=%08lX, r30=%08lX, r31=%08lX, rPC=%08lX\n", ++ pr_info(" r29=%08lX, r30=%08lX, r31=%08lX, rPC=%08lX\n", + regs->r29, regs->r30, regs->r31, regs->pc); +- printk(KERN_INFO " msr=%08lX, ear=%08lX, esr=%08lX, fsr=%08lX\n", ++ pr_info(" msr=%08lX, ear=%08lX, esr=%08lX, fsr=%08lX\n", + regs->msr, regs->ear, regs->esr, regs->fsr); + } + +diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c +index a744e3f..0a2c68f 100644 +--- a/arch/microblaze/kernel/prom.c ++++ b/arch/microblaze/kernel/prom.c +@@ -14,6 +14,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -25,7 +26,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff --git a/arch/microblaze/kernel/prom_parse.c b/arch/microblaze/kernel/prom_parse.c +index 47187cc..068762f 100644 +--- a/arch/microblaze/kernel/prom_parse.c ++++ b/arch/microblaze/kernel/prom_parse.c +@@ -1,8 +1,8 @@ + #undef DEBUG + ++#include + #include + #include +-#include + #include + #include + #include +diff --git a/arch/microblaze/kernel/ptrace.c b/arch/microblaze/kernel/ptrace.c +index ab1b9db..c554980 100644 +--- a/arch/microblaze/kernel/ptrace.c ++++ b/arch/microblaze/kernel/ptrace.c +@@ -40,7 +40,7 @@ + #include + #include + #include +-#include ++#include + + /* Returns the address where the register at REG_OFFS in P is stashed away. */ + static microblaze_reg_t *reg_save_addr(unsigned reg_offs, +diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c +index 954348f..0263da7 100644 +--- a/arch/microblaze/kernel/setup.c ++++ b/arch/microblaze/kernel/setup.c +@@ -150,33 +150,35 @@ void __init machine_early_init(const char *cmdline, unsigned int ram, + /* printk("TLB1 0x%08x, TLB0 0x%08x, tlb 0x%x\n", tlb0, + tlb1, kernel_tlb); */ + +- printk("Ramdisk addr 0x%08x, ", ram); ++ pr_info("Ramdisk addr 0x%08x, ", ram); + if (fdt) +- printk("FDT at 0x%08x\n", fdt); ++ pr_info("FDT at 0x%08x\n", fdt); + else +- printk("Compiled-in FDT at 0x%08x\n", ++ pr_info("Compiled-in FDT at 0x%08x\n", + (unsigned int)_fdt_start); + + #ifdef CONFIG_MTD_UCLINUX +- printk("Found romfs @ 0x%08x (0x%08x)\n", ++ pr_info("Found romfs @ 0x%08x (0x%08x)\n", + romfs_base, romfs_size); +- printk("#### klimit %p ####\n", old_klimit); ++ pr_info("#### klimit %p ####\n", old_klimit); + BUG_ON(romfs_size < 0); /* What else can we do? */ + +- printk("Moved 0x%08x bytes from 0x%08x to 0x%08x\n", ++ pr_info("Moved 0x%08x bytes from 0x%08x to 0x%08x\n", + romfs_size, romfs_base, (unsigned)&__bss_stop); + +- printk("New klimit: 0x%08x\n", (unsigned)klimit); ++ pr_info("New klimit: 0x%08x\n", (unsigned)klimit); + #endif + + #if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR +- if (msr) +- printk("!!!Your kernel has setup MSR instruction but " +- "CPU don't have it %x\n", msr); ++ if (msr) { ++ pr_info("!!!Your kernel has setup MSR instruction but "); ++ pr_cont("CPU don't have it %x\n", msr); ++ } + #else +- if (!msr) +- printk("!!!Your kernel not setup MSR instruction but " +- "CPU have it %x\n", msr); ++ if (!msr) { ++ pr_info("!!!Your kernel not setup MSR instruction but "); ++ pr_cont"CPU have it %x\n", msr); ++ } + #endif + + /* Do not copy reset vectors. offset = 0x2 means skip the first +@@ -216,6 +218,8 @@ static int __init debugfs_tlb(void) + d = debugfs_create_u32("tlb_skip", S_IRUGO, of_debugfs_root, &tlb_skip); + if (!d) + return -ENOMEM; ++ ++ return 0; + } + device_initcall(debugfs_tlb); + # endif +diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c +index ac3d0a0..4fcbad0 100644 +--- a/arch/microblaze/kernel/signal.c ++++ b/arch/microblaze/kernel/signal.c +@@ -255,7 +255,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, + set_fs(USER_DS); + + #ifdef DEBUG_SIG +- printk(KERN_INFO "SIG deliver (%s:%d): sp=%p pc=%08lx\n", ++ pr_info("SIG deliver (%s:%d): sp=%p pc=%08lx\n", + current->comm, current->pid, frame, regs->pc); + #endif + +@@ -330,8 +330,8 @@ static void do_signal(struct pt_regs *regs, int in_syscall) + int signr; + struct k_sigaction ka; + #ifdef DEBUG_SIG +- printk(KERN_INFO "do signal: %p %d\n", regs, in_syscall); +- printk(KERN_INFO "do signal2: %lx %lx %ld [%lx]\n", regs->pc, regs->r1, ++ pr_info("do signal: %p %d\n", regs, in_syscall); ++ pr_info("do signal2: %lx %lx %ld [%lx]\n", regs->pc, regs->r1, + regs->r12, current_thread_info()->flags); + #endif + +diff --git a/arch/microblaze/kernel/stacktrace.c b/arch/microblaze/kernel/stacktrace.c +index 84bc668..b4debe2 100644 +--- a/arch/microblaze/kernel/stacktrace.c ++++ b/arch/microblaze/kernel/stacktrace.c +@@ -9,11 +9,11 @@ + * for more details. + */ + ++#include + #include + #include + #include + #include +-#include + #include + + void save_stack_trace(struct stack_trace *trace) +diff --git a/arch/microblaze/kernel/sys_microblaze.c b/arch/microblaze/kernel/sys_microblaze.c +index 63647c5..f905b3a 100644 +--- a/arch/microblaze/kernel/sys_microblaze.c ++++ b/arch/microblaze/kernel/sys_microblaze.c +@@ -13,6 +13,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -24,14 +25,12 @@ + #include + #include + #include +-#include + #include + #include + #include + #include + #include + #include +- + #include + + asmlinkage long sys_mmap(unsigned long addr, unsigned long len, +diff --git a/arch/microblaze/kernel/traps.c b/arch/microblaze/kernel/traps.c +index 5541ac5..30e6b50 100644 +--- a/arch/microblaze/kernel/traps.c ++++ b/arch/microblaze/kernel/traps.c +@@ -8,9 +8,9 @@ + * for more details. + */ + ++#include + #include + #include +-#include + #include + #include + +@@ -26,7 +26,7 @@ static unsigned long kstack_depth_to_print; /* 0 == entire stack */ + + static int __init kstack_setup(char *s) + { +- return !strict_strtoul(s, 0, &kstack_depth_to_print); ++ return !kstrtoul(s, 0, &kstack_depth_to_print); + } + __setup("kstack=", kstack_setup); + +@@ -66,9 +66,7 @@ void show_stack(struct task_struct *task, unsigned long *sp) + } + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 32, 4, (void *)fp, + words_to_show << 2, 0); +- printk(KERN_INFO "\n\n"); +- +- pr_info("Call Trace:\n"); ++ pr_info("\n\nCall Trace:\n"); + microblaze_unwind(task, NULL); + pr_info("\n"); + +diff --git a/arch/microblaze/kernel/unwind.c b/arch/microblaze/kernel/unwind.c +index 6be4ae3..1f7b8d4 100644 +--- a/arch/microblaze/kernel/unwind.c ++++ b/arch/microblaze/kernel/unwind.c +@@ -13,13 +13,13 @@ + */ + + /* #define DEBUG 1 */ ++#include + #include + #include + #include + #include + #include + #include +-#include + #include + #include + #include +diff --git a/arch/microblaze/lib/ashldi3.c b/arch/microblaze/lib/ashldi3.c +index beb80f31..1af904c 100644 +--- a/arch/microblaze/lib/ashldi3.c ++++ b/arch/microblaze/lib/ashldi3.c +@@ -1,4 +1,4 @@ +-#include ++#include + + #include "libgcc.h" + +@@ -25,5 +25,4 @@ long long __ashldi3(long long u, word_type b) + + return w.ll; + } +- + EXPORT_SYMBOL(__ashldi3); +diff --git a/arch/microblaze/lib/ashrdi3.c b/arch/microblaze/lib/ashrdi3.c +index c884a91..32c334c 100644 +--- a/arch/microblaze/lib/ashrdi3.c ++++ b/arch/microblaze/lib/ashrdi3.c +@@ -1,4 +1,4 @@ +-#include ++#include + + #include "libgcc.h" + +@@ -27,5 +27,4 @@ long long __ashrdi3(long long u, word_type b) + + return w.ll; + } +- + EXPORT_SYMBOL(__ashrdi3); +diff --git a/arch/microblaze/lib/cmpdi2.c b/arch/microblaze/lib/cmpdi2.c +index a708400..67abc9a 100644 +--- a/arch/microblaze/lib/cmpdi2.c ++++ b/arch/microblaze/lib/cmpdi2.c +@@ -1,4 +1,4 @@ +-#include ++#include + + #include "libgcc.h" + +diff --git a/arch/microblaze/lib/lshrdi3.c b/arch/microblaze/lib/lshrdi3.c +index dcf8d68..adcb253 100644 +--- a/arch/microblaze/lib/lshrdi3.c ++++ b/arch/microblaze/lib/lshrdi3.c +@@ -1,4 +1,4 @@ +-#include ++#include + + #include "libgcc.h" + +@@ -25,5 +25,4 @@ long long __lshrdi3(long long u, word_type b) + + return w.ll; + } +- + EXPORT_SYMBOL(__lshrdi3); +diff --git a/arch/microblaze/lib/memcpy.c b/arch/microblaze/lib/memcpy.c +index fe9c53f..f536e81 100644 +--- a/arch/microblaze/lib/memcpy.c ++++ b/arch/microblaze/lib/memcpy.c +@@ -24,10 +24,10 @@ + * not any responsibility to update it. + */ + ++#include + #include + #include + #include +-#include + + #include + +@@ -103,12 +103,12 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c) + } + #else + /* Load the holding buffer */ +- buf_hold = (*i_src++ & 0xFFFFFF00) >>8; ++ buf_hold = (*i_src++ & 0xFFFFFF00) >> 8; + + for (; c >= 4; c -= 4) { + value = *i_src++; + *i_dst++ = buf_hold | ((value & 0xFF) << 24); +- buf_hold = (value & 0xFFFFFF00) >>8; ++ buf_hold = (value & 0xFFFFFF00) >> 8; + } + #endif + /* Realign the source */ +@@ -129,12 +129,12 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c) + } + #else + /* Load the holding buffer */ +- buf_hold = (*i_src++ & 0xFFFF0000 )>>16; ++ buf_hold = (*i_src++ & 0xFFFF0000) >> 16; + + for (; c >= 4; c -= 4) { + value = *i_src++; +- *i_dst++ = buf_hold | ((value & 0xFFFF)<<16); +- buf_hold = (value & 0xFFFF0000) >>16; ++ *i_dst++ = buf_hold | ((value & 0xFFFF) << 16); ++ buf_hold = (value & 0xFFFF0000) >> 16; + } + #endif + /* Realign the source */ +diff --git a/arch/microblaze/lib/memmove.c b/arch/microblaze/lib/memmove.c +index 2146c37..3611ce7 100644 +--- a/arch/microblaze/lib/memmove.c ++++ b/arch/microblaze/lib/memmove.c +@@ -24,10 +24,10 @@ + * not any responsibility to update it. + */ + ++#include + #include + #include + #include +-#include + #include + + #ifdef __HAVE_ARCH_MEMMOVE +@@ -129,7 +129,8 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c) + + for (; c >= 4; c -= 4) { + value = *--i_src; +- *--i_dst = buf_hold | ((value & 0xFFFFFF00)>>8); ++ *--i_dst = buf_hold | ++ ((value & 0xFFFFFF00) >> 8); + buf_hold = (value & 0xFF) << 24; + } + #endif +@@ -155,7 +156,8 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c) + + for (; c >= 4; c -= 4) { + value = *--i_src; +- *--i_dst = buf_hold | ((value & 0xFFFF0000)>>16); ++ *--i_dst = buf_hold | ++ ((value & 0xFFFF0000) >> 16); + buf_hold = (value & 0xFFFF) << 16; + } + #endif +@@ -181,7 +183,8 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c) + + for (; c >= 4; c -= 4) { + value = *--i_src; +- *--i_dst = buf_hold | ((value & 0xFF000000)>> 24); ++ *--i_dst = buf_hold | ++ ((value & 0xFF000000) >> 24); + buf_hold = (value & 0xFFFFFF) << 8; + } + #endif +diff --git a/arch/microblaze/lib/memset.c b/arch/microblaze/lib/memset.c +index ddf6793..04ea72c 100644 +--- a/arch/microblaze/lib/memset.c ++++ b/arch/microblaze/lib/memset.c +@@ -24,10 +24,10 @@ + * not any responsibility to update it. + */ + ++#include + #include + #include + #include +-#include + #include + + #ifdef __HAVE_ARCH_MEMSET +diff --git a/arch/microblaze/lib/muldi3.c b/arch/microblaze/lib/muldi3.c +index d365924..a3f9a03 100644 +--- a/arch/microblaze/lib/muldi3.c ++++ b/arch/microblaze/lib/muldi3.c +@@ -1,4 +1,4 @@ +-#include ++#include + + #include "libgcc.h" + +diff --git a/arch/microblaze/lib/ucmpdi2.c b/arch/microblaze/lib/ucmpdi2.c +index 63ca105..d05f158 100644 +--- a/arch/microblaze/lib/ucmpdi2.c ++++ b/arch/microblaze/lib/ucmpdi2.c +@@ -1,4 +1,4 @@ +-#include ++#include + + #include "libgcc.h" + +diff --git a/arch/microblaze/mm/consistent.c b/arch/microblaze/mm/consistent.c +index a1e2e18..5226b09 100644 +--- a/arch/microblaze/mm/consistent.c ++++ b/arch/microblaze/mm/consistent.c +@@ -13,7 +13,7 @@ + * published by the Free Software Foundation. + */ + +-#include ++#include + #include + #include + #include +@@ -37,7 +37,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include +@@ -102,8 +102,7 @@ void *consistent_alloc(gfp_t gfp, size_t size, dma_addr_t *dma_handle) + # endif + if ((unsigned int)ret > cpuinfo.dcache_base && + (unsigned int)ret < cpuinfo.dcache_high) +- printk(KERN_WARNING +- "ERROR: Your cache coherent area is CACHED!!!\n"); ++ pr_warn("ERROR: Your cache coherent area is CACHED!!!\n"); + + /* dma_handle is same as physical (shadowed) address */ + *dma_handle = (dma_addr_t)ret; +diff --git a/arch/microblaze/mm/fault.c b/arch/microblaze/mm/fault.c +index 714b35a..731f739 100644 +--- a/arch/microblaze/mm/fault.c ++++ b/arch/microblaze/mm/fault.c +@@ -32,7 +32,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + +@@ -100,7 +100,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, + + /* On a kernel SLB miss we can only check for a valid exception entry */ + if (unlikely(kernel_mode(regs) && (address >= TASK_SIZE))) { +- printk(KERN_WARNING "kernel task_size exceed"); ++ pr_warn("kernel task_size exceed"); + _exception(SIGSEGV, regs, code, address); + } + +@@ -114,9 +114,9 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, + + /* in_atomic() in user mode is really bad, + as is current->mm == NULL. */ +- printk(KERN_EMERG "Page fault in user mode with " +- "in_atomic(), mm = %p\n", mm); +- printk(KERN_EMERG "r15 = %lx MSR = %lx\n", ++ pr_emerg("Page fault in user mode with in_atomic(), mm = %p\n", ++ mm); ++ pr_emerg("r15 = %lx MSR = %lx\n", + regs->r15, regs->msr); + die("Weird page fault", regs, SIGSEGV); + } +diff --git a/arch/microblaze/mm/highmem.c b/arch/microblaze/mm/highmem.c +index 7d78838..5a92576 100644 +--- a/arch/microblaze/mm/highmem.c ++++ b/arch/microblaze/mm/highmem.c +@@ -20,8 +20,8 @@ + * highmem.h by Benjamin Herrenschmidt (c) 2009 IBM Corp. + */ + ++#include + #include +-#include + + /* + * The use of kmap_atomic/kunmap_atomic is discouraged - kmap/kunmap +diff --git a/arch/microblaze/mm/init.c b/arch/microblaze/mm/init.c +index f394ad8..40acde5 100644 +--- a/arch/microblaze/mm/init.c ++++ b/arch/microblaze/mm/init.c +@@ -89,7 +89,7 @@ static unsigned long highmem_setup(void) + reservedpages++; + } + totalram_pages += totalhigh_pages; +- printk(KERN_INFO "High memory: %luk\n", ++ pr_info("High memory: %luk\n", + totalhigh_pages << (PAGE_SHIFT-10)); + + return reservedpages; +@@ -142,8 +142,8 @@ void __init setup_memory(void) + ((u32)_text <= (memory_start + lowmem_size - 1))) { + memory_size = lowmem_size; + PAGE_OFFSET = memory_start; +- printk(KERN_INFO "%s: Main mem: 0x%x, " +- "size 0x%08x\n", __func__, (u32) memory_start, ++ pr_info("%s: Main mem: 0x%x, size 0x%08x\n", ++ __func__, (u32) memory_start, + (u32) memory_size); + break; + } +@@ -158,7 +158,7 @@ void __init setup_memory(void) + kernel_align_start = PAGE_DOWN((u32)_text); + /* ALIGN can be remove because _end in vmlinux.lds.S is align */ + kernel_align_size = PAGE_UP((u32)klimit) - kernel_align_start; +- printk(KERN_INFO "%s: kernel addr:0x%08x-0x%08x size=0x%08x\n", ++ pr_info("%s: kernel addr:0x%08x-0x%08x size=0x%08x\n", + __func__, kernel_align_start, kernel_align_start + + kernel_align_size, kernel_align_size); + memblock_reserve(kernel_align_start, kernel_align_size); +@@ -181,10 +181,10 @@ void __init setup_memory(void) + max_low_pfn = ((u64)memory_start + (u64)lowmem_size) >> PAGE_SHIFT; + max_pfn = ((u64)memory_start + (u64)memory_size) >> PAGE_SHIFT; + +- printk(KERN_INFO "%s: max_mapnr: %#lx\n", __func__, max_mapnr); +- printk(KERN_INFO "%s: min_low_pfn: %#lx\n", __func__, min_low_pfn); +- printk(KERN_INFO "%s: max_low_pfn: %#lx\n", __func__, max_low_pfn); +- printk(KERN_INFO "%s: max_pfn: %#lx\n", __func__, max_pfn); ++ pr_info("%s: max_mapnr: %#lx\n", __func__, max_mapnr); ++ pr_info("%s: min_low_pfn: %#lx\n", __func__, min_low_pfn); ++ pr_info("%s: max_low_pfn: %#lx\n", __func__, max_low_pfn); ++ pr_info("%s: max_pfn: %#lx\n", __func__, max_pfn); + + /* + * Find an area to use for the bootmem bitmap. +@@ -301,11 +301,11 @@ void __init mem_init(void) + initsize = (unsigned long)&__init_end - (unsigned long)&__init_begin; + bsssize = (unsigned long)&__bss_stop - (unsigned long)&__bss_start; + +- pr_info("Memory: %luk/%luk available (%luk kernel code, " +- "%luk reserved, %luk data, %luk bss, %luk init)\n", ++ pr_info("Memory: %luk/%luk available (%luk kernel code, ", + nr_free_pages() << (PAGE_SHIFT-10), + num_physpages << (PAGE_SHIFT-10), +- codesize >> 10, ++ codesize >> 10); ++ pr_cont("%luk reserved, %luk data, %luk bss, %luk init)\n", + reservedpages << (PAGE_SHIFT-10), + datasize >> 10, + bsssize >> 10, +@@ -391,17 +391,17 @@ asmlinkage void __init mmu_init(void) + unsigned int kstart, ksize; + + if (!memblock.reserved.cnt) { +- printk(KERN_EMERG "Error memory count\n"); ++ pr_emerg("Error memory count\n"); + machine_restart(NULL); + } + + if ((u32) memblock.memory.regions[0].size < 0x400000) { +- printk(KERN_EMERG "Memory must be greater than 4MB\n"); ++ pr_emerg("Memory must be greater than 4MB\n"); + machine_restart(NULL); + } + + if ((u32) memblock.memory.regions[0].size < kernel_tlb) { +- printk(KERN_EMERG "Kernel size is greater than memory node\n"); ++ pr_emerg("Kernel size is greater than memory node\n"); + machine_restart(NULL); + } + +diff --git a/arch/microblaze/mm/pgtable.c b/arch/microblaze/mm/pgtable.c +index d1c06d0..10b3bd0 100644 +--- a/arch/microblaze/mm/pgtable.c ++++ b/arch/microblaze/mm/pgtable.c +@@ -26,8 +26,8 @@ + * + */ + ++#include + #include +-#include + #include + #include + #include +@@ -39,8 +39,6 @@ + #include + #include + +-#define flush_HPTE(X, va, pg) _tlbie(va) +- + unsigned long ioremap_base; + unsigned long ioremap_bot; + EXPORT_SYMBOL(ioremap_bot); +@@ -75,9 +73,8 @@ static void __iomem *__ioremap(phys_addr_t addr, unsigned long size, + p >= memory_start && p < virt_to_phys(high_memory) && + !(p >= virt_to_phys((unsigned long)&__bss_stop) && + p < virt_to_phys((unsigned long)__bss_stop))) { +- printk(KERN_WARNING "__ioremap(): phys addr "PTE_FMT +- " is RAM lr %pf\n", (unsigned long)p, +- __builtin_return_address(0)); ++ pr_warn("__ioremap(): phys addr "PTE_FMT" is RAM lr %pf\n", ++ (unsigned long)p, __builtin_return_address(0)); + return NULL; + } + +@@ -128,9 +125,10 @@ void __iomem *ioremap(phys_addr_t addr, unsigned long size) + } + EXPORT_SYMBOL(ioremap); + +-void iounmap(void *addr) ++void iounmap(void __iomem *addr) + { +- if (addr > high_memory && (unsigned long) addr < ioremap_bot) ++ if ((__force void *)addr > high_memory && ++ (unsigned long) addr < ioremap_bot) + vfree((void *) (PAGE_MASK & (unsigned long) addr)); + } + EXPORT_SYMBOL(iounmap); +@@ -152,8 +150,7 @@ int map_page(unsigned long va, phys_addr_t pa, int flags) + set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT, + __pgprot(flags))); + if (unlikely(mem_init_done)) +- flush_HPTE(0, va, pmd_val(*pd)); +- /* flush_HPTE(0, va, pg); */ ++ _tlbie(va); + } + return err; + } +diff --git a/arch/microblaze/pci/indirect_pci.c b/arch/microblaze/pci/indirect_pci.c +index 4196eb6..ae4fca4 100644 +--- a/arch/microblaze/pci/indirect_pci.c ++++ b/arch/microblaze/pci/indirect_pci.c +@@ -15,7 +15,7 @@ + #include + #include + +-#include ++#include + #include + #include + +diff --git a/arch/microblaze/pci/iomap.c b/arch/microblaze/pci/iomap.c +index b07abba..94149f5 100644 +--- a/arch/microblaze/pci/iomap.c ++++ b/arch/microblaze/pci/iomap.c +@@ -7,7 +7,7 @@ + #include + #include + #include +-#include ++#include + #include + + void pci_iounmap(struct pci_dev *dev, void __iomem *addr) +diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c +index b087a56..abae0f8 100644 +--- a/arch/microblaze/pci/pci-common.c ++++ b/arch/microblaze/pci/pci-common.c +@@ -30,10 +30,11 @@ + #include + #include + #include ++#include + #include + + #include +-#include ++#include + #include + #include + +@@ -554,11 +555,10 @@ int pci_mmap_legacy_page_range(struct pci_bus *bus, + */ + if ((offset + size) > hose->isa_mem_size) { + #ifdef CONFIG_MMU +- printk(KERN_DEBUG +- "Process %s (pid:%d) mapped non-existing PCI" +- "legacy memory for 0%04x:%02x\n", +- current->comm, current->pid, pci_domain_nr(bus), +- bus->number); ++ pr_debug("Process %s (pid:%d) mapped non-existing PCI", ++ current->comm, current->pid); ++ pr_debug("legacy memory for 0%04x:%02x\n", ++ pci_domain_nr(bus), bus->number); + #endif + if (vma->vm_flags & VM_SHARED) + return shmem_zero_setup(vma); +@@ -566,7 +566,7 @@ int pci_mmap_legacy_page_range(struct pci_bus *bus, + } + offset += hose->isa_mem_phys; + } else { +- unsigned long io_offset = (unsigned long)hose->io_base_virt - \ ++ unsigned long io_offset = (unsigned long)hose->io_base_virt - + _IO_BASE; + unsigned long roffset = offset + io_offset; + rp = &hose->io_resource; +@@ -671,7 +671,7 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose, + unsigned long long isa_mb = 0; + struct resource *res; + +- printk(KERN_INFO "PCI host bridge %s %s ranges:\n", ++ pr_info("PCI host bridge %s %s ranges:\n", + dev->full_name, primary ? "(primary)" : ""); + + /* Get ranges property */ +@@ -688,9 +688,10 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose, + cpu_addr = of_translate_address(dev, ranges + 3); + size = of_read_number(ranges + pna + 3, 2); + +- pr_debug("pci_space: 0x%08x pci_addr:0x%016llx " +- "cpu_addr:0x%016llx size:0x%016llx\n", +- pci_space, pci_addr, cpu_addr, size); ++ pr_debug("pci_space: 0x%08x pci_addr:0x%016llx ", ++ pci_space, pci_addr); ++ pr_debug("cpu_addr:0x%016llx size:0x%016llx\n", ++ cpu_addr, size); + + ranges += np; + +@@ -719,14 +720,12 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose, + res = NULL; + switch ((pci_space >> 24) & 0x3) { + case 1: /* PCI IO space */ +- printk(KERN_INFO +- " IO 0x%016llx..0x%016llx -> 0x%016llx\n", ++ pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n", + cpu_addr, cpu_addr + size - 1, pci_addr); + + /* We support only one IO range */ + if (hose->pci_io_size) { +- printk(KERN_INFO +- " \\--> Skipped (too many) !\n"); ++ pr_info(" \\--> Skipped (too many) !\n"); + continue; + } + /* On 32 bits, limit I/O space to 16MB */ +@@ -753,15 +752,13 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose, + break; + case 2: /* PCI Memory space */ + case 3: /* PCI 64 bits Memory space */ +- printk(KERN_INFO +- " MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n", ++ pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n", + cpu_addr, cpu_addr + size - 1, pci_addr, + (pci_space & 0x40000000) ? "Prefetch" : ""); + + /* We support only 3 memory ranges */ + if (memno >= 3) { +- printk(KERN_INFO +- " \\--> Skipped (too many) !\n"); ++ pr_info(" \\--> Skipped (too many) !\n"); + continue; + } + /* Handles ISA memory hole space here */ +@@ -784,8 +781,7 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose, + hose->pci_mem_offset = cpu_addr - pci_addr; + else if (pci_addr != 0 && + hose->pci_mem_offset != cpu_addr - pci_addr) { +- printk(KERN_INFO +- " \\--> Skipped (offset mismatch) !\n"); ++ pr_info(" \\--> Skipped (offset mismatch) !\n"); + continue; + } + +@@ -812,7 +808,7 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose, + */ + if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) { + unsigned int next = isa_hole + 1; +- printk(KERN_INFO " Removing ISA hole at 0x%016llx\n", isa_mb); ++ pr_info(" Removing ISA hole at 0x%016llx\n", isa_mb); + if (next < memno) + memmove(&hose->mem_resources[isa_hole], + &hose->mem_resources[next], +@@ -836,7 +832,7 @@ static void pcibios_fixup_resources(struct pci_dev *dev) + int i; + + if (!hose) { +- printk(KERN_ERR "No host bridge for PCI dev %s !\n", ++ pr_err("No host bridge for PCI dev %s !\n", + pci_name(dev)); + return; + } +@@ -845,12 +841,12 @@ static void pcibios_fixup_resources(struct pci_dev *dev) + if (!res->flags) + continue; + if (res->start == 0) { +- pr_debug("PCI:%s Resource %d %016llx-%016llx [%x]" \ +- "is unassigned\n", ++ pr_debug("PCI:%s Resource %d %016llx-%016llx [%x]", + pci_name(dev), i, + (unsigned long long)res->start, + (unsigned long long)res->end, + (unsigned int)res->flags); ++ pr_debug("is unassigned\n"); + res->end -= res->start; + res->start = 0; + res->flags |= IORESOURCE_UNSET; +@@ -859,7 +855,7 @@ static void pcibios_fixup_resources(struct pci_dev *dev) + + pr_debug("PCI:%s Resource %d %016llx-%016llx [%x]\n", + pci_name(dev), i, +- (unsigned long long)res->start,\ ++ (unsigned long long)res->start, + (unsigned long long)res->end, + (unsigned int)res->flags); + } +@@ -950,7 +946,7 @@ static void pcibios_fixup_bridge(struct pci_bus *bus) + + pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x] fixup...\n", + pci_name(dev), i, +- (unsigned long long)res->start,\ ++ (unsigned long long)res->start, + (unsigned long long)res->end, + (unsigned int)res->flags); + +@@ -1162,12 +1158,12 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus) + } + } + +- pr_debug("PCI: %s (bus %d) bridge rsrc %d: %016llx-%016llx " +- "[0x%x], parent %p (%s)\n", ++ pr_debug("PCI: %s (bus %d) bridge rsrc %d: %016llx-%016llx ", + bus->self ? pci_name(bus->self) : "PHB", + bus->number, i, + (unsigned long long)res->start, +- (unsigned long long)res->end, ++ (unsigned long long)res->end); ++ pr_debug("[0x%x], parent %p (%s)\n", + (unsigned int)res->flags, + pr, (pr && pr->name) ? pr->name : "nil"); + +@@ -1182,9 +1178,8 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus) + if (reparent_resources(pr, res) == 0) + continue; + } +- printk(KERN_WARNING "PCI: Cannot allocate resource region " +- "%d of PCI bridge %d, will remap\n", i, bus->number); +- ++ pr_warn("PCI: Cannot allocate resource region "); ++ pr_cont("%d of PCI bridge %d, will remap\n", i, bus->number); + res->start = res->end = 0; + res->flags = 0; + } +@@ -1206,8 +1201,8 @@ static inline void alloc_resource(struct pci_dev *dev, int idx) + pr = pci_find_parent_resource(dev, r); + if (!pr || (pr->flags & IORESOURCE_UNSET) || + request_resource(pr, r) < 0) { +- printk(KERN_WARNING "PCI: Cannot allocate resource region %d" +- " of device %s, will remap\n", idx, pci_name(dev)); ++ pr_warn("PCI: Cannot allocate resource region %d ", idx); ++ pr_cont("of device %s, will remap\n", pci_name(dev)); + if (pr) + pr_debug("PCI: parent is %p: %016llx-%016llx [%x]\n", + pr, +@@ -1290,8 +1285,7 @@ static void __init pcibios_reserve_legacy_regions(struct pci_bus *bus) + res->end = (offset + 0xfff) & 0xfffffffful; + pr_debug("Candidate legacy IO: %pR\n", res); + if (request_resource(&hose->io_resource, res)) { +- printk(KERN_DEBUG +- "PCI %04x:%02x Cannot reserve Legacy IO %pR\n", ++ pr_debug("PCI %04x:%02x Cannot reserve Legacy IO %pR\n", + pci_domain_nr(bus), bus->number, res); + kfree(res); + } +@@ -1319,8 +1313,7 @@ static void __init pcibios_reserve_legacy_regions(struct pci_bus *bus) + res->end = 0xbffff + offset; + pr_debug("Candidate VGA memory: %pR\n", res); + if (request_resource(pres, res)) { +- printk(KERN_DEBUG +- "PCI %04x:%02x Cannot reserve VGA memory %pR\n", ++ pr_debug("PCI %04x:%02x Cannot reserve VGA memory %pR\n", + pci_domain_nr(bus), bus->number, res); + kfree(res); + } +@@ -1370,10 +1363,9 @@ void pcibios_claim_one_bus(struct pci_bus *bus) + if (r->parent || !r->start || !r->flags) + continue; + +- pr_debug("PCI: Claiming %s: " +- "Resource %d: %016llx..%016llx [%x]\n", +- pci_name(dev), i, +- (unsigned long long)r->start, ++ pr_debug("PCI: Claiming %s: ", pci_name(dev)); ++ pr_debug("Resource %d: %016llx..%016llx [%x]\n", ++ i, (unsigned long long)r->start, + (unsigned long long)r->end, + (unsigned int)r->flags); + +@@ -1430,9 +1422,9 @@ static void pcibios_setup_phb_resources(struct pci_controller *hose, + res->end = (res->end + io_offset) & 0xffffffffu; + + if (!res->flags) { +- printk(KERN_WARNING "PCI: I/O resource not set for host" +- " bridge %s (domain %d)\n", +- hose->dn->full_name, hose->global_number); ++ pr_warn("PCI: I/O resource not set for host "); ++ pr_cont("bridge %s (domain %d)\n", ++ hose->dn->full_name, hose->global_number); + /* Workaround for lack of IO resource only on 32-bit */ + res->start = (unsigned long)hose->io_base_virt - isa_io_base; + res->end = res->start + IO_SPACE_LIMIT; +@@ -1452,9 +1444,9 @@ static void pcibios_setup_phb_resources(struct pci_controller *hose, + if (!res->flags) { + if (i > 0) + continue; +- printk(KERN_ERR "PCI: Memory resource 0 not set for " +- "host bridge %s (domain %d)\n", +- hose->dn->full_name, hose->global_number); ++ pr_err("PCI: Memory resource 0 not set for "); ++ pr_cont("host bridge %s (domain %d)\n", ++ hose->dn->full_name, hose->global_number); + + /* Workaround for lack of MEM resource only on 32-bit */ + res->start = hose->pci_mem_offset; +@@ -1496,7 +1488,7 @@ static void pcibios_scan_phb(struct pci_controller *hose) + bus = pci_scan_root_bus(hose->parent, hose->first_busno, + hose->ops, hose, &resources); + if (bus == NULL) { +- printk(KERN_ERR "Failed to create bus for PCI domain %04x\n", ++ pr_err("Failed to create bus for PCI domain %04x\n", + hose->global_number); + pci_free_resource_list(&resources); + return; +@@ -1512,7 +1504,7 @@ static int __init pcibios_init(void) + struct pci_controller *hose, *tmp; + int next_busno = 0; + +- printk(KERN_INFO "PCI: Probing PCI hardware\n"); ++ pr_info("PCI: Probing PCI hardware\n"); + + /* Scan all of the recorded PCI controllers. */ + list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { +@@ -1612,7 +1604,7 @@ fake_pci_bus(struct pci_controller *hose, int busnr) + static struct pci_bus bus; + + if (!hose) +- printk(KERN_ERR "Can't find hose for PCI bus %d!\n", busnr); ++ pr_err("Can't find hose for PCI bus %d!\n", busnr); + + bus.number = busnr; + bus.sysdata = hose; +diff --git a/arch/microblaze/pci/xilinx_pci.c b/arch/microblaze/pci/xilinx_pci.c +index 0687a42..14c7da5 100644 +--- a/arch/microblaze/pci/xilinx_pci.c ++++ b/arch/microblaze/pci/xilinx_pci.c +@@ -18,7 +18,7 @@ + #include + #include + #include +-#include ++#include + + #define XPLB_PCI_ADDR 0x10c + #define XPLB_PCI_DATA 0x110 +@@ -82,7 +82,7 @@ xilinx_pci_exclude_device(struct pci_controller *hose, u_char bus, u8 devfn) + * + * List pci devices in very early phase. + */ +-void __init xilinx_early_pci_scan(struct pci_controller *hose) ++static void __init xilinx_early_pci_scan(struct pci_controller *hose) + { + u32 bus = 0; + u32 val, dev, func, offset; +@@ -91,27 +91,27 @@ void __init xilinx_early_pci_scan(struct pci_controller *hose) + for (dev = 0; dev < 2; dev++) { + /* List only first function number - up-to 8 functions */ + for (func = 0; func < 1; func++) { +- printk(KERN_INFO "%02x:%02x:%02x", bus, dev, func); ++ pr_info("%02x:%02x:%02x", bus, dev, func); + /* read the first 64 standardized bytes */ + /* Up-to 192 bytes can be list of capabilities */ + for (offset = 0; offset < 64; offset += 4) { + early_read_config_dword(hose, bus, + PCI_DEVFN(dev, func), offset, &val); + if (offset == 0 && val == 0xFFFFFFFF) { +- printk(KERN_CONT "\nABSENT"); ++ pr_cont("\nABSENT"); + break; + } + if (!(offset % 0x10)) +- printk(KERN_CONT "\n%04x: ", offset); ++ pr_cont("\n%04x: ", offset); + +- printk(KERN_CONT "%08x ", val); ++ pr_cont("%08x ", val); + } +- printk(KERN_INFO "\n"); ++ pr_info("\n"); + } + } + } + #else +-void __init xilinx_early_pci_scan(struct pci_controller *hose) ++static void __init xilinx_early_pci_scan(struct pci_controller *hose) + { + } + #endif +diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c +index ac3a0e7..07dff54 100644 +--- a/arch/mips/kernel/proc.c ++++ b/arch/mips/kernel/proc.c +@@ -22,7 +22,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) + unsigned int version = cpu_data[n].processor_id; + unsigned int fp_vers = cpu_data[n].fpu_id; + char fmt [64]; +- int cpu,i; ++ int i; + + #ifdef CONFIG_SMP + if (!cpu_online(n)) +@@ -42,11 +42,9 @@ static int show_cpuinfo(struct seq_file *m, void *v) + seq_printf(m, "processor\t\t: %ld\n", n); + sprintf(fmt, "cpu model\t\t: %%s V%%d.%%d%s\n", + cpu_data[n].options & MIPS_CPU_FPU ? " FPU V%d.%d" : ""); +- cpu = get_cpu(); +- seq_printf(m, fmt, __cpu_name[cpu], ++ seq_printf(m, fmt, __cpu_name[n], + (version >> 4) & 0x0f, version & 0x0f, + (fp_vers >> 4) & 0x0f, fp_vers & 0x0f); +- put_cpu(); + seq_printf(m, "BogoMIPS\t\t: %u.%02u\n", + cpu_data[n].udelay_val / (500000/HZ), + (cpu_data[n].udelay_val / (5000/HZ)) % 100); +diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c +index c5e99e0..0f7d788 100644 +--- a/arch/mips/mm/c-r4k.c ++++ b/arch/mips/mm/c-r4k.c +@@ -382,12 +382,12 @@ static inline int has_valid_asid(const struct mm_struct *mm) + + static void r4k__flush_cache_vmap(void) + { +- r4k_on_each_cpu((void *)r4k_blast_dcache, NULL); ++ r4k_blast_dcache(); + } + + static void r4k__flush_cache_vunmap(void) + { +- r4k_on_each_cpu((void *)r4k_blast_dcache, NULL); ++ r4k_blast_dcache(); + } + + static inline void local_r4k_flush_cache_range(void * args) +@@ -613,7 +613,7 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) + * explicitly + */ + if (cpu_has_safe_index_cacheops && size >= dcache_size) { +- r4k_on_each_cpu((void *)r4k_blast_dcache, NULL); ++ r4k_blast_dcache(); + } else { + R4600_HIT_CACHEOP_WAR_IMPL; + blast_dcache_range(addr, addr + size); +@@ -647,7 +647,7 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size) + } + + if (cpu_has_safe_index_cacheops && size >= dcache_size) { +- r4k_on_each_cpu((void *)r4k_blast_dcache, NULL); ++ r4k_blast_dcache(); + } else { + R4600_HIT_CACHEOP_WAR_IMPL; + blast_inv_dcache_range(addr, addr + size); +diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c +index b2b8511..1c8ac49 100644 +--- a/arch/mips/mm/tlbex.c ++++ b/arch/mips/mm/tlbex.c +@@ -488,7 +488,6 @@ static void __cpuinit __maybe_unused build_tlb_probe_entry(u32 **p) + case CPU_R4700: + case CPU_R5000: + case CPU_NEVADA: +- case CPU_4KC: + uasm_i_nop(p); + uasm_i_tlbp(p); + break; +@@ -555,7 +554,6 @@ static void __cpuinit build_tlb_write_entry(u32 **p, struct uasm_label **l, + + case CPU_R4600: + case CPU_R4700: +- case CPU_4KC: + uasm_i_nop(p); + tlbw(p); + uasm_i_nop(p); +@@ -580,6 +578,7 @@ static void __cpuinit build_tlb_write_entry(u32 **p, struct uasm_label **l, + case CPU_R10000: + case CPU_R12000: + case CPU_R14000: ++ case CPU_4KC: + case CPU_4KEC: + case CPU_M14KC: + case CPU_SB1: +diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile +index dc50b28..b639852 100644 +--- a/arch/powerpc/Makefile ++++ b/arch/powerpc/Makefile +@@ -172,9 +172,6 @@ relocs_check: arch/powerpc/relocs_check.pl vmlinux + zImage: relocs_check + endif + +-# These targets cannot be built in parallel +-.NOTPARALLEL: $(BOOT_TARGETS) +- + $(BOOT_TARGETS1): vmlinux + $(Q)$(MAKE) ARCH=ppc64 $(build)=$(boot) $(patsubst %,$(boot)/%,$@) + $(BOOT_TARGETS2): vmlinux +@@ -221,7 +218,7 @@ endif + archclean: + $(Q)$(MAKE) $(clean)=$(boot) + +-archprepare: checkbin arch/powerpc/lib/crtsavres.o ++archprepare: checkbin + + # Use the file '.tmp_gas_check' for binutils tests, as gas won't output + # to stdout and these checks are run even on install targets. +diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile +index 5381ef6..c39b728 100644 +--- a/arch/powerpc/boot/Makefile ++++ b/arch/powerpc/boot/Makefile +@@ -20,7 +20,7 @@ + all: $(obj)/zImage + + BOOTCFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \ +- -fno-strict-aliasing -msoft-float -pipe \ ++ -fno-strict-aliasing -Os -msoft-float -pipe \ + -fomit-frame-pointer -fno-builtin -fPIC -nostdinc \ + -isystem $(shell $(CROSS32CC) -print-file-name=include) + BOOTAFLAGS := -D__ASSEMBLY__ $(BOOTCFLAGS) -traditional -nostdinc +diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h +index 4f440a6..51fb00a 100644 +--- a/arch/powerpc/include/asm/ppc-opcode.h ++++ b/arch/powerpc/include/asm/ppc-opcode.h +@@ -112,10 +112,6 @@ + #define PPC_INST_MFSPR_DSCR_MASK 0xfc1fffff + #define PPC_INST_MTSPR_DSCR 0x7c1103a6 + #define PPC_INST_MTSPR_DSCR_MASK 0xfc1fffff +-#define PPC_INST_MFSPR_DSCR_USER 0x7c0302a6 +-#define PPC_INST_MFSPR_DSCR_USER_MASK 0xfc1fffff +-#define PPC_INST_MTSPR_DSCR_USER 0x7c0303a6 +-#define PPC_INST_MTSPR_DSCR_USER_MASK 0xfc1fffff + #define PPC_INST_SLBFEE 0x7c0007a7 + + #define PPC_INST_STRING 0x7c00042a +diff --git a/arch/powerpc/kernel/cpu_setup_power.S b/arch/powerpc/kernel/cpu_setup_power.S +index 0c0fc7b..57cf140 100644 +--- a/arch/powerpc/kernel/cpu_setup_power.S ++++ b/arch/powerpc/kernel/cpu_setup_power.S +@@ -64,7 +64,6 @@ _GLOBAL(__restore_cpu_power8) + mflr r11 + mfmsr r3 + rldicl. r0,r3,4,63 +- mtlr r11 + beqlr + li r0,0 + mtspr SPRN_LPID,r0 +diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S +index bb11075..3684cbd 100644 +--- a/arch/powerpc/kernel/exceptions-64s.S ++++ b/arch/powerpc/kernel/exceptions-64s.S +@@ -740,7 +740,7 @@ hardware_interrupt_relon_hv: + _MASKABLE_RELON_EXCEPTION_PSERIES(0x502, hardware_interrupt, EXC_HV, SOFTEN_TEST_HV) + FTR_SECTION_ELSE + _MASKABLE_RELON_EXCEPTION_PSERIES(0x500, hardware_interrupt, EXC_STD, SOFTEN_TEST_PR) +- ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE) ++ ALT_FTR_SECTION_END_IFSET(CPU_FTR_ARCH_206) + STD_RELON_EXCEPTION_PSERIES(0x4600, 0x600, alignment) + STD_RELON_EXCEPTION_PSERIES(0x4700, 0x700, program_check) + STD_RELON_EXCEPTION_PSERIES(0x4800, 0x800, fp_unavailable) +diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S +index 1a63feb..116f086 100644 +--- a/arch/powerpc/kernel/head_64.S ++++ b/arch/powerpc/kernel/head_64.S +@@ -490,7 +490,6 @@ _GLOBAL(copy_and_flush) + sync + addi r5,r5,8 + addi r6,r6,8 +- isync + blr + + .align 8 +diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c +index 3a64ecb..97dadd9 100644 +--- a/arch/powerpc/kernel/traps.c ++++ b/arch/powerpc/kernel/traps.c +@@ -965,10 +965,7 @@ static int emulate_instruction(struct pt_regs *regs) + + #ifdef CONFIG_PPC64 + /* Emulate the mfspr rD, DSCR. */ +- if ((((instword & PPC_INST_MFSPR_DSCR_USER_MASK) == +- PPC_INST_MFSPR_DSCR_USER) || +- ((instword & PPC_INST_MFSPR_DSCR_MASK) == +- PPC_INST_MFSPR_DSCR)) && ++ if (((instword & PPC_INST_MFSPR_DSCR_MASK) == PPC_INST_MFSPR_DSCR) && + cpu_has_feature(CPU_FTR_DSCR)) { + PPC_WARN_EMULATED(mfdscr, regs); + rd = (instword >> 21) & 0x1f; +@@ -976,10 +973,7 @@ static int emulate_instruction(struct pt_regs *regs) + return 0; + } + /* Emulate the mtspr DSCR, rD. */ +- if ((((instword & PPC_INST_MTSPR_DSCR_USER_MASK) == +- PPC_INST_MTSPR_DSCR_USER) || +- ((instword & PPC_INST_MTSPR_DSCR_MASK) == +- PPC_INST_MTSPR_DSCR)) && ++ if (((instword & PPC_INST_MTSPR_DSCR_MASK) == PPC_INST_MTSPR_DSCR) && + cpu_has_feature(CPU_FTR_DSCR)) { + PPC_WARN_EMULATED(mtdscr, regs); + rd = (instword >> 21) & 0x1f; +diff --git a/arch/powerpc/kernel/vdso32/sigtramp.S b/arch/powerpc/kernel/vdso32/sigtramp.S +index 78c88af..cf0c9c9 100644 +--- a/arch/powerpc/kernel/vdso32/sigtramp.S ++++ b/arch/powerpc/kernel/vdso32/sigtramp.S +@@ -251,40 +251,6 @@ V_FUNCTION_END(__kernel_sigtramp_rt32) + vsave_msr1 (31); \ + vsave_msr2 (33, 32*16+12); \ + vsave (32, 32*16) +-#elif defined(CONFIG_SPE) +-#define EH_FRAME_VMX \ +- rsave (113, VREGS); \ +- rsave (114, VREGS + 1*4); \ +- rsave (115, VREGS + 2*4); \ +- rsave (116, VREGS + 3*4); \ +- rsave (117, VREGS + 4*4); \ +- rsave (118, VREGS + 5*4); \ +- rsave (119, VREGS + 6*4); \ +- rsave (120, VREGS + 7*4); \ +- rsave (121, VREGS + 8*4); \ +- rsave (122, VREGS + 9*4); \ +- rsave (123, VREGS + 10*4); \ +- rsave (124, VREGS + 11*4); \ +- rsave (125, VREGS + 12*4); \ +- rsave (126, VREGS + 13*4); \ +- rsave (127, VREGS + 14*4); \ +- rsave (128, VREGS + 15*4); \ +- rsave (129, VREGS + 16*4); \ +- rsave (130, VREGS + 17*4); \ +- rsave (131, VREGS + 18*4); \ +- rsave (132, VREGS + 19*4); \ +- rsave (133, VREGS + 20*4); \ +- rsave (134, VREGS + 21*4); \ +- rsave (135, VREGS + 22*4); \ +- rsave (136, VREGS + 23*4); \ +- rsave (137, VREGS + 24*4); \ +- rsave (138, VREGS + 25*4); \ +- rsave (139, VREGS + 26*4); \ +- rsave (140, VREGS + 27*4); \ +- rsave (141, VREGS + 28*4); \ +- rsave (142, VREGS + 29*4); \ +- rsave (143, VREGS + 30*4); \ +- rsave (144, VREGS + 31*4); + #else + #define EH_FRAME_VMX + #endif +diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c +index 6a252c4..bba87ca 100644 +--- a/arch/powerpc/mm/numa.c ++++ b/arch/powerpc/mm/numa.c +@@ -201,7 +201,7 @@ int __node_distance(int a, int b) + int distance = LOCAL_DISTANCE; + + if (!form1_affinity) +- return ((a == b) ? LOCAL_DISTANCE : REMOTE_DISTANCE); ++ return distance; + + for (i = 0; i < distance_ref_points_depth; i++) { + if (distance_lookup_table[a][i] == distance_lookup_table[b][i]) +diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c +index eb42124..a538c80 100644 +--- a/arch/powerpc/mm/slb.c ++++ b/arch/powerpc/mm/slb.c +@@ -313,7 +313,6 @@ void slb_initialize(void) + asm volatile("isync":::"memory"); + asm volatile("slbmte %0,%0"::"r" (0) : "memory"); + asm volatile("isync; slbia; isync":::"memory"); +- mb(); + create_shadowed_slbe(PAGE_OFFSET, mmu_kernel_ssize, lflags, 0); + + create_shadowed_slbe(VMALLOC_START, mmu_kernel_ssize, vflags, 1); +diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c +index 506dc9f..dba1ce2 100644 +--- a/arch/powerpc/platforms/cell/spufs/inode.c ++++ b/arch/powerpc/platforms/cell/spufs/inode.c +@@ -99,7 +99,6 @@ spufs_new_inode(struct super_block *sb, umode_t mode) + if (!inode) + goto out; + +- inode->i_ino = get_next_ino(); + inode->i_mode = mode; + inode->i_uid = current_fsuid(); + inode->i_gid = current_fsgid(); +diff --git a/arch/x86/crypto/crc32c-pcl-intel-asm_64.S b/arch/x86/crypto/crc32c-pcl-intel-asm_64.S +index b0f7d39..93c6d39 100644 +--- a/arch/x86/crypto/crc32c-pcl-intel-asm_64.S ++++ b/arch/x86/crypto/crc32c-pcl-intel-asm_64.S +@@ -42,8 +42,6 @@ + * SOFTWARE. + */ + +-#include +- + ## ISCSI CRC 32 Implementation with crc32 and pclmulqdq Instruction + + .macro LABEL prefix n +@@ -226,10 +224,10 @@ LABEL crc_ %i + movdqa (bufp), %xmm0 # 2 consts: K1:K2 + + movq crc_init, %xmm1 # CRC for block 1 +- PCLMULQDQ 0x00,%xmm0,%xmm1 # Multiply by K2 ++ pclmulqdq $0x00,%xmm0,%xmm1 # Multiply by K2 + + movq crc1, %xmm2 # CRC for block 2 +- PCLMULQDQ 0x10, %xmm0, %xmm2 # Multiply by K1 ++ pclmulqdq $0x10, %xmm0, %xmm2 # Multiply by K1 + + pxor %xmm2,%xmm1 + movq %xmm1, %rax +diff --git a/arch/x86/kernel/cpu/perf_event_intel_lbr.c b/arch/x86/kernel/cpu/perf_event_intel_lbr.c +index d978353..da02e9c 100644 +--- a/arch/x86/kernel/cpu/perf_event_intel_lbr.c ++++ b/arch/x86/kernel/cpu/perf_event_intel_lbr.c +@@ -310,7 +310,7 @@ void intel_pmu_lbr_read(void) + * - in case there is no HW filter + * - in case the HW filter has errata or limitations + */ +-static int intel_pmu_setup_sw_lbr_filter(struct perf_event *event) ++static void intel_pmu_setup_sw_lbr_filter(struct perf_event *event) + { + u64 br_type = event->attr.branch_sample_type; + int mask = 0; +@@ -318,11 +318,8 @@ static int intel_pmu_setup_sw_lbr_filter(struct perf_event *event) + if (br_type & PERF_SAMPLE_BRANCH_USER) + mask |= X86_BR_USER; + +- if (br_type & PERF_SAMPLE_BRANCH_KERNEL) { +- if (perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN)) +- return -EACCES; ++ if (br_type & PERF_SAMPLE_BRANCH_KERNEL) + mask |= X86_BR_KERNEL; +- } + + /* we ignore BRANCH_HV here */ + +@@ -342,8 +339,6 @@ static int intel_pmu_setup_sw_lbr_filter(struct perf_event *event) + * be used by fixup code for some CPU + */ + event->hw.branch_reg.reg = mask; +- +- return 0; + } + + /* +@@ -391,9 +386,7 @@ int intel_pmu_setup_lbr_filter(struct perf_event *event) + /* + * setup SW LBR filter + */ +- ret = intel_pmu_setup_sw_lbr_filter(event); +- if (ret) +- return ret; ++ intel_pmu_setup_sw_lbr_filter(event); + + /* + * setup HW LBR filter, if any +@@ -449,18 +442,8 @@ static int branch_type(unsigned long from, unsigned long to) + return X86_BR_NONE; + + addr = buf; +- } else { +- /* +- * The LBR logs any address in the IP, even if the IP just +- * faulted. This means userspace can control the from address. +- * Ensure we don't blindy read any address by validating it is +- * a known text address. +- */ +- if (kernel_text_address(from)) +- addr = (void *)from; +- else +- return X86_BR_NONE; +- } ++ } else ++ addr = (void *)from; + + /* + * decoder needs to know the ABI especially +diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c +index 3e091f0..b43200d 100644 +--- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c ++++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c +@@ -2428,7 +2428,7 @@ static void __init uncore_types_exit(struct intel_uncore_type **types) + static int __init uncore_type_init(struct intel_uncore_type *type) + { + struct intel_uncore_pmu *pmus; +- struct attribute_group *attr_group; ++ struct attribute_group *events_group; + struct attribute **attrs; + int i, j; + +@@ -2455,19 +2455,19 @@ static int __init uncore_type_init(struct intel_uncore_type *type) + while (type->event_descs[i].attr.attr.name) + i++; + +- attr_group = kzalloc(sizeof(struct attribute *) * (i + 1) + +- sizeof(*attr_group), GFP_KERNEL); +- if (!attr_group) ++ events_group = kzalloc(sizeof(struct attribute *) * (i + 1) + ++ sizeof(*events_group), GFP_KERNEL); ++ if (!events_group) + goto fail; + +- attrs = (struct attribute **)(attr_group + 1); +- attr_group->name = "events"; +- attr_group->attrs = attrs; ++ attrs = (struct attribute **)(events_group + 1); ++ events_group->name = "events"; ++ events_group->attrs = attrs; + + for (j = 0; j < i; j++) + attrs[j] = &type->event_descs[j].attr.attr; + +- type->events_group = attr_group; ++ type->events_group = events_group; + } + + type->pmu_group = &uncore_pmu_attr_group; +@@ -2853,7 +2853,6 @@ static int __init uncore_cpu_init(void) + msr_uncores = nhm_msr_uncores; + break; + case 42: /* Sandy Bridge */ +- case 58: /* Ivy Bridge */ + if (snb_uncore_cbox.num_boxes > max_cores) + snb_uncore_cbox.num_boxes = max_cores; + msr_uncores = snb_msr_uncores; +diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c +index 66b8a6d..d22d0c4 100644 +--- a/arch/x86/kernel/cpu/vmware.c ++++ b/arch/x86/kernel/cpu/vmware.c +@@ -21,7 +21,6 @@ + * + */ + +-#include + #include + #include + #include +diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c +index 84b7789..e4595f1 100644 +--- a/arch/x86/kernel/irq.c ++++ b/arch/x86/kernel/irq.c +@@ -165,6 +165,10 @@ u64 arch_irq_stat_cpu(unsigned int cpu) + u64 arch_irq_stat(void) + { + u64 sum = atomic_read(&irq_err_count); ++ ++#ifdef CONFIG_X86_IO_APIC ++ sum += atomic_read(&irq_mis_count); ++#endif + return sum; + } + +diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c +index d330b3c..a27e763 100644 +--- a/arch/x86/kvm/emulate.c ++++ b/arch/x86/kvm/emulate.c +@@ -4030,10 +4030,6 @@ static int decode_operand(struct x86_emulate_ctxt *ctxt, struct operand *op, + break; + case OpMem8: + ctxt->memop.bytes = 1; +- if (ctxt->memop.type == OP_REG) { +- ctxt->memop.addr.reg = decode_register(ctxt, ctxt->modrm_rm, 1); +- fetch_register_operand(&ctxt->memop); +- } + goto mem_common; + case OpMem16: + ctxt->memop.bytes = 2; +diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c +index 7d7a36d..d7aea41 100644 +--- a/arch/x86/mm/init.c ++++ b/arch/x86/mm/init.c +@@ -45,15 +45,11 @@ static void __init find_early_table_space(struct map_range *mr, int nr_range) + int i; + unsigned long puds = 0, pmds = 0, ptes = 0, tables; + unsigned long start = 0, good_end; +- unsigned long pgd_extra = 0; + phys_addr_t base; + + for (i = 0; i < nr_range; i++) { + unsigned long range, extra; + +- if ((mr[i].end >> PGDIR_SHIFT) - (mr[i].start >> PGDIR_SHIFT)) +- pgd_extra++; +- + range = mr[i].end - mr[i].start; + puds += (range + PUD_SIZE - 1) >> PUD_SHIFT; + +@@ -78,7 +74,6 @@ static void __init find_early_table_space(struct map_range *mr, int nr_range) + tables = roundup(puds * sizeof(pud_t), PAGE_SIZE); + tables += roundup(pmds * sizeof(pmd_t), PAGE_SIZE); + tables += roundup(ptes * sizeof(pte_t), PAGE_SIZE); +- tables += (pgd_extra * PAGE_SIZE); + + #ifdef CONFIG_X86_32 + /* for fixmap */ +diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c +index 958a985..e2cd38f 100644 +--- a/arch/x86/platform/efi/efi.c ++++ b/arch/x86/platform/efi/efi.c +@@ -889,13 +889,10 @@ void __init efi_enter_virtual_mode(void) + + for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { + md = p; +- if (!(md->attribute & EFI_MEMORY_RUNTIME)) { +-#ifdef CONFIG_X86_64 +- if (md->type != EFI_BOOT_SERVICES_CODE && +- md->type != EFI_BOOT_SERVICES_DATA) +-#endif +- continue; +- } ++ if (!(md->attribute & EFI_MEMORY_RUNTIME) && ++ md->type != EFI_BOOT_SERVICES_CODE && ++ md->type != EFI_BOOT_SERVICES_DATA) ++ continue; + + size = md->num_pages << EFI_PAGE_SHIFT; + end = md->phys_addr + size; +diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c +index 08c6511..2262003 100644 +--- a/arch/x86/xen/enlighten.c ++++ b/arch/x86/xen/enlighten.c +@@ -1589,11 +1589,8 @@ static int __cpuinit xen_hvm_cpu_notify(struct notifier_block *self, + switch (action) { + case CPU_UP_PREPARE: + xen_vcpu_setup(cpu); +- if (xen_have_vector_callback) { ++ if (xen_have_vector_callback) + xen_init_lock_cpu(cpu); +- if (xen_feature(XENFEAT_hvm_safe_pvclock)) +- xen_setup_timer(cpu); +- } + break; + default: + break; +diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c +index 48d7b2c..34bc4ce 100644 +--- a/arch/x86/xen/smp.c ++++ b/arch/x86/xen/smp.c +@@ -658,8 +658,6 @@ static void xen_hvm_cpu_die(unsigned int cpu) + unbind_from_irqhandler(per_cpu(xen_debug_irq, cpu), NULL); + unbind_from_irqhandler(per_cpu(xen_callfuncsingle_irq, cpu), NULL); + unbind_from_irqhandler(per_cpu(xen_irq_work, cpu), NULL); +- xen_uninit_lock_cpu(cpu); +- xen_teardown_timer(cpu); + native_cpu_die(cpu); + } + +diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c +index 054cc01..0296a95 100644 +--- a/arch/x86/xen/time.c ++++ b/arch/x86/xen/time.c +@@ -497,11 +497,7 @@ static void xen_hvm_setup_cpu_clockevents(void) + { + int cpu = smp_processor_id(); + xen_setup_runstate_info(cpu); +- /* +- * xen_setup_timer(cpu) - snprintf is bad in atomic context. Hence +- * doing it xen_hvm_cpu_notify (which gets called by smp_init during +- * early bootup and also during CPU hotplug events). +- */ ++ xen_setup_timer(cpu); + xen_setup_cpu_clockevents(); + } + +diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c +index 2999966..bd22f86 100644 +--- a/drivers/acpi/osl.c ++++ b/drivers/acpi/osl.c +@@ -642,7 +642,7 @@ void __init acpi_initrd_override(void *data, size_t size) + * Both memblock_reserve and e820_add_region (via arch_reserve_mem_area) + * works fine. + */ +- memblock_reserve(acpi_tables_addr, all_tables_size); ++ memblock_reserve(acpi_tables_addr, acpi_tables_addr + all_tables_size); + arch_reserve_mem_area(acpi_tables_addr, all_tables_size); + + p = early_ioremap(acpi_tables_addr, all_tables_size); +diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c +index 77c9a92..eb73798 100644 +--- a/drivers/acpi/pci_root.c ++++ b/drivers/acpi/pci_root.c +@@ -240,8 +240,8 @@ static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, + *control &= OSC_PCI_CONTROL_MASKS; + capbuf[OSC_CONTROL_TYPE] = *control | root->osc_control_set; + } else { +- /* Run _OSC query only with existing controls. */ +- capbuf[OSC_CONTROL_TYPE] = root->osc_control_set; ++ /* Run _OSC query for all possible controls. */ ++ capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS; + } + + status = acpi_pci_run_osc(root->device->handle, capbuf, &result); +diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c +index 25246e8..506fbd4 100644 +--- a/drivers/acpi/thermal.c ++++ b/drivers/acpi/thermal.c +@@ -719,19 +719,9 @@ static int thermal_get_trend(struct thermal_zone_device *thermal, + return -EINVAL; + + if (type == THERMAL_TRIP_ACTIVE) { +- unsigned long trip_temp; +- unsigned long temp = KELVIN_TO_MILLICELSIUS(tz->temperature, +- tz->kelvin_offset); +- if (thermal_get_trip_temp(thermal, trip, &trip_temp)) +- return -EINVAL; +- +- if (temp > trip_temp) { +- *trend = THERMAL_TREND_RAISING; +- return 0; +- } else { +- /* Fall back on default trend */ +- return -EINVAL; +- } ++ /* aggressive active cooling */ ++ *trend = THERMAL_TREND_RAISING; ++ return 0; + } + + /* +diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c +index cc8aa9e..ef01ac0 100644 +--- a/drivers/ata/libata-acpi.c ++++ b/drivers/ata/libata-acpi.c +@@ -60,8 +60,7 @@ acpi_handle ata_ap_acpi_handle(struct ata_port *ap) + if (ap->flags & ATA_FLAG_ACPI_SATA) + return NULL; + +- return ap->scsi_host ? +- DEVICE_ACPI_HANDLE(&ap->scsi_host->shost_gendev) : NULL; ++ return acpi_get_child(DEVICE_ACPI_HANDLE(ap->host->dev), ap->port_no); + } + EXPORT_SYMBOL(ata_ap_acpi_handle); + +@@ -240,15 +239,28 @@ void ata_acpi_dissociate(struct ata_host *host) + } + } + +-static int __ata_acpi_gtm(struct ata_port *ap, acpi_handle handle, +- struct ata_acpi_gtm *gtm) ++/** ++ * ata_acpi_gtm - execute _GTM ++ * @ap: target ATA port ++ * @gtm: out parameter for _GTM result ++ * ++ * Evaluate _GTM and store the result in @gtm. ++ * ++ * LOCKING: ++ * EH context. ++ * ++ * RETURNS: ++ * 0 on success, -ENOENT if _GTM doesn't exist, -errno on failure. ++ */ ++int ata_acpi_gtm(struct ata_port *ap, struct ata_acpi_gtm *gtm) + { + struct acpi_buffer output = { .length = ACPI_ALLOCATE_BUFFER }; + union acpi_object *out_obj; + acpi_status status; + int rc = 0; + +- status = acpi_evaluate_object(handle, "_GTM", NULL, &output); ++ status = acpi_evaluate_object(ata_ap_acpi_handle(ap), "_GTM", NULL, ++ &output); + + rc = -ENOENT; + if (status == AE_NOT_FOUND) +@@ -282,27 +294,6 @@ static int __ata_acpi_gtm(struct ata_port *ap, acpi_handle handle, + return rc; + } + +-/** +- * ata_acpi_gtm - execute _GTM +- * @ap: target ATA port +- * @gtm: out parameter for _GTM result +- * +- * Evaluate _GTM and store the result in @gtm. +- * +- * LOCKING: +- * EH context. +- * +- * RETURNS: +- * 0 on success, -ENOENT if _GTM doesn't exist, -errno on failure. +- */ +-int ata_acpi_gtm(struct ata_port *ap, struct ata_acpi_gtm *gtm) +-{ +- if (ata_ap_acpi_handle(ap)) +- return __ata_acpi_gtm(ap, ata_ap_acpi_handle(ap), gtm); +- else +- return -EINVAL; +-} +- + EXPORT_SYMBOL_GPL(ata_acpi_gtm); + + /** +@@ -1104,7 +1095,7 @@ static int ata_acpi_bind_host(struct ata_port *ap, acpi_handle *handle) + if (!*handle) + return -ENODEV; + +- if (__ata_acpi_gtm(ap, *handle, &ap->__acpi_init_gtm) == 0) ++ if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0) + ap->pflags |= ATA_PFLAG_INIT_GTM_VALID; + + return 0; +diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c +index b1a664a..5dba77c 100644 +--- a/drivers/ata/sata_highbank.c ++++ b/drivers/ata/sata_highbank.c +@@ -251,7 +251,7 @@ static const struct ata_port_info ahci_highbank_port_info = { + }; + + static struct scsi_host_template ahci_highbank_platform_sht = { +- AHCI_SHT("sata_highbank"), ++ AHCI_SHT("highbank-ahci"), + }; + + static const struct of_device_id ahci_of_match[] = { +diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c +index ba780b7..93211df 100644 +--- a/drivers/char/tpm/tpm.c ++++ b/drivers/char/tpm/tpm.c +@@ -1291,7 +1291,7 @@ int tpm_pm_suspend(struct device *dev) + { + struct tpm_chip *chip = dev_get_drvdata(dev); + struct tpm_cmd_t cmd; +- int rc, try; ++ int rc; + + u8 dummy_hash[TPM_DIGEST_SIZE] = { 0 }; + +@@ -1309,32 +1309,9 @@ int tpm_pm_suspend(struct device *dev) + } + + /* now do the actual savestate */ +- for (try = 0; try < TPM_RETRY; try++) { +- cmd.header.in = savestate_header; +- rc = transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL); +- +- /* +- * If the TPM indicates that it is too busy to respond to +- * this command then retry before giving up. It can take +- * several seconds for this TPM to be ready. +- * +- * This can happen if the TPM has already been sent the +- * SaveState command before the driver has loaded. TCG 1.2 +- * specification states that any communication after SaveState +- * may cause the TPM to invalidate previously saved state. +- */ +- if (rc != TPM_WARN_RETRY) +- break; +- msleep(TPM_TIMEOUT_RETRY); +- } +- +- if (rc) +- dev_err(chip->dev, +- "Error (%d) sending savestate before suspend\n", rc); +- else if (try > 0) +- dev_warn(chip->dev, "TPM savestate took %dms\n", +- try * TPM_TIMEOUT_RETRY); +- ++ cmd.header.in = savestate_header; ++ rc = transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, ++ "sending savestate before suspend"); + return rc; + } + EXPORT_SYMBOL_GPL(tpm_pm_suspend); +diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h +index 9c12a52..8ef7649 100644 +--- a/drivers/char/tpm/tpm.h ++++ b/drivers/char/tpm/tpm.h +@@ -32,12 +32,10 @@ enum tpm_const { + TPM_MINOR = 224, /* officially assigned */ + TPM_BUFSIZE = 4096, + TPM_NUM_DEVICES = 256, +- TPM_RETRY = 50, /* 5 seconds */ + }; + + enum tpm_timeout { + TPM_TIMEOUT = 5, /* msecs */ +- TPM_TIMEOUT_RETRY = 100 /* msecs */ + }; + + /* TPM addresses */ +@@ -46,7 +44,6 @@ enum tpm_addr { + TPM_ADDR = 0x4E, + }; + +-#define TPM_WARN_RETRY 0x800 + #define TPM_WARN_DOING_SELFTEST 0x802 + #define TPM_ERR_DEACTIVATED 0x6 + #define TPM_ERR_DISABLED 0x7 +diff --git a/drivers/char/xilinx_devcfg.c b/drivers/char/xilinx_devcfg.c +index 4f50fff..e821d42 100644 +--- a/drivers/char/xilinx_devcfg.c ++++ b/drivers/char/xilinx_devcfg.c +@@ -125,6 +125,9 @@ struct xdevcfg_drvdata { + void __iomem *base_address; + int ep107; + bool is_partial_bitstream; ++ bool endian_swap; ++ char residue_buf[3]; ++ int residue_len; + }; + + /* Register read/write access routines */ +@@ -211,13 +214,15 @@ static ssize_t + xdevcfg_write(struct file *file, const char __user *buf, size_t count, + loff_t *ppos) + { +- u32 *kbuf; ++ char *kbuf; + int status; + unsigned long timeout; + u32 intr_reg; + dma_addr_t dma_addr; + u32 transfer_length = 0; + struct xdevcfg_drvdata *drvdata = file->private_data; ++ size_t user_count = count; ++ int i; + + status = clk_enable(drvdata->clk); + if (status) +@@ -228,16 +233,60 @@ xdevcfg_write(struct file *file, const char __user *buf, size_t count, + if (status) + goto err_clk; + +- kbuf = dma_alloc_coherent(drvdata->dev, count, &dma_addr, GFP_KERNEL); ++ kbuf = dma_alloc_coherent(drvdata->dev, count + drvdata->residue_len, ++ &dma_addr, GFP_KERNEL); + if (!kbuf) { + status = -ENOMEM; + goto err_unlock; + } + +- if (copy_from_user(kbuf, buf, count)) { ++ /* Collect stragglers from last time (0 to 3 bytes) */ ++ memcpy(kbuf, drvdata->residue_buf, drvdata->residue_len); ++ ++ /* Fetch user data, appending to stragglers */ ++ if (copy_from_user(kbuf + drvdata->residue_len, buf, count)) { + status = -EFAULT; + goto error; + } ++ ++ /* Include stragglers in total bytes to be handled */ ++ count += drvdata->residue_len; ++ ++ /* First block contains a header */ ++ if (*ppos == 0 && count > 4) { ++ /* Look for sync word */ ++ for (i = 0; i < count - 4; i++) { ++ if (memcmp(kbuf + i, "\x66\x55\x99\xAA", 4) == 0) { ++ printk("Found normal sync word\n"); ++ drvdata->endian_swap = 0; ++ break; ++ } ++ if (memcmp(kbuf + i, "\xAA\x99\x55\x66", 4) == 0) { ++ printk("Found swapped sync word\n"); ++ drvdata->endian_swap = 1; ++ break; ++ } ++ } ++ /* Remove the header, aligning the data on word boundary */ ++ if (i != count - 4) { ++ count -= i; ++ memmove(kbuf, kbuf + i, count); ++ } ++ } ++ ++ /* Save stragglers for next time */ ++ drvdata->residue_len = count % 4; ++ count -= drvdata->residue_len; ++ memcpy(drvdata->residue_buf, kbuf + count, drvdata->residue_len); ++ ++ /* Fixup endianess of the data */ ++ if (drvdata->endian_swap) { ++ for (i = 0; i < count; i += 4) { ++ u32 *p = (u32 *)&kbuf[i]; ++ *p = swab32(*p); ++ } ++ } ++ + /* Enable DMA and error interrupts */ + xdevcfg_writereg(drvdata->base_address + XDCFG_INT_STS_OFFSET, + XDCFG_IXR_ALL_MASK); +@@ -294,7 +343,8 @@ xdevcfg_write(struct file *file, const char __user *buf, size_t count, + goto error; + } + +- status = count; ++ *ppos += user_count; ++ status = user_count; + + error: + dma_free_coherent(drvdata->dev, count, kbuf, dma_addr); +@@ -429,6 +479,8 @@ static int xdevcfg_open(struct inode *inode, struct file *file) + + file->private_data = drvdata; + drvdata->is_open = 1; ++ drvdata->endian_swap = 0; ++ drvdata->residue_len= 0; + + /* + * If is_partial_bitstream is set, then PROG_B is not asserted +@@ -471,6 +523,10 @@ static int xdevcfg_release(struct inode *inode, struct file *file) + if (!drvdata->is_partial_bitstream) + xslcr_init_postload_fpga(); + ++ if (drvdata->residue_len) ++ printk("Did not transfer last %d bytes\n", ++ drvdata->residue_len); ++ + drvdata->is_open = 0; + + return 0; +@@ -1590,7 +1646,7 @@ static int xdevcfg_drv_probe(struct platform_device *pdev) + drvdata->base_address, + (unsigned long long) (regs_res->end - regs_res->start + 1)); + +- drvdata->clk = clk_get_sys("PCAP", NULL); ++ drvdata->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(drvdata->clk)) { + dev_err(&pdev->dev, "input clock not found\n"); + retval = PTR_ERR(drvdata->clk); +diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c +index a9204c6..2e29d69 100644 +--- a/drivers/clk/clk-divider.c ++++ b/drivers/clk/clk-divider.c +@@ -109,8 +109,9 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, + + div = _get_div(divider, val); + if (!div) { +- WARN(1, "%s: Invalid divisor for clock %s\n", __func__, +- __clk_get_name(hw->clk)); ++ WARN(!(divider->flags & CLK_DIVIDER_ALLOW_ZERO), ++ "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n", ++ __clk_get_name(hw->clk)); + return parent_rate; + } + +diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c +index 251e45d..72633c6 100644 +--- a/drivers/clk/clk.c ++++ b/drivers/clk/clk.c +@@ -599,8 +599,9 @@ unsigned long __clk_round_rate(struct clk *clk, unsigned long rate) + * @rate: the rate which is to be rounded + * + * Takes in a rate as input and rounds it to a rate that the clk can actually +- * use which is then returned. If clk doesn't support round_rate operation +- * then the parent rate is returned. ++ * use and does not exceed the requested frequency, which is then returned. ++ * If clk doesn't support round_rate operation then the parent rate ++ * is returned. + */ + long clk_round_rate(struct clk *clk, unsigned long rate) + { +@@ -615,6 +616,27 @@ long clk_round_rate(struct clk *clk, unsigned long rate) + EXPORT_SYMBOL_GPL(clk_round_rate); + + /** ++ * clk_round_rate_nearest - round the given rate for a clk ++ * @clk: the clk for which we are rounding a rate ++ * @rate: the rate which is to be rounded ++ * ++ * Takes in a rate as input and rounds it to the closest rate that the clk ++ * can actually use which is then returned. If clk doesn't support ++ * round_rate operation then the parent rate is returned. ++ */ ++long clk_round_rate_nearest(struct clk *clk, unsigned long rate) ++{ ++ long lower_limit = clk_round_rate(clk, rate); ++ long upper_limit = clk_round_rate(clk, rate + (rate - lower_limit)); ++ ++ if (rate - lower_limit < upper_limit - rate) ++ return lower_limit; ++ else ++ return upper_limit; ++} ++EXPORT_SYMBOL_GPL(clk_round_rate_nearest); ++ ++/** + * __clk_notify - call clk notifier chain + * @clk: struct clk * that is changing rate + * @msg: clk notifier type (see include/linux/clk.h) +@@ -744,16 +766,16 @@ static int __clk_speculate_rates(struct clk *clk, unsigned long parent_rate) + else + new_rate = parent_rate; + +- /* abort the rate change if a driver returns NOTIFY_BAD */ ++ /* abort rate change if a driver returns NOTIFY_BAD or NOTIFY_STOP */ + if (clk->notifier_count) + ret = __clk_notify(clk, PRE_RATE_CHANGE, clk->rate, new_rate); + +- if (ret == NOTIFY_BAD) ++ if (ret & NOTIFY_STOP_MASK) + goto out; + + hlist_for_each_entry(child, tmp, &clk->children, child_node) { + ret = __clk_speculate_rates(child, new_rate); +- if (ret == NOTIFY_BAD) ++ if (ret & NOTIFY_STOP_MASK) + break; + } + +@@ -848,7 +870,7 @@ static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long even + + if (clk->notifier_count) { + ret = __clk_notify(clk, event, clk->rate, clk->new_rate); +- if (ret == NOTIFY_BAD) ++ if (ret & NOTIFY_STOP_MASK) + fail_clk = clk; + } + +@@ -1166,11 +1188,10 @@ int clk_set_parent(struct clk *clk, struct clk *parent) + goto out; + + /* propagate PRE_RATE_CHANGE notifications */ +- if (clk->notifier_count) +- ret = __clk_speculate_rates(clk, parent->rate); ++ ret = __clk_speculate_rates(clk, parent->rate); + + /* abort if a driver objects */ +- if (ret == NOTIFY_STOP) ++ if (ret & NOTIFY_STOP_MASK) + goto out; + + /* only re-parent if the clock is not in use */ +diff --git a/drivers/clk/zynq/Makefile b/drivers/clk/zynq/Makefile +index 1c4763a..156d923 100644 +--- a/drivers/clk/zynq/Makefile ++++ b/drivers/clk/zynq/Makefile +@@ -1,3 +1,3 @@ + # Zynq clock specific Makefile + +-obj-$(CONFIG_ARCH_ZYNQ) += clk.o clk621.o peripheral_clk.o ++obj-$(CONFIG_ARCH_ZYNQ) += clkc.o pll.o +diff --git a/drivers/clk/zynq/clk.c b/drivers/clk/zynq/clk.c +deleted file mode 100644 +index b97d0e5..0000000 +--- a/drivers/clk/zynq/clk.c ++++ /dev/null +@@ -1,743 +0,0 @@ +-/* +- * Zynq clock initalization code +- * Code is based on clock code from the orion/kirkwood architecture. +- * +- * Copyright (C) 2012 Xilinx +- * +- * This software is licensed under the terms of the GNU General Public +- * License version 2, as published by the Free Software Foundation, and +- * may be copied, distributed, and modified under those terms. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- */ +- +-#include +-#include +-#include +-#include +-#include +- +-#define SLCR_ARM_CLK_CTRL (slcr_base + 0x120) +-#define SLCR_DDR_CLK_CTRL (slcr_base + 0x124) +-#define SLCR_DCI_CLK_CTRL (slcr_base + 0x128) +-#define SLCR_APER_CLK_CTRL (slcr_base + 0x12c) +-#define SLCR_GEM0_CLK_CTRL (slcr_base + 0x140) +-#define SLCR_GEM1_CLK_CTRL (slcr_base + 0x144) +-#define SLCR_SMC_CLK_CTRL (slcr_base + 0x148) +-#define SLCR_LQSPI_CLK_CTRL (slcr_base + 0x14c) +-#define SLCR_SDIO_CLK_CTRL (slcr_base + 0x150) +-#define SLCR_UART_CLK_CTRL (slcr_base + 0x154) +-#define SLCR_SPI_CLK_CTRL (slcr_base + 0x158) +-#define SLCR_CAN_CLK_CTRL (slcr_base + 0x15c) +-#define SLCR_DBG_CLK_CTRL (slcr_base + 0x164) +-#define SLCR_PCAP_CLK_CTRL (slcr_base + 0x168) +-#define SLCR_FPGA0_CLK_CTRL (slcr_base + 0x170) +-#define SLCR_FPGA1_CLK_CTRL (slcr_base + 0x180) +-#define SLCR_FPGA2_CLK_CTRL (slcr_base + 0x190) +-#define SLCR_FPGA3_CLK_CTRL (slcr_base + 0x1a0) +-#define SLCR_621_TRUE (slcr_base + 0x1c4) +- +-static void __iomem *zynq_slcr_base; +- +- +-/* clock implementation for Zynq PLLs */ +- +-/** +- * struct zynq_pll +- * @hw: Handle between common and hardware-specific interfaces +- * @pll_ctrl: PLL control register +- * @pll_cfg: PLL config register +- * @pll_status: PLL status register +- * @lock: Register lock +- * @lockbit: Indicates the associated PLL_LOCKED bit in the PLL status +- * register. +- * @bypassed: Indicates PLL bypass. 1 = bypassed, 0 = PLL output +- */ +-struct zynq_pll { +- struct clk_hw hw; +- void __iomem *pll_ctrl; +- void __iomem *pll_cfg; +- void __iomem *pll_status; +- spinlock_t lock; +- u32 lockbit; +- u8 bypassed; +-}; +-#define to_zynq_pll(_hw) container_of(_hw, struct zynq_pll, hw) +- +-/* Register bitfield defines */ +-#define PLLCTRL_FBDIV_MASK 0x7f000 +-#define PLLCTRL_FBDIV_SHIFT 12 +-#define PLLCTRL_BYPASS_MASK 0x10 +-#define PLLCTRL_BYPASS_SHIFT 4 +-#define PLLCTRL_BPQUAL_MASK (1 << 3) +-#define PLLCTRL_PWRDWN_MASK 2 +-#define PLLCTRL_PWRDWN_SHIFT 1 +-#define PLLCTRL_RESET_MASK 1 +-#define PLLCTRL_RESET_SHIFT 0 +-#define PLLCFG_PLLRES_MASK 0xf0 +-#define PLLCFG_PLLRES_SHIFT 4 +-#define PLLCFG_PLLCP_MASK 0xf00 +-#define PLLCFG_PLLCP_SHIFT 8 +-#define PLLCFG_LOCKCNT_MASK 0x3ff000 +-#define PLLCFG_LOCKCNT_SHIFT 12 +- +-/** +- * zynq_pll_get_params() - Get PLL parameters for given feedback divider +- * @fbdiv: Desired feedback divider +- * @rpll_cp: PLL_CP value (return value) +- * @rpll_res: PLL_RES value (return value) +- * @rlock_cnt: LOCK_CNT value (return value) +- * Returns 0 on success. +- */ +-static int zynq_pll_get_pll_params(unsigned int fbdiv, u32 *rpll_cp, +- u32 *rpll_res, u32 *rlock_cnt) +-{ +- unsigned int pll_cp; +- unsigned int pll_res; +- unsigned int lock_cnt; +- +- /* Check that fbdiv is in a valid range */ +- if ((fbdiv < 13) || (fbdiv > 66)) +- return -EINVAL; +- +- /* Set other PLL parameters according to target fbdiv */ +- if ((fbdiv >= 41) && (fbdiv <= 47)) +- pll_cp = 3; +- else +- pll_cp = 2; +- +- if (fbdiv <= 15) +- pll_res = 6; +- else if ((fbdiv >= 16) && (fbdiv <= 19)) +- pll_res = 10; +- else if ((fbdiv >= 31) && (fbdiv <= 40)) +- pll_res = 2; +- else if (fbdiv >= 48) +- pll_res = 4; +- else +- pll_res = 12; +- +- switch (fbdiv) { +- case 13: +- lock_cnt = 750; +- break; +- case 14: +- lock_cnt = 700; +- break; +- case 15: +- lock_cnt = 650; +- break; +- case 16: +- lock_cnt = 625; +- break; +- case 17: +- lock_cnt = 575; +- break; +- case 18: +- lock_cnt = 550; +- break; +- case 19: +- lock_cnt = 525; +- break; +- case 20: +- lock_cnt = 500; +- break; +- case 21: +- lock_cnt = 475; +- break; +- case 22: +- lock_cnt = 450; +- break; +- case 23: +- lock_cnt = 425; +- break; +- case 24 ... 25: +- lock_cnt = 400; +- break; +- case 26: +- lock_cnt = 375; +- break; +- case 27 ... 28: +- lock_cnt = 350; +- break; +- case 29 ... 30: +- lock_cnt = 325; +- break; +- case 31 ... 33: +- lock_cnt = 300; +- break; +- case 34 ... 36: +- lock_cnt = 275; +- break; +- default: +- lock_cnt = 250; +- break; +- } +- +- *rpll_cp = pll_cp; +- *rpll_res = pll_res; +- *rlock_cnt = lock_cnt; +- return 0; +-} +- +-/** +- * zynq_pll_set_rate() - Change frequency of a PLL +- * @hw: Handle between common and hardware-specific interfaces +- * @rate: Desired clock frequency +- * @prate: Clock frequency of parent clock +- * Returns 0 on success, negative errno otherwise. +- */ +-static int zynq_pll_set_rate(struct clk_hw *hw, unsigned long rate, +- unsigned long prate) +-{ +- struct zynq_pll *clk = to_zynq_pll(hw); +- u32 reg, fbdiv, pll_res, pll_cp, lock_cnt; +- unsigned long flags; +- +- /* +- * Set a new rate to the PLL includes bypassing and resetting the PLL, +- * hence the connected subsystem will see old_f->bypass_f->new_f. Every +- * driver must register clock notifiers for its clock to make sure it is +- * asked for rate changes. This way it can make sure it can work with +- * new_f and do whatever is necessary to continue working after such a +- * change. +- */ +- /* Rate change is only possible if not bypassed */ +- if (clk->bypassed) +- return -EINVAL; +- +- fbdiv = DIV_ROUND_CLOSEST(rate, prate); +- if (zynq_pll_get_pll_params(fbdiv, &pll_cp, &pll_res, &lock_cnt)) +- return -EINVAL; +- +- spin_lock_irqsave(&clk->lock, flags); +- +- /* Write new parameters */ +- reg = readl(clk->pll_ctrl); +- reg &= ~PLLCTRL_FBDIV_MASK; +- reg |= (fbdiv << PLLCTRL_FBDIV_SHIFT) & PLLCTRL_FBDIV_MASK; +- writel(reg, clk->pll_ctrl); +- +- reg = (pll_res << PLLCFG_PLLRES_SHIFT) & PLLCFG_PLLRES_MASK; +- reg |= (pll_cp << PLLCFG_PLLCP_SHIFT) & PLLCFG_PLLCP_MASK; +- reg |= (lock_cnt << PLLCFG_LOCKCNT_SHIFT) & PLLCFG_LOCKCNT_MASK; +- writel(reg, clk->pll_cfg); +- +- /* bypass PLL */ +- reg = readl(clk->pll_ctrl); +- reg |= PLLCTRL_BYPASS_MASK; +- writel(reg, clk->pll_ctrl); +- /* reset PLL */ +- reg |= PLLCTRL_RESET_MASK; +- writel(reg, clk->pll_ctrl); +- reg &= ~PLLCTRL_RESET_MASK; +- writel(reg, clk->pll_ctrl); +- /* wait for PLL lock */ +- while (readl(clk->pll_status) & (1 << clk->lockbit)) ; +- /* remove bypass */ +- reg &= ~PLLCTRL_BYPASS_MASK; +- writel(reg, clk->pll_ctrl); +- +- spin_unlock_irqrestore(&clk->lock, flags); +- +- return 0; +-} +- +-/** +- * zynq_pll_round_rate() - Round a clock frequency +- * @hw: Handle between common and hardware-specific interfaces +- * @rate: Desired clock frequency +- * @prate: Clock frequency of parent clock +- * Returns frequency closest to @rate the hardware can generate. +- */ +-static long zynq_pll_round_rate(struct clk_hw *hw, unsigned long rate, +- unsigned long *prate) +-{ +- struct zynq_pll *clk = to_zynq_pll(hw); +- u32 fbdiv; +- +- if (clk->bypassed) +- return *prate; +- +- fbdiv = DIV_ROUND_CLOSEST(rate, *prate); +- if (fbdiv < 13) +- fbdiv = 13; +- else if (fbdiv > 66) +- fbdiv = 66; +- +- return *prate * fbdiv; +-} +- +-/** +- * zynq_pll_recalc_rate() - Recalculate clock frequency +- * @hw: Handle between common and hardware-specific interfaces +- * @parent_rate: Clock frequency of parent clock +- * Returns current clock frequency. +- */ +-static unsigned long zynq_pll_recalc_rate(struct clk_hw *hw, unsigned long +- parent_rate) +-{ +- struct zynq_pll *clk = to_zynq_pll(hw); +- u32 fbdiv; +- +- if (clk->bypassed) +- return parent_rate; +- +- /* makes probably sense to redundantly save fbdiv in the struct +- * zynq_pll to save the IO access. */ +- fbdiv = (readl(clk->pll_ctrl) & PLLCTRL_FBDIV_MASK) >> +- PLLCTRL_FBDIV_SHIFT; +- +- return parent_rate * fbdiv; +-} +- +-/** +- * zynq_pll_enable - Enable clock +- * @hw: Handle between common and hardware-specific interfaces +- * Returns 0 on success +- */ +-static int zynq_pll_enable(struct clk_hw *hw) +-{ +- unsigned long flags = 0; +- u32 reg; +- struct zynq_pll *clk = to_zynq_pll(hw); +- +- if (!clk->bypassed) +- return 0; +- +- pr_info("PLL: Enable\n"); +- +- /* Power up PLL and wait for lock before removing bypass */ +- spin_lock_irqsave(&clk->lock, flags); +- +- reg = readl(clk->pll_ctrl); +- reg &= ~(PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK); +- writel(reg, clk->pll_ctrl); +- while (readl(clk->pll_status) & (1 << clk->lockbit)) +- ; +- +- reg = readl(clk->pll_ctrl); +- reg &= ~PLLCTRL_BYPASS_MASK; +- writel(reg, clk->pll_ctrl); +- +- spin_unlock_irqrestore(&clk->lock, flags); +- +- clk->bypassed = 0; +- +- return 0; +-} +- +-/** +- * zynq_pll_disable - Disable clock +- * @hw: Handle between common and hardware-specific interfaces +- * Returns 0 on success +- */ +-static void zynq_pll_disable(struct clk_hw *hw) +-{ +- unsigned long flags = 0; +- u32 reg; +- struct zynq_pll *clk = to_zynq_pll(hw); +- +- if (clk->bypassed) +- return; +- +- pr_info("PLL: Bypass\n"); +- +- /* Set bypass bit and shut down PLL */ +- spin_lock_irqsave(&clk->lock, flags); +- +- reg = readl(clk->pll_ctrl); +- reg |= PLLCTRL_BYPASS_MASK; +- writel(reg, clk->pll_ctrl); +- reg |= PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK; +- writel(reg, clk->pll_ctrl); +- +- spin_unlock_irqrestore(&clk->lock, flags); +- +- clk->bypassed = 1; +-} +- +-/** +- * zynq_pll_is_enabled - Check if a clock is enabled +- * @hw: Handle between common and hardware-specific interfaces +- * Returns 1 if the clock is enabled, 0 otherwise. +- * +- * Not sure this is a good idea, but since disabled means bypassed for +- * this clock implementation we say we are always enabled. +- */ +-static int zynq_pll_is_enabled(struct clk_hw *hw) +-{ +- return 1; +-} +- +-static const struct clk_ops zynq_pll_ops = { +- .enable = zynq_pll_enable, +- .disable = zynq_pll_disable, +- .is_enabled = zynq_pll_is_enabled, +- .set_rate = zynq_pll_set_rate, +- .round_rate = zynq_pll_round_rate, +- .recalc_rate = zynq_pll_recalc_rate +-}; +- +-/** +- * clk_register_zynq_pll() - Register PLL with the clock framework +- * @np Pointer to the DT device node +- */ +-static void clk_register_zynq_pll(struct device_node *np) +-{ +- struct zynq_pll *pll; +- struct clk *clk; +- int ret; +- u32 reg; +- u32 regs[3]; +- const char *parent_name; +- unsigned long flags = 0; +- struct clk_init_data initd = { +- .ops = &zynq_pll_ops, +- .num_parents = 1, +- .flags = 0 +- }; +- +- ret = of_property_read_u32_array(np, "reg", regs, ARRAY_SIZE(regs)); +- if (WARN_ON(ret)) +- return; +- +- if (of_property_read_string(np, "clock-output-names", &initd.name)) +- initd.name = np->name; +- +- parent_name = of_clk_get_parent_name(np, 0); +- initd.parent_names = &parent_name; +- +- pll = kmalloc(sizeof(*pll), GFP_KERNEL); +- if (!pll) { +- pr_err("%s: Could not allocate Zynq PLL clk.\n", __func__); +- return; +- } +- +- /* Populate the struct */ +- pll->hw.init = &initd; +- pll->pll_ctrl = zynq_slcr_base + regs[0]; +- pll->pll_cfg = zynq_slcr_base + regs[1]; +- pll->pll_status = zynq_slcr_base + regs[2]; +- spin_lock_init(&pll->lock); +- ret = of_property_read_u32(np, "lockbit", &pll->lockbit); +- if (WARN_ON(ret)) +- goto free_pll; +- +- +- if (readl(pll->pll_ctrl) & PLLCTRL_BYPASS_MASK) +- pll->bypassed = 1; +- else +- pll->bypassed = 0; +- +- spin_lock_irqsave(&pll->lock, flags); +- +- reg = readl(pll->pll_ctrl); +- reg &= ~PLLCTRL_BPQUAL_MASK; +- writel(reg, pll->pll_ctrl); +- +- spin_unlock_irqrestore(&pll->lock, flags); +- +- clk = clk_register(NULL, &pll->hw); +- if (WARN_ON(IS_ERR(clk))) +- goto free_pll; +- +- WARN_ON(of_clk_add_provider(np, of_clk_src_simple_get, clk)); +- /* +- * at least until all clock lookups and init is converted to DT add a +- * clkdev to help clk lookups +- */ +- clk_register_clkdev(clk, NULL, initd.name); +- +- return; +- +-free_pll: +- kfree(pll); +-} +- +- +-static DEFINE_SPINLOCK(armclk_lock); +-static DEFINE_SPINLOCK(ddrclk_lock); +-static DEFINE_SPINLOCK(dciclk_lock); +-static DEFINE_SPINLOCK(pcapclk_lock); +-static DEFINE_SPINLOCK(smcclk_lock); +-static DEFINE_SPINLOCK(lqspiclk_lock); +-static DEFINE_SPINLOCK(gem0clk_lock); +-static DEFINE_SPINLOCK(gem1clk_lock); +-static DEFINE_SPINLOCK(fpga0clk_lock); +-static DEFINE_SPINLOCK(fpga1clk_lock); +-static DEFINE_SPINLOCK(fpga2clk_lock); +-static DEFINE_SPINLOCK(fpga3clk_lock); +-static DEFINE_SPINLOCK(canclk_lock); +-static DEFINE_SPINLOCK(sdioclk_lock); +-static DEFINE_SPINLOCK(uartclk_lock); +-static DEFINE_SPINLOCK(spiclk_lock); +-static DEFINE_SPINLOCK(dbgclk_lock); +-static DEFINE_SPINLOCK(aperclk_lock); +- +- +-/* Clock parent arrays */ +-static const char *cpu_parents[] __initdata = {"armpll", "armpll", +- "ddrpll", "iopll"}; +-static const char *def_periph_parents[] __initdata = {"iopll", "iopll", +- "armpll", "ddrpll"}; +-static const char *gem_parents[] __initdata = {"iopll", "iopll", "armpll", +- "ddrpll", "GEM0EMIO", "GEM0EMIO", "GEM0EMIO", "GEM0EMIO"}; +-static const char *dbg_parents[] __initdata = {"iopll", "iopll", "armpll", +- "ddrpll", "DBGEMIOTRC", "DBGEMIOTRC", "DBGEMIOTRC", "DBGEMIOTRC"}; +-static const char *dci_parents[] __initdata = {"ddrpll"}; +-static const char *clk621_parents[] __initdata = {"CPU_MASTER_CLK"}; +- +-/** +- * zynq_clkdev_add() - Add a clock device +- * @con_id: Connection identifier +- * @dev_id: Device identifier +- * @clk: Struct clock to associate with given connection and device. +- * +- * Create a clkdev entry for a given device/clk +- */ +-static void __init zynq_clkdev_add(const char *con_id, const char *dev_id, +- struct clk *clk) +-{ +- if (clk_register_clkdev(clk, con_id, dev_id)) +- pr_warn("Adding clkdev failed."); +-} +- +-static const struct of_device_id clk_match[] __initconst = { +- { .compatible = "fixed-clock", .data = of_fixed_clk_setup, }, +- { .compatible = "xlnx,zynq-pll", .data = clk_register_zynq_pll, }, +- {} +-}; +- +-/** +- * zynq_clock_init() - Clock initalization +- * +- * Register clocks and clock devices with the common clock framework. +- * To avoid enabling unused clocks, only leaf clocks are present for which the +- * drivers supports the common clock framework. +- */ +-void __init zynq_clock_init(void __iomem *slcr_base) +-{ +- struct clk *clk; +- +- pr_info("Zynq clock init\n"); +- +- zynq_slcr_base = slcr_base; +- of_clk_init(clk_match); +- +- /* CPU clocks */ +- clk = clk_register_zynq_d1m("CPU_MASTER_CLK", SLCR_ARM_CLK_CTRL, +- cpu_parents, 4, &armclk_lock); +- clk = clk_register_gate(NULL, "CPU_6OR4X_CLK", "CPU_MASTER_CLK", +- CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, +- SLCR_ARM_CLK_CTRL, 24, 0, &armclk_lock); +- zynq_clkdev_add(NULL, "CPU_6OR4X_CLK", clk); +- clk_prepare(clk); +- clk_enable(clk); +- clk = clk_register_fixed_factor(NULL, "CPU_3OR2X_DIV_CLK", +- "CPU_MASTER_CLK", 0, 1, 2); +- clk = clk_register_gate(NULL, "CPU_3OR2X_CLK", "CPU_3OR2X_DIV_CLK", +- CLK_IGNORE_UNUSED, SLCR_ARM_CLK_CTRL, 25, 0, +- &armclk_lock); +- zynq_clkdev_add(NULL, "smp_twd", clk); +- clk_prepare(clk); +- clk_enable(clk); +- clk = clk_register_zynq_clk621("CPU_1X_DIV_CLK", SLCR_ARM_CLK_CTRL, +- SLCR_621_TRUE, 4, 2, clk621_parents, 1, &armclk_lock); +- clk = clk_register_zynq_clk621("CPU_2X_DIV_CLK", SLCR_ARM_CLK_CTRL, +- SLCR_621_TRUE, 2, 1, clk621_parents, 1, &armclk_lock); +- clk = clk_register_gate(NULL, "CPU_2X_CLK", "CPU_2X_DIV_CLK", +- CLK_IGNORE_UNUSED, SLCR_ARM_CLK_CTRL, 26, 0, +- &armclk_lock); +- clk_prepare(clk); +- clk_enable(clk); +- clk = clk_register_gate(NULL, "CPU_1X_CLK", "CPU_1X_DIV_CLK", +- CLK_IGNORE_UNUSED, SLCR_ARM_CLK_CTRL, 27, 0, +- &armclk_lock); +- zynq_clkdev_add(NULL, "CPU_1X_CLK", clk); +- clk_register_clkdev(clk, "apb_pclk", NULL); +- clk_prepare(clk); +- clk_enable(clk); +- /* DDR clocks */ +- clk = clk_register_divider(NULL, "DDR_2X_DIV_CLK", "ddrpll", 0, +- SLCR_DDR_CLK_CTRL, 26, 6, CLK_DIVIDER_ONE_BASED, +- &ddrclk_lock); +- clk = clk_register_gate(NULL, "DDR_2X_CLK", "DDR_2X_DIV_CLK", 0, +- SLCR_DDR_CLK_CTRL, 1, 0, &ddrclk_lock); +- clk_prepare(clk); +- clk_enable(clk); +- clk = clk_register_divider(NULL, "DDR_3X_DIV_CLK", "ddrpll", 0, +- SLCR_DDR_CLK_CTRL, 20, 6, CLK_DIVIDER_ONE_BASED, +- &ddrclk_lock); +- clk = clk_register_gate(NULL, "DDR_3X_CLK", "DDR_3X_DIV_CLK", 0, +- SLCR_DDR_CLK_CTRL, 0, 0, &ddrclk_lock); +- clk_prepare(clk); +- clk_enable(clk); +- clk = clk_register_zynq_gd2m("DCI_CLK", SLCR_DCI_CLK_CTRL, dci_parents, +- 1, &dciclk_lock); +- clk_prepare(clk); +- clk_enable(clk); +- +- /* Peripheral clocks */ +- clk = clk_register_zynq_gd1m("LQSPI_CLK", SLCR_LQSPI_CLK_CTRL, +- def_periph_parents, &lqspiclk_lock); +- zynq_clkdev_add(NULL, "LQSPI", clk); +- +- clk = clk_register_zynq_gd1m("SMC_CLK", SLCR_SMC_CLK_CTRL, +- def_periph_parents, &smcclk_lock); +- zynq_clkdev_add(NULL, "SMC", clk); +- +- clk = clk_register_zynq_gd1m("PCAP_CLK", SLCR_PCAP_CLK_CTRL, +- def_periph_parents, &pcapclk_lock); +- zynq_clkdev_add(NULL, "PCAP", clk); +- +- clk = clk_register_zynq_gd2m("GEM0_CLK", SLCR_GEM0_CLK_CTRL, +- gem_parents, 8, &gem0clk_lock); +- zynq_clkdev_add(NULL, "GEM0", clk); +- clk = clk_register_zynq_gd2m("GEM1_CLK", SLCR_GEM1_CLK_CTRL, +- gem_parents, 8, &gem1clk_lock); +- zynq_clkdev_add(NULL, "GEM1", clk); +- +- clk = clk_register_zynq_d2m("FPGA0_CLK", SLCR_FPGA0_CLK_CTRL, +- def_periph_parents, &fpga0clk_lock); +- clk_prepare(clk); +- clk_enable(clk); +- zynq_clkdev_add(NULL, "FPGA0", clk); +- clk = clk_register_zynq_d2m("FPGA1_CLK", SLCR_FPGA1_CLK_CTRL, +- def_periph_parents, &fpga1clk_lock); +- clk_prepare(clk); +- clk_enable(clk); +- zynq_clkdev_add(NULL, "FPGA1", clk); +- clk = clk_register_zynq_d2m("FPGA2_CLK", SLCR_FPGA2_CLK_CTRL, +- def_periph_parents, &fpga2clk_lock); +- clk_prepare(clk); +- clk_enable(clk); +- zynq_clkdev_add(NULL, "FPGA2", clk); +- clk = clk_register_zynq_d2m("FPGA3_CLK", SLCR_FPGA3_CLK_CTRL, +- def_periph_parents, &fpga3clk_lock); +- clk_prepare(clk); +- clk_enable(clk); +- zynq_clkdev_add(NULL, "FPGA3", clk); +- clk = clk_register_zynq_d2m("CAN_MASTER_CLK", SLCR_CAN_CLK_CTRL, +- def_periph_parents, &canclk_lock); +- +- clk = clk_register_zynq_d1m("SDIO_MASTER_CLK", SLCR_SDIO_CLK_CTRL, +- def_periph_parents, 4, &sdioclk_lock); +- clk = clk_register_zynq_d1m("UART_MASTER_CLK", SLCR_UART_CLK_CTRL, +- def_periph_parents, 4, &uartclk_lock); +- clk = clk_register_zynq_d1m("SPI_MASTER_CLK", SLCR_SPI_CLK_CTRL, +- def_periph_parents, 4, &spiclk_lock); +- clk = clk_register_zynq_d1m("DBG_MASTER_CLK", SLCR_DBG_CLK_CTRL, +- dbg_parents, 8, &dbgclk_lock); +- +- /* +- * clk = clk_register_gate(NULL, "CAN0_CLK", "CAN_MASTER_CLK", +- * CLK_SET_RATE_PARENT, SLCR_CAN_CLK_CTRL, +- * 0, 0, &canclk_lock); +- * zynq_clkdev_add(NULL, "CAN0", clk); +- * clk = clk_register_gate(NULL, "CAN1_CLK", "CAN_MASTER_CLK", +- * CLK_SET_RATE_PARENT, SLCR_CAN_CLK_CTRL, +- * 1, 0, &canclk_lock); +- * zynq_clkdev_add(NULL, "CAN1", clk); +- */ +- +- clk = clk_register_gate(NULL, "SDIO0_CLK", "SDIO_MASTER_CLK", +- CLK_SET_RATE_PARENT, SLCR_SDIO_CLK_CTRL, 0, 0, +- &sdioclk_lock); +- zynq_clkdev_add(NULL, "SDIO0", clk); +- clk = clk_register_gate(NULL, "SDIO1_CLK", "SDIO_MASTER_CLK", +- CLK_SET_RATE_PARENT, SLCR_SDIO_CLK_CTRL, 1, 0, +- &sdioclk_lock); +- zynq_clkdev_add(NULL, "SDIO1", clk); +- +- clk = clk_register_gate(NULL, "UART0_CLK", "UART_MASTER_CLK", +- CLK_SET_RATE_PARENT, SLCR_UART_CLK_CTRL, 0, 0, +- &uartclk_lock); +- zynq_clkdev_add(NULL, "UART0", clk); +- clk = clk_register_gate(NULL, "UART1_CLK", "UART_MASTER_CLK", +- CLK_SET_RATE_PARENT, SLCR_UART_CLK_CTRL, 1, 0, +- &uartclk_lock); +- zynq_clkdev_add(NULL, "UART1", clk); +- +- clk = clk_register_gate(NULL, "SPI0_CLK", "SPI_MASTER_CLK", +- CLK_SET_RATE_PARENT, SLCR_SPI_CLK_CTRL, 0, 0, +- &spiclk_lock); +- zynq_clkdev_add(NULL, "SPI0", clk); +- clk = clk_register_gate(NULL, "SPI1_CLK", "SPI_MASTER_CLK", +- CLK_SET_RATE_PARENT, SLCR_SPI_CLK_CTRL, 1, 0, +- &spiclk_lock); +- zynq_clkdev_add(NULL, "SPI1", clk); +- /* +- * clk = clk_register_gate(NULL, "DBGTRC_CLK", "DBG_MASTER_CLK", +- * CLK_SET_RATE_PARENT, SLCR_DBG_CLK_CTRL, 0, 0, +- * &dbgclk_lock); +- * zynq_clkdev_add(NULL, "DBGTRC", clk); +- * clk = clk_register_gate(NULL, "DBG1X_CLK", "DBG_MASTER_CLK", +- * CLK_SET_RATE_PARENT, SLCR_DBG_CLK_CTRL, 1, 0, +- * &dbgclk_lock); +- * zynq_clkdev_add(NULL, "DBG1X", clk); +- */ +- +- /* One gated clock for all APER clocks. */ +- /* +- * clk = clk_register_gate(NULL, "DMA_CPU2X", "CPU_2X_CLK", 0, +- * SLCR_APER_CLK_CTRL, 0, 0, &aperclk_lock); +- * zynq_clkdev_add(NULL, "DMA_APER", clk); +- */ +- clk = clk_register_gate(NULL, "USB0_CPU1X", "CPU_1X_CLK", 0, +- SLCR_APER_CLK_CTRL, 2, 0, &aperclk_lock); +- zynq_clkdev_add(NULL, "USB0_APER", clk); +- clk = clk_register_gate(NULL, "USB1_CPU1X", "CPU_1X_CLK", 0, +- SLCR_APER_CLK_CTRL, 3, 0, &aperclk_lock); +- zynq_clkdev_add(NULL, "USB1_APER", clk); +- clk = clk_register_gate(NULL, "GEM0_CPU1X", "CPU_1X_CLK", 0, +- SLCR_APER_CLK_CTRL, 6, 0, &aperclk_lock); +- zynq_clkdev_add(NULL, "GEM0_APER", clk); +- clk = clk_register_gate(NULL, "GEM1_CPU1X", "CPU_1X_CLK", 0, +- SLCR_APER_CLK_CTRL, 7, 0, &aperclk_lock); +- zynq_clkdev_add(NULL, "GEM1_APER", clk); +- clk = clk_register_gate(NULL, "SDI0_CPU1X", "CPU_1X_CLK", 0, +- SLCR_APER_CLK_CTRL, 10, 0, &aperclk_lock); +- zynq_clkdev_add(NULL, "SDIO0_APER", clk); +- clk = clk_register_gate(NULL, "SDI1_CPU1X", "CPU_1X_CLK", 0, +- SLCR_APER_CLK_CTRL, 11, 0, &aperclk_lock); +- zynq_clkdev_add(NULL, "SDIO1_APER", clk); +- clk = clk_register_gate(NULL, "SPI0_CPU1X", "CPU_1X_CLK", 0, +- SLCR_APER_CLK_CTRL, 14, 0, &aperclk_lock); +- zynq_clkdev_add(NULL, "SPI0_APER", clk); +- clk = clk_register_gate(NULL, "SPI1_CPU1X", "CPU_1X_CLK", 0, +- SLCR_APER_CLK_CTRL, 15, 0, &aperclk_lock); +- zynq_clkdev_add(NULL, "SPI1_APER", clk); +- /* +- * clk = clk_register_gate(NULL, "CAN0_CPU1X", "CPU_1X_CLK", 0, +- * SLCR_APER_CLK_CTRL, 16, 0, &aperclk_lock); +- * zynq_clkdev_add(NULL, "CAN0_APER", clk); +- * clk = clk_register_gate(NULL, "CAN1_CPU1X", "CPU_1X_CLK", 0, +- * SLCR_APER_CLK_CTRL, 17, 0, &aperclk_lock); +- * zynq_clkdev_add(NULL, "CAN1_APER", clk); +- */ +- clk = clk_register_gate(NULL, "I2C0_CPU1X", "CPU_1X_CLK", 0, +- SLCR_APER_CLK_CTRL, 18, 0, &aperclk_lock); +- zynq_clkdev_add(NULL, "I2C0_APER", clk); +- clk = clk_register_gate(NULL, "I2C1_CPU1X", "CPU_1X_CLK", 0, +- SLCR_APER_CLK_CTRL, 19, 0, &aperclk_lock); +- zynq_clkdev_add(NULL, "I2C1_APER", clk); +- clk = clk_register_gate(NULL, "UART0_CPU1X", "CPU_1X_CLK", 0, +- SLCR_APER_CLK_CTRL, 20, 0, &aperclk_lock); +- zynq_clkdev_add(NULL, "UART0_APER", clk); +- clk = clk_register_gate(NULL, "UART1_CPU1X", "CPU_1X_CLK", 0, +- SLCR_APER_CLK_CTRL, 21, 0, &aperclk_lock); +- zynq_clkdev_add(NULL, "UART1_APER", clk); +- clk = clk_register_gate(NULL, "GPIO_CPU1X", "CPU_1X_CLK", 0, +- SLCR_APER_CLK_CTRL, 22, 0, &aperclk_lock); +- zynq_clkdev_add(NULL, "GPIO_APER", clk); +- clk = clk_register_gate(NULL, "LQSPI_CPU1X", "CPU_1X_CLK", 0, +- SLCR_APER_CLK_CTRL, 23, 0, &aperclk_lock); +- zynq_clkdev_add(NULL, "LQSPI_APER", clk); +- clk = clk_register_gate(NULL, "SMC_CPU1X", "CPU_1X_CLK", 0, +- SLCR_APER_CLK_CTRL, 24, 0, &aperclk_lock); +- zynq_clkdev_add(NULL, "SMC_APER", clk); +-} +diff --git a/drivers/clk/zynq/clk621.c b/drivers/clk/zynq/clk621.c +deleted file mode 100644 +index dcf3918..0000000 +--- a/drivers/clk/zynq/clk621.c ++++ /dev/null +@@ -1,171 +0,0 @@ +-/* +- * A try to model the Zynq CPU_1X and CPU_2X clocks. These clocks depend on the +- * setting in the clk621_true register. They have the same clock parent +- * (CPU_MASTER_CLK/CPU_6OR4X) but a common 'divider'. +- * +- * Copyright (C) 2012 Xilinx +- * +- * This software is licensed under the terms of the GNU General Public +- * License version 2, as published by the Free Software Foundation, and +- * may be copied, distributed, and modified under those terms. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +- +-/** +- * struct zynq_clk621 +- * @hw: Handle between common and hardware-specific interfaces +- * @clkctrl: Pointer to clock control register +- * @clk621: Pointer to CLK_621_TRUE register +- * @basediv: Base clock divider +- * @divadd: Clock divider increment for 621 mode +- * @lock: Register lock +- */ +-struct zynq_clk621 { +- struct clk_hw hw; +- void __iomem *clkctrl; +- void __iomem *clk621; +- unsigned int basediv; +- unsigned int divadd; +- spinlock_t *lock; +-}; +-#define to_zynq_clk621(_hw) container_of(_hw,\ +- struct zynq_clk621, hw); +-#define CLK621_MASK 1 +-#define CLK621_SHIFT 0 +- +-/** +- * zynq_clk621_round_rate() - Round a clock frequency +- * @hw: Handle between common and hardware-specific interfaces +- * @rate: Desired clock frequency +- * @prate: Clock frequency of parent clock +- * Returns frequency closest to @rate the hardware can generate. +- */ +-static long zynq_clk621_round_rate(struct clk_hw *hw, unsigned long rate, +- unsigned long *prate) +-{ +- unsigned long rerror1; +- unsigned long rerror2; +- long rate1; +- long rate2; +- struct zynq_clk621 *clk = to_zynq_clk621(hw); +- +- rate1 = *prate / clk->basediv; +- rate2 = *prate / (clk->basediv + clk->divadd); +- +- if (rate1 > rate) +- rerror1 = rate1 - rate; +- else +- rerror1 = rate - rate1; +- if (rate2 > rate) +- rerror2 = rate2 - rate; +- else +- rerror2 = rate - rate1; +- if (rerror1 > rerror2) +- return rate2; +- else +- return rate1; +-} +- +-/** +- * zynq_clk621_recalc_rate() - Recalculate clock frequency +- * @hw: Handle between common and hardware-specific interfaces +- * @parent_rate: Clock frequency of parent clock +- * Returns current clock frequency. +- */ +-static unsigned long zynq_clk621_recalc_rate(struct clk_hw *hw, +- unsigned long parent_rate) +-{ +- unsigned int div; +- struct zynq_clk621 *clk = to_zynq_clk621(hw); +- +- div = clk->basediv; +- +- if ((readl(clk->clk621) & CLK621_MASK) >> CLK621_SHIFT) +- div += clk->divadd; +- return parent_rate / div; +-} +- +- +-/** +- * zynq_clk621_set_rate() - Change clock frequncy +- * @hw: Handle between common and hardware-specific interfaces +- * @rate: Desired clock frequency +- * @prate: Clock frequency of parent clock +- * Returns 0 on success, negative errno otherwise. +- * +- * I doubt we can safely set a new rate. Changing the rate of one of these +- * clocks will also affect the other. We cannot model this kind of dependency on +- * the same hierarchical level +- */ +-static int zynq_clk621_set_rate(struct clk_hw *hw, unsigned long rate, +- unsigned long prate) +-{ +- return -EINVAL; +-} +- +-static const struct clk_ops zynq_clk621_ops = { +- .set_rate = zynq_clk621_set_rate, +- .round_rate = zynq_clk621_round_rate, +- .recalc_rate = zynq_clk621_recalc_rate +-}; +- +-/** +- * clk_register_zynq_clk621() - Register a clk621 with the clock framework +- * @name: Clock name +- * @clkctrl: Pointer to clock control register +- * @clk621: Pointer to CLK_621_TRUE register +- * @basediv: Base clock divider +- * @divadd: Clock divider increment for 621 mode +- * @pnames: Array of names of clock parents +- * @num_parents:Number of parents +- * @lock: Register lock +- * Returns clk_register() return value or errpointer. +- */ +-struct clk *clk_register_zynq_clk621(const char *name, +- void __iomem *clkctrl, void __iomem *clk621, +- unsigned int basediv, +- unsigned int divadd, const char **pnames, u8 num_parents, +- spinlock_t *lock) +-{ +- struct clk *ret; +- struct zynq_clk621 *clk; +- struct clk_init_data initd = { +- .name = name, +- .ops = &zynq_clk621_ops, +- .parent_names = pnames, +- .num_parents = num_parents, +- .flags = 0 +- }; +- +- clk = kmalloc(sizeof(*clk), GFP_KERNEL); +- if (!clk) { +- pr_err("%s: could not allocate Zynq clk\n", __func__); +- return ERR_PTR(-ENOMEM); +- } +- +- /* Populate the struct */ +- clk->hw.init = &initd; +- clk->clkctrl = clkctrl; +- clk->clk621 = clk621; +- clk->basediv = basediv; +- clk->divadd = divadd; +- clk->lock = lock; +- +- ret = clk_register(NULL, &clk->hw); +- +- if (IS_ERR(ret)) +- kfree(clk); +- +- return ret; +-} +diff --git a/drivers/clk/zynq/clkc.c b/drivers/clk/zynq/clkc.c +new file mode 100644 +index 0000000..b4f8a51 +--- /dev/null ++++ b/drivers/clk/zynq/clkc.c +@@ -0,0 +1,590 @@ ++/* ++ * Zynq clock controller ++ * ++ * Copyright (C) 2012 - 2013 Xilinx ++ * ++ * Sören Brinkmann ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License v2 as published by ++ * the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void __iomem *zynq_slcr_base_priv; ++ ++#define SLCR_ARMPLL_CTRL (zynq_slcr_base_priv + 0x100) ++#define SLCR_DDRPLL_CTRL (zynq_slcr_base_priv + 0x104) ++#define SLCR_IOPLL_CTRL (zynq_slcr_base_priv + 0x108) ++#define SLCR_PLL_STATUS (zynq_slcr_base_priv + 0x10c) ++#define SLCR_ARM_CLK_CTRL (zynq_slcr_base_priv + 0x120) ++#define SLCR_DDR_CLK_CTRL (zynq_slcr_base_priv + 0x124) ++#define SLCR_DCI_CLK_CTRL (zynq_slcr_base_priv + 0x128) ++#define SLCR_APER_CLK_CTRL (zynq_slcr_base_priv + 0x12c) ++#define SLCR_GEM0_CLK_CTRL (zynq_slcr_base_priv + 0x140) ++#define SLCR_GEM1_CLK_CTRL (zynq_slcr_base_priv + 0x144) ++#define SLCR_SMC_CLK_CTRL (zynq_slcr_base_priv + 0x148) ++#define SLCR_LQSPI_CLK_CTRL (zynq_slcr_base_priv + 0x14c) ++#define SLCR_SDIO_CLK_CTRL (zynq_slcr_base_priv + 0x150) ++#define SLCR_UART_CLK_CTRL (zynq_slcr_base_priv + 0x154) ++#define SLCR_SPI_CLK_CTRL (zynq_slcr_base_priv + 0x158) ++#define SLCR_CAN_CLK_CTRL (zynq_slcr_base_priv + 0x15c) ++#define SLCR_CAN_MIOCLK_CTRL (zynq_slcr_base_priv + 0x160) ++#define SLCR_DBG_CLK_CTRL (zynq_slcr_base_priv + 0x164) ++#define SLCR_PCAP_CLK_CTRL (zynq_slcr_base_priv + 0x168) ++#define SLCR_FPGA0_CLK_CTRL (zynq_slcr_base_priv + 0x170) ++#define SLCR_621_TRUE (zynq_slcr_base_priv + 0x1c4) ++#define SLCR_SWDT_CLK_SEL (zynq_slcr_base_priv + 0x304) ++ ++#define NUM_MIO_PINS 54 ++ ++enum zynq_clk { ++ armpll, ddrpll, iopll, ++ cpu_6or4x, cpu_3or2x, cpu_2x, cpu_1x, ++ ddr2x, ddr3x, dci, ++ lqspi, smc, pcap, gem0, gem1, fclk0, fclk1, fclk2, fclk3, can0, can1, ++ sdio0, sdio1, uart0, uart1, spi0, spi1, dma, ++ usb0_aper, usb1_aper, gem0_aper, gem1_aper, ++ sdio0_aper, sdio1_aper, spi0_aper, spi1_aper, can0_aper, can1_aper, ++ i2c0_aper, i2c1_aper, uart0_aper, uart1_aper, gpio_aper, lqspi_aper, ++ smc_aper, swdt, dbg_trc, dbg_apb, clk_max}; ++ ++static struct clk *ps_clk; ++static struct clk *clks[clk_max]; ++static struct clk_onecell_data clk_data; ++ ++static DEFINE_SPINLOCK(armpll_lock); ++static DEFINE_SPINLOCK(ddrpll_lock); ++static DEFINE_SPINLOCK(iopll_lock); ++static DEFINE_SPINLOCK(armclk_lock); ++static DEFINE_SPINLOCK(swdtclk_lock); ++static DEFINE_SPINLOCK(ddrclk_lock); ++static DEFINE_SPINLOCK(dciclk_lock); ++static DEFINE_SPINLOCK(gem0clk_lock); ++static DEFINE_SPINLOCK(gem1clk_lock); ++static DEFINE_SPINLOCK(canclk_lock); ++static DEFINE_SPINLOCK(canmioclk_lock); ++static DEFINE_SPINLOCK(dbgclk_lock); ++static DEFINE_SPINLOCK(aperclk_lock); ++ ++static const char dummy_nm[] __initconst = "dummy_name"; ++ ++static const char *armpll_parents[] __initdata = {"armpll_int", "ps_clk"}; ++static const char *ddrpll_parents[] __initdata = {"ddrpll_int", "ps_clk"}; ++static const char *iopll_parents[] __initdata = {"iopll_int", "ps_clk"}; ++static const char *gem0_mux_parents[] __initdata = {"gem0_div1", dummy_nm}; ++static const char *gem1_mux_parents[] __initdata = {"gem1_div1", dummy_nm}; ++static const char *can0_mio_mux2_parents[] __initdata = {"can0_gate", ++ "can0_mio_mux"}; ++static const char *can1_mio_mux2_parents[] __initdata = {"can1_gate", ++ "can1_mio_mux"}; ++static const char *dbg_emio_mux_parents[] __initdata = {"dbg_div", ++ dummy_nm}; ++ ++static const char *dbgtrc_emio_input_names[] __initdata = {"trace_emio_clk"}; ++static const char *gem0_emio_input_names[] __initdata = {"gem0_emio_clk"}; ++static const char *gem1_emio_input_names[] __initdata = {"gem1_emio_clk"}; ++static const char *swdt_ext_clk_input_names[] __initdata = {"swdt_ext_clk"}; ++ ++#ifdef CONFIG_SUSPEND ++unsigned int zynq_clk_suspended; ++static struct clk *armpll_save_parent; ++static struct clk *iopll_save_parent; ++ ++int zynq_clk_suspend_early(void) ++{ ++ int ret; ++ ++ zynq_clk_suspended = 1; ++ ++ iopll_save_parent = clk_get_parent(clks[iopll]); ++ armpll_save_parent = clk_get_parent(clks[armpll]); ++ ++ ret = clk_set_parent(clks[iopll], ps_clk); ++ if (ret) ++ pr_info("%s: reparent iopll failed %d\n", __func__, ret); ++ ++ ret = clk_set_parent(clks[armpll], ps_clk); ++ if (ret) ++ pr_info("%s: reparent armpll failed %d\n", __func__, ret); ++ ++ return 0; ++} ++ ++void zynq_clk_resume_late(void) ++{ ++ clk_set_parent(clks[armpll], armpll_save_parent); ++ clk_set_parent(clks[iopll], iopll_save_parent); ++ ++ zynq_clk_suspended = 0; ++} ++#endif ++ ++static void __init zynq_clk_register_fclk(enum zynq_clk fclk, ++ const char *clk_name, void __iomem *fclk_ctrl_reg, ++ const char **parents) ++{ ++ struct clk *clk; ++ char *mux_name; ++ char *div0_name; ++ char *div1_name; ++ spinlock_t *fclk_lock; ++ spinlock_t *fclk_gate_lock; ++ void __iomem *fclk_gate_reg = fclk_ctrl_reg + 8; ++ ++ fclk_lock = kmalloc(sizeof(*fclk_lock), GFP_KERNEL); ++ if (!fclk_lock) ++ goto err; ++ fclk_gate_lock = kmalloc(sizeof(*fclk_gate_lock), GFP_KERNEL); ++ if (!fclk_gate_lock) ++ goto err; ++ spin_lock_init(fclk_lock); ++ spin_lock_init(fclk_gate_lock); ++ ++ mux_name = kasprintf(GFP_KERNEL, "%s_mux", clk_name); ++ div0_name = kasprintf(GFP_KERNEL, "%s_div0", clk_name); ++ div1_name = kasprintf(GFP_KERNEL, "%s_div1", clk_name); ++ ++ clk = clk_register_mux(NULL, mux_name, parents, 4, 0, ++ fclk_ctrl_reg, 4, 2, 0, fclk_lock); ++ ++ clk = clk_register_divider(NULL, div0_name, mux_name, ++ 0, fclk_ctrl_reg, 8, 6, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, fclk_lock); ++ ++ clk = clk_register_divider(NULL, div1_name, div0_name, ++ CLK_SET_RATE_PARENT, fclk_ctrl_reg, 20, 6, ++ CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, ++ fclk_lock); ++ ++ clks[fclk] = clk_register_gate(NULL, clk_name, ++ div1_name, CLK_SET_RATE_PARENT, fclk_gate_reg, ++ 0, CLK_GATE_SET_TO_DISABLE, fclk_gate_lock); ++ kfree(mux_name); ++ kfree(div0_name); ++ kfree(div1_name); ++ ++ return; ++ ++err: ++ clks[fclk] = ERR_PTR(-ENOMEM); ++} ++ ++static void __init zynq_clk_register_periph_clk(enum zynq_clk clk0, ++ enum zynq_clk clk1, const char *clk_name0, ++ const char *clk_name1, void __iomem *clk_ctrl, ++ const char **parents, unsigned int two_gates) ++{ ++ struct clk *clk; ++ char *mux_name; ++ char *div_name; ++ spinlock_t *lock; ++ ++ lock = kmalloc(sizeof(*lock), GFP_KERNEL); ++ if (!lock) ++ goto err; ++ spin_lock_init(lock); ++ ++ mux_name = kasprintf(GFP_KERNEL, "%s_mux", clk_name0); ++ div_name = kasprintf(GFP_KERNEL, "%s_div", clk_name0); ++ ++ clk = clk_register_mux(NULL, mux_name, parents, 4, 0, ++ clk_ctrl, 4, 2, 0, lock); ++ ++ clk = clk_register_divider(NULL, div_name, mux_name, 0, clk_ctrl, 8, 6, ++ CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, lock); ++ ++ clks[clk0] = clk_register_gate(NULL, clk_name0, div_name, ++ CLK_SET_RATE_PARENT, clk_ctrl, 0, 0, lock); ++ if (two_gates) ++ clks[clk1] = clk_register_gate(NULL, clk_name1, div_name, ++ CLK_SET_RATE_PARENT, clk_ctrl, 1, 0, lock); ++ ++ kfree(mux_name); ++ kfree(div_name); ++ ++ return; ++ ++err: ++ clks[clk0] = ERR_PTR(-ENOMEM); ++ if (two_gates) ++ clks[clk1] = ERR_PTR(-ENOMEM); ++} ++ ++static void __init zynq_clk_setup(struct device_node *np) ++{ ++ int i; ++ u32 tmp; ++ int ret; ++ struct clk *clk; ++ char *clk_name; ++ unsigned int fclk_enable; ++ const char *clk_output_name[clk_max]; ++ const char *cpu_parents[4]; ++ const char *periph_parents[4]; ++ const char *swdt_ext_clk_mux_parents[2]; ++ const char *can_mio_mux_parents[NUM_MIO_PINS]; ++ ++ pr_info("Zynq clock init\n"); ++ ++ /* get clock output names from DT */ ++ for (i = 0; i < clk_max; i++) { ++ if (of_property_read_string_index(np, "clock-output-names", ++ i, &clk_output_name[i])) { ++ pr_err("%s: clock output name not in DT\n", __func__); ++ BUG(); ++ } ++ } ++ cpu_parents[0] = clk_output_name[armpll]; ++ cpu_parents[1] = clk_output_name[armpll]; ++ cpu_parents[2] = clk_output_name[ddrpll]; ++ cpu_parents[3] = clk_output_name[iopll]; ++ periph_parents[0] = clk_output_name[iopll]; ++ periph_parents[1] = clk_output_name[iopll]; ++ periph_parents[2] = clk_output_name[armpll]; ++ periph_parents[3] = clk_output_name[ddrpll]; ++ ++ /* ps_clk */ ++ ret = of_property_read_u32(np, "ps-clk-frequency", &tmp); ++ if (ret) { ++ pr_warn("ps_clk frequency not specified, using 33 MHz.\n"); ++ tmp = 33333333; ++ } ++ ps_clk = clk_register_fixed_rate(NULL, "ps_clk", NULL, CLK_IS_ROOT, ++ tmp); ++ ++ ret = of_property_read_u32(np, "fclk-enable", &fclk_enable); ++ if (ret) ++ fclk_enable = 0; ++ ++ /* PLLs */ ++ clk = clk_register_zynq_pll("armpll_int", "ps_clk", SLCR_ARMPLL_CTRL, ++ SLCR_PLL_STATUS, 0, &armpll_lock); ++ clks[armpll] = clk_register_mux(NULL, clk_output_name[armpll], ++ armpll_parents, 2, 0, SLCR_ARMPLL_CTRL, 4, 1, 0, ++ &armpll_lock); ++ ++ clk = clk_register_zynq_pll("ddrpll_int", "ps_clk", SLCR_DDRPLL_CTRL, ++ SLCR_PLL_STATUS, 1, &ddrpll_lock); ++ clks[ddrpll] = clk_register_mux(NULL, clk_output_name[ddrpll], ++ ddrpll_parents, 2, 0, SLCR_DDRPLL_CTRL, 4, 1, 0, ++ &ddrpll_lock); ++ ++ clk = clk_register_zynq_pll("iopll_int", "ps_clk", SLCR_IOPLL_CTRL, ++ SLCR_PLL_STATUS, 2, &iopll_lock); ++ clks[iopll] = clk_register_mux(NULL, clk_output_name[iopll], ++ iopll_parents, 2, 0, SLCR_IOPLL_CTRL, 4, 1, 0, ++ &iopll_lock); ++ ++ /* CPU clocks */ ++ tmp = readl(SLCR_621_TRUE) & 1; ++ clk = clk_register_mux(NULL, "cpu_mux", cpu_parents, 4, 0, ++ SLCR_ARM_CLK_CTRL, 4, 2, 0, &armclk_lock); ++ clk = clk_register_divider(NULL, "cpu_div", "cpu_mux", 0, ++ SLCR_ARM_CLK_CTRL, 8, 6, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, &armclk_lock); ++ ++ clks[cpu_6or4x] = clk_register_gate(NULL, clk_output_name[cpu_6or4x], ++ "cpu_div", CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, ++ SLCR_ARM_CLK_CTRL, 24, 0, &armclk_lock); ++ clk_register_clkdev(clks[cpu_6or4x], "cpufreq_clk", NULL); ++ ++ clk = clk_register_fixed_factor(NULL, "cpu_3or2x_div", "cpu_div", 0, ++ 1, 2); ++ clks[cpu_3or2x] = clk_register_gate(NULL, clk_output_name[cpu_3or2x], ++ "cpu_3or2x_div", CLK_IGNORE_UNUSED, ++ SLCR_ARM_CLK_CTRL, 25, 0, &armclk_lock); ++ /* FIXME: in newer kernels the timer uses DT */ ++ clk_register_clkdev(clks[cpu_3or2x], NULL, "smp_twd"); ++ ++ clk = clk_register_fixed_factor(NULL, "cpu_2x_div", "cpu_div", 0, 1, ++ 2 + tmp); ++ clks[cpu_2x] = clk_register_gate(NULL, clk_output_name[cpu_2x], ++ "cpu_2x_div", CLK_IGNORE_UNUSED, SLCR_ARM_CLK_CTRL, ++ 26, 0, &armclk_lock); ++ ++ clk = clk_register_fixed_factor(NULL, "cpu_1x_div", "cpu_div", 0, 1, ++ 4 + 2 * tmp); ++ clks[cpu_1x] = clk_register_gate(NULL, clk_output_name[cpu_1x], ++ "cpu_1x_div", CLK_IGNORE_UNUSED, SLCR_ARM_CLK_CTRL, 27, ++ 0, &armclk_lock); ++ ++ /* Timers */ ++ swdt_ext_clk_mux_parents[0] = clk_output_name[cpu_1x]; ++ for (i = 0; i < ARRAY_SIZE(swdt_ext_clk_input_names); i++) { ++ int idx = of_property_match_string(np, "clock-names", ++ swdt_ext_clk_input_names[i]); ++ if (idx >= 0) ++ swdt_ext_clk_mux_parents[i + 1] = ++ of_clk_get_parent_name(np, idx); ++ else ++ swdt_ext_clk_mux_parents[i + 1] = dummy_nm; ++ } ++ clks[swdt] = clk_register_mux(NULL, clk_output_name[swdt], ++ swdt_ext_clk_mux_parents, 2, CLK_SET_RATE_PARENT, ++ SLCR_SWDT_CLK_SEL, 0, 1, 0, &swdtclk_lock); ++ ++ /* DDR clocks */ ++ clk = clk_register_divider(NULL, "ddr2x_div", "ddrpll", 0, ++ SLCR_DDR_CLK_CTRL, 26, 6, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, &ddrclk_lock); ++ clks[ddr2x] = clk_register_gate(NULL, clk_output_name[ddr2x], ++ "ddr2x_div", 0, SLCR_DDR_CLK_CTRL, 1, 0, &ddrclk_lock); ++ clk_prepare_enable(clks[ddr2x]); ++ clk = clk_register_divider(NULL, "ddr3x_div", "ddrpll", 0, ++ SLCR_DDR_CLK_CTRL, 20, 6, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, &ddrclk_lock); ++ clks[ddr3x] = clk_register_gate(NULL, clk_output_name[ddr3x], ++ "ddr3x_div", 0, SLCR_DDR_CLK_CTRL, 0, 0, &ddrclk_lock); ++ clk_prepare_enable(clks[ddr3x]); ++ ++ clk = clk_register_divider(NULL, "dci_div0", "ddrpll", 0, ++ SLCR_DCI_CLK_CTRL, 8, 6, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, &dciclk_lock); ++ clk = clk_register_divider(NULL, "dci_div1", "dci_div0", ++ CLK_SET_RATE_PARENT, SLCR_DCI_CLK_CTRL, 20, 6, ++ CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, ++ &dciclk_lock); ++ clks[dci] = clk_register_gate(NULL, clk_output_name[dci], "dci_div1", ++ CLK_SET_RATE_PARENT, SLCR_DCI_CLK_CTRL, 0, 0, ++ &dciclk_lock); ++ clk_prepare_enable(clks[dci]); ++ ++ /* Peripheral clocks */ ++ for (i = fclk0; i <= fclk3; i++) { ++ zynq_clk_register_fclk(i, clk_output_name[i], ++ SLCR_FPGA0_CLK_CTRL + 0x10 * (i - fclk0), ++ periph_parents); ++ ++ if (fclk_enable & BIT(i - fclk0)) { ++ if (clk_prepare_enable(clks[i])) ++ pr_warn("%s: FCLK%u enable failed\n", ++ __func__, i - fclk0); ++ } ++ } ++ ++ zynq_clk_register_periph_clk(lqspi, 0, clk_output_name[lqspi], NULL, ++ SLCR_LQSPI_CLK_CTRL, periph_parents, 0); ++ ++ zynq_clk_register_periph_clk(smc, 0, clk_output_name[smc], NULL, ++ SLCR_SMC_CLK_CTRL, periph_parents, 0); ++ ++ zynq_clk_register_periph_clk(pcap, 0, clk_output_name[pcap], NULL, ++ SLCR_PCAP_CLK_CTRL, periph_parents, 0); ++ ++ zynq_clk_register_periph_clk(sdio0, sdio1, clk_output_name[sdio0], ++ clk_output_name[sdio1], SLCR_SDIO_CLK_CTRL, ++ periph_parents, 1); ++ ++ zynq_clk_register_periph_clk(uart0, uart1, clk_output_name[uart0], ++ clk_output_name[uart1], SLCR_UART_CLK_CTRL, ++ periph_parents, 1); ++ ++ zynq_clk_register_periph_clk(spi0, spi1, clk_output_name[spi0], ++ clk_output_name[spi1], SLCR_SPI_CLK_CTRL, ++ periph_parents, 1); ++ ++ for (i = 0; i < ARRAY_SIZE(gem0_emio_input_names); i++) { ++ int idx = of_property_match_string(np, "clock-names", ++ gem0_emio_input_names[i]); ++ if (idx >= 0) ++ gem0_mux_parents[i + 1] = of_clk_get_parent_name(np, ++ idx); ++ } ++ clk = clk_register_mux(NULL, "gem0_mux", periph_parents, 4, 0, ++ SLCR_GEM0_CLK_CTRL, 4, 2, 0, &gem0clk_lock); ++ clk = clk_register_divider(NULL, "gem0_div0", "gem0_mux", 0, ++ SLCR_GEM0_CLK_CTRL, 8, 6, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, &gem0clk_lock); ++ clk = clk_register_divider(NULL, "gem0_div1", "gem0_div0", ++ CLK_SET_RATE_PARENT, SLCR_GEM0_CLK_CTRL, 20, 6, ++ CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, ++ &gem0clk_lock); ++ clk = clk_register_mux(NULL, "gem0_emio_mux", gem0_mux_parents, 2, ++ CLK_SET_RATE_PARENT, SLCR_GEM0_CLK_CTRL, 6, 1, 0, ++ &gem0clk_lock); ++ clks[gem0] = clk_register_gate(NULL, clk_output_name[gem0], ++ "gem0_emio_mux", CLK_SET_RATE_PARENT, ++ SLCR_GEM0_CLK_CTRL, 0, 0, &gem0clk_lock); ++ ++ for (i = 0; i < ARRAY_SIZE(gem1_emio_input_names); i++) { ++ int idx = of_property_match_string(np, "clock-names", ++ gem1_emio_input_names[i]); ++ if (idx >= 0) ++ gem1_mux_parents[i + 1] = of_clk_get_parent_name(np, ++ idx); ++ } ++ clk = clk_register_mux(NULL, "gem1_mux", periph_parents, 4, 0, ++ SLCR_GEM1_CLK_CTRL, 4, 2, 0, &gem1clk_lock); ++ clk = clk_register_divider(NULL, "gem1_div0", "gem1_mux", 0, ++ SLCR_GEM1_CLK_CTRL, 8, 6, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, &gem1clk_lock); ++ clk = clk_register_divider(NULL, "gem1_div1", "gem1_div0", ++ CLK_SET_RATE_PARENT, SLCR_GEM1_CLK_CTRL, 20, 6, ++ CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, ++ &gem1clk_lock); ++ clk = clk_register_mux(NULL, "gem1_emio_mux", gem1_mux_parents, 2, ++ CLK_SET_RATE_PARENT, SLCR_GEM1_CLK_CTRL, 6, 1, 0, ++ &gem1clk_lock); ++ clks[gem1] = clk_register_gate(NULL, clk_output_name[gem1], ++ "gem1_emio_mux", CLK_SET_RATE_PARENT, ++ SLCR_GEM1_CLK_CTRL, 0, 0, &gem1clk_lock); ++ ++ tmp = strlen("mio_clk_00x"); ++ clk_name = kmalloc(tmp, GFP_KERNEL); ++ for (i = 0; i < NUM_MIO_PINS; i++) { ++ int idx; ++ ++ snprintf(clk_name, tmp, "mio_clk_%2.2d", i); ++ idx = of_property_match_string(np, "clock-names", clk_name); ++ if (idx >= 0) ++ can_mio_mux_parents[i] = of_clk_get_parent_name(np, ++ idx); ++ else ++ can_mio_mux_parents[i] = dummy_nm; ++ } ++ kfree(clk_name); ++ clk = clk_register_mux(NULL, "can_mux", periph_parents, 4, 0, ++ SLCR_CAN_CLK_CTRL, 4, 2, 0, &canclk_lock); ++ clk = clk_register_divider(NULL, "can_div0", "can_mux", 0, ++ SLCR_CAN_CLK_CTRL, 8, 6, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, &canclk_lock); ++ clk = clk_register_divider(NULL, "can_div1", "can_div0", ++ CLK_SET_RATE_PARENT, SLCR_CAN_CLK_CTRL, 20, 6, ++ CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, ++ &canclk_lock); ++ clk = clk_register_gate(NULL, "can0_gate", "can_div1", ++ CLK_SET_RATE_PARENT, SLCR_CAN_CLK_CTRL, 0, 0, ++ &canclk_lock); ++ clk = clk_register_gate(NULL, "can1_gate", "can_div1", ++ CLK_SET_RATE_PARENT, SLCR_CAN_CLK_CTRL, 1, 0, ++ &canclk_lock); ++ clk = clk_register_mux(NULL, "can0_mio_mux", ++ can_mio_mux_parents, 54, CLK_SET_RATE_PARENT, ++ SLCR_CAN_MIOCLK_CTRL, 0, 6, 0, &canmioclk_lock); ++ clk = clk_register_mux(NULL, "can1_mio_mux", ++ can_mio_mux_parents, 54, CLK_SET_RATE_PARENT, ++ SLCR_CAN_MIOCLK_CTRL, 16, 6, 0, &canmioclk_lock); ++ clks[can0] = clk_register_mux(NULL, clk_output_name[can0], ++ can0_mio_mux2_parents, 2, CLK_SET_RATE_PARENT, ++ SLCR_CAN_MIOCLK_CTRL, 6, 1, 0, &canmioclk_lock); ++ clks[can1] = clk_register_mux(NULL, clk_output_name[can1], ++ can1_mio_mux2_parents, 2, CLK_SET_RATE_PARENT, ++ SLCR_CAN_MIOCLK_CTRL, 22, 1, 0, &canmioclk_lock); ++ ++ for (i = 0; i < ARRAY_SIZE(dbgtrc_emio_input_names); i++) { ++ int idx = of_property_match_string(np, "clock-names", ++ dbgtrc_emio_input_names[i]); ++ if (idx >= 0) ++ dbg_emio_mux_parents[i + 1] = of_clk_get_parent_name(np, ++ idx); ++ } ++ clk = clk_register_mux(NULL, "dbg_mux", periph_parents, 4, 0, ++ SLCR_DBG_CLK_CTRL, 4, 2, 0, &dbgclk_lock); ++ clk = clk_register_divider(NULL, "dbg_div", "dbg_mux", 0, ++ SLCR_DBG_CLK_CTRL, 8, 6, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, &dbgclk_lock); ++ clk = clk_register_mux(NULL, "dbg_emio_mux", dbg_emio_mux_parents, 2, 0, ++ SLCR_DBG_CLK_CTRL, 6, 1, 0, &dbgclk_lock); ++ clks[dbg_trc] = clk_register_gate(NULL, clk_output_name[dbg_trc], ++ "dbg_emio_mux", CLK_SET_RATE_PARENT, SLCR_DBG_CLK_CTRL, ++ 0, 0, &dbgclk_lock); ++ clks[dbg_apb] = clk_register_gate(NULL, clk_output_name[dbg_apb], ++ clk_output_name[cpu_1x], 0, SLCR_DBG_CLK_CTRL, 1, 0, ++ &dbgclk_lock); ++ ++ /* One gated clock for all APER clocks. */ ++ clks[dma] = clk_register_gate(NULL, clk_output_name[dma], ++ clk_output_name[cpu_2x], 0, SLCR_APER_CLK_CTRL, 0, 0, ++ &aperclk_lock); ++ clks[usb0_aper] = clk_register_gate(NULL, clk_output_name[usb0_aper], ++ clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 2, 0, ++ &aperclk_lock); ++ clks[usb1_aper] = clk_register_gate(NULL, clk_output_name[usb1_aper], ++ clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 3, 0, ++ &aperclk_lock); ++ clks[gem0_aper] = clk_register_gate(NULL, clk_output_name[gem0_aper], ++ clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 6, 0, ++ &aperclk_lock); ++ clks[gem1_aper] = clk_register_gate(NULL, clk_output_name[gem1_aper], ++ clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 7, 0, ++ &aperclk_lock); ++ clks[sdio0_aper] = clk_register_gate(NULL, clk_output_name[sdio0_aper], ++ clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 10, 0, ++ &aperclk_lock); ++ clks[sdio1_aper] = clk_register_gate(NULL, clk_output_name[sdio1_aper], ++ clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 11, 0, ++ &aperclk_lock); ++ clks[spi0_aper] = clk_register_gate(NULL, clk_output_name[spi0_aper], ++ clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 14, 0, ++ &aperclk_lock); ++ clks[spi1_aper] = clk_register_gate(NULL, clk_output_name[spi1_aper], ++ clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 15, 0, ++ &aperclk_lock); ++ clks[can0_aper] = clk_register_gate(NULL, clk_output_name[can0_aper], ++ clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 16, 0, ++ &aperclk_lock); ++ clks[can1_aper] = clk_register_gate(NULL, clk_output_name[can1_aper], ++ clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 17, 0, ++ &aperclk_lock); ++ clks[i2c0_aper] = clk_register_gate(NULL, clk_output_name[i2c0_aper], ++ clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 18, 0, ++ &aperclk_lock); ++ clks[i2c1_aper] = clk_register_gate(NULL, clk_output_name[i2c1_aper], ++ clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 19, 0, ++ &aperclk_lock); ++ clks[uart0_aper] = clk_register_gate(NULL, clk_output_name[uart0_aper], ++ clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 20, 0, ++ &aperclk_lock); ++ clks[uart1_aper] = clk_register_gate(NULL, clk_output_name[uart1_aper], ++ clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 21, 0, ++ &aperclk_lock); ++ clks[gpio_aper] = clk_register_gate(NULL, clk_output_name[gpio_aper], ++ clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 22, 0, ++ &aperclk_lock); ++ clks[lqspi_aper] = clk_register_gate(NULL, clk_output_name[lqspi_aper], ++ clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 23, 0, ++ &aperclk_lock); ++ clks[smc_aper] = clk_register_gate(NULL, clk_output_name[smc_aper], ++ clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 24, 0, ++ &aperclk_lock); ++ ++ for (i = 0; i < ARRAY_SIZE(clks); i++) { ++ if (IS_ERR(clks[i])) { ++ pr_err("Zynq clk %d: register failed with %ld\n", ++ i, PTR_ERR(clks[i])); ++ BUG(); ++ } ++ } ++ ++ clk_data.clks = clks; ++ clk_data.clk_num = ARRAY_SIZE(clks); ++ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); ++} ++ ++static const struct of_device_id zynq_clk_match[] __initconst = { ++ { .compatible = "xlnx,ps7-clkc", .data = zynq_clk_setup, }, ++ { .compatible = "fixed-clock", .data = of_fixed_clk_setup, }, ++ {} ++}; ++ ++void __init zynq_clock_init(void __iomem *slcr_base) ++{ ++ zynq_slcr_base_priv = slcr_base; ++ of_clk_init(zynq_clk_match); ++} +diff --git a/drivers/clk/zynq/peripheral_clk.c b/drivers/clk/zynq/peripheral_clk.c +deleted file mode 100644 +index ea33d68..0000000 +--- a/drivers/clk/zynq/peripheral_clk.c ++++ /dev/null +@@ -1,515 +0,0 @@ +-/** +- * Xilinx Zynq Clock Implementations for Peripheral clocks. +- * +- * zynq_periphclk_* where * is one of: +- * d1m: 1 divisor register, muxable +- * d2m: 2 divisor registers, muxable +- * gd1m: 1 divisor register, muxable, gateable +- * gd2m: 2 divisor registers, muxable, gateable +- * +- * +- * Copyright (C) 2012 Xilinx +- * +- * This software is licensed under the terms of the GNU General Public +- * License version 2, as published by the Free Software Foundation, and +- * may be copied, distributed, and modified under those terms. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +- +-/** +- * struct zynq_periph_clk +- * @hw: handle between common and hardware-specific interfaces +- * @clkctrl: CLK control register +- * @lock: register lock +- */ +-struct zynq_periph_clk { +- struct clk_hw hw; +- void __iomem *clkctrl; +- spinlock_t *lock; +-}; +-#define to_zynq_periph_clk(_hw)\ +- container_of(_hw, struct zynq_periph_clk, hw) +-#define CLKCTRL_DIV_MASK 0x3f00 +-#define CLKCTRL_DIV_SHIFT 8 +-#define CLKCTRL_DIV1_MASK CLKCTRL_DIV_MASK +-#define CLKCTRL_DIV1_SHIFT CLKCTRL_DIV_SHIFT +-#define CLKCTRL_DIV2_MASK 0x3f00000 +-#define CLKCTRL_DIV2_SHIFT 20 +-/* +- * This is a hack: We have clocks with 0 - 3 bit muxes. If present they start +- * all in the corresponding clk_ctrl reg. If narrower than 3 bits the bit fiels +- * is write ignore/read zero. Alternatively we could save the mask and shift +- * values in the zynq_periph_clk_* struct, like the clk-mux implementation. +- */ +-#define CLKCTRL_CLKSRC_MASK 0x70 +-#define CLKCTRL_CLKSRC_SHIFT 4 +-#define CLKCTRL_ENABLE_MASK 1 +-#define CLKCTRL_ENABLE_SHIFT 0 +- +-/* Clock gating ops for peripheral clocks featuring 1 gate */ +-/** +- * zynq_periphclk_gate1_enable - Enable clock +- * @hw: Handle between common and hardware-specific interfaces +- * Returns 0 on success +- */ +-static int zynq_periphclk_gate1_enable(struct clk_hw *hw) +-{ +- u32 reg; +- unsigned long flags = 0; +- struct zynq_periph_clk *clk = +- to_zynq_periph_clk(hw); +- +- spin_lock_irqsave(clk->lock, flags); +- reg = readl(clk->clkctrl); +- reg |= CLKCTRL_ENABLE_MASK; +- writel(reg, clk->clkctrl); +- spin_unlock_irqrestore(clk->lock, flags); +- +- return 0; +-} +- +-/** +- * zynq_periphclk_gate1_disable - Disable clock +- * @hw: Handle between common and hardware-specific interfaces +- * Returns 0 on success +- */ +-static void zynq_periphclk_gate1_disable(struct clk_hw *hw) +-{ +- u32 reg; +- unsigned long flags = 0; +- struct zynq_periph_clk *clk = +- to_zynq_periph_clk(hw); +- +- spin_lock_irqsave(clk->lock, flags); +- reg = readl(clk->clkctrl); +- reg &= ~CLKCTRL_ENABLE_MASK; +- writel(reg, clk->clkctrl); +- spin_unlock_irqrestore(clk->lock, flags); +-} +- +-/** +- * zynq_periphclk_gate1_is_enabled - Check if a clock is enabled +- * @hw: Handle between common and hardware-specific interfaces +- * Returns 1 if the clock is enabled, 0 otherwise. +- */ +-static int zynq_periphclk_gate1_is_enabled(struct clk_hw *hw) +-{ +- u32 reg; +- unsigned long flags = 0; +- struct zynq_periph_clk *clk = +- to_zynq_periph_clk(hw); +- +- /* do we need lock for read? */ +- spin_lock_irqsave(clk->lock, flags); +- reg = readl(clk->clkctrl); +- spin_unlock_irqrestore(clk->lock, flags); +- +- return (reg & CLKCTRL_ENABLE_MASK) >> CLKCTRL_ENABLE_SHIFT; +-} +- +-/* Rate set/get functions for peripheral clocks with a single divisor */ +-/** +- * zynq_periphclk_div1_set_rate() - Change clock frequncy +- * @hw: Handle between common and hardware-specific interfaces +- * @rate: Desired clock frequency +- * @prate: Clock frequency of parent clock +- * Returns 0 on success, negative errno otherwise. +- */ +-static int zynq_periphclk_div1_set_rate(struct clk_hw *hw, unsigned long rate, +- unsigned long prate) +-{ +- u32 div = DIV_ROUND_CLOSEST(prate, rate); +- u32 reg; +- unsigned long flags = 0; +- struct zynq_periph_clk *clk = +- to_zynq_periph_clk(hw); +- +- if ((div < 1) || (div > 0x3f)) +- return -EINVAL; +- +- spin_lock_irqsave(clk->lock, flags); +- +- reg = readl(clk->clkctrl); +- reg &= ~CLKCTRL_DIV_MASK; +- reg |= div << CLKCTRL_DIV_SHIFT; +- writel(reg, clk->clkctrl); +- +- spin_unlock_irqrestore(clk->lock, flags); +- +- return 0; +-} +- +-/** +- * zynq_periphclk_div1_round_rate() - Round a clock frequency +- * @hw: Handle between common and hardware-specific interfaces +- * @rate: Desired clock frequency +- * @prate: Clock frequency of parent clock +- * Returns frequency closest to @rate the hardware can generate. +- */ +-static long zynq_periphclk_div1_round_rate(struct clk_hw *hw, +- unsigned long rate, unsigned long *prate) +-{ +- long div; +- +- div = DIV_ROUND_CLOSEST(*prate, rate); +- if (div < 1) +- div = 1; +- if (div > 0x3f) +- div = 0x3f; +- +- return *prate / div; +-} +- +-/** +- * zynq_periphclk_div1_recalc_rate() - Recalculate clock frequency +- * @hw: Handle between common and hardware-specific interfaces +- * @parent_rate: Clock frequency of parent clock +- * Returns current clock frequency. +- */ +-static unsigned long zynq_periphclk_div1_recalc_rate(struct clk_hw *hw, +- unsigned long parent_rate) +-{ +- u32 div; +- struct zynq_periph_clk *clk = +- to_zynq_periph_clk(hw); +- +- /* +- * makes probably sense to redundantly save div in the struct +- * zynq_periphclk_gd1m to save the IO access. Do we need spinlock for +- * read access? +- */ +- div = (readl(clk->clkctrl) & CLKCTRL_DIV_MASK) >> CLKCTRL_DIV_SHIFT; +- if (div < 1) +- div = 1; +- +- return parent_rate / div; +-} +- +-/* Rate set/get functions for peripheral clocks with two divisors */ +-/** +- * zynq_periphclk_get_best_divs2 - Calculate best divisors values +- * @inputrate: Clock input frequency +- * @targetrate: Desired output frequency +- * @div1: Value for divisor 1 (return value) +- * @div2: Value for divisor 2 (return value) +- * Returns the resulting frequency or zero if no valid divisors are found. +- * +- * Calculate the best divisors values to achieve a given target frequency for a +- * given input frequency for clocks with two dividers fields +- */ +-static unsigned long +-zynq_periphclk_get_best_divs2(const unsigned long inputrate, +- const unsigned long targetrate, u32 *div1, u32 *div2) +-{ +- u32 d1; +- u32 d2; +- unsigned long calcrate; +- unsigned long bestrate = 0; +- unsigned int error; +- unsigned int besterror = ~0; +- +- /* Probably micro-optimizing, but probably worth thinking about reducing +- * the iterations and/or getting rid of some divisions */ +- for (d1 = 1; d1 <= 0x3f; d1++) { +- d2 = DIV_ROUND_CLOSEST(inputrate / d1, targetrate); +- if ((d2 < 1) || (d2 > 0x3f)) +- continue; +- calcrate = (inputrate / d1) / d2; +- +- if (calcrate > targetrate) +- error = calcrate - targetrate; +- else +- error = targetrate - calcrate; +- +- if (error < besterror) { +- *div1 = d1; +- *div2 = d2; +- bestrate = calcrate; +- besterror = error; +- } +- } +- +- return bestrate; +-} +- +-/** +- * zynq_periphclk_div2_set_rate() - Change clock frequncy +- * @hw: Handle between common and hardware-specific interfaces +- * @rate: Desired clock frequency +- * @prate: Clock frequency of parent clock +- * Returns 0 on success, negative errno otherwise. +- */ +-static int zynq_periphclk_div2_set_rate(struct clk_hw *hw, unsigned long rate, +- unsigned long prate) +-{ +- u32 div1; +- u32 div2; +- u32 reg; +- unsigned long flags = 0; +- struct zynq_periph_clk *clk = +- to_zynq_periph_clk(hw); +- +- if (!zynq_periphclk_get_best_divs2(prate, rate, &div1, &div2)) +- return -EINVAL; +- +- spin_lock_irqsave(clk->lock, flags); +- +- reg = readl(clk->clkctrl); +- reg &= ~CLKCTRL_DIV1_MASK; +- reg &= ~CLKCTRL_DIV2_MASK; +- reg |= div1 << CLKCTRL_DIV1_SHIFT; +- reg |= div2 << CLKCTRL_DIV2_SHIFT; +- writel(reg, clk->clkctrl); +- +- spin_unlock_irqrestore(clk->lock, flags); +- +- return 0; +-} +- +-/** +- * zynq_periphclk_div2_round_rate() - Round a clock frequency +- * @hw: Handle between common and hardware-specific interfaces +- * @rate: Desired clock frequency +- * @prate: Clock frequency of parent clock +- * Returns frequency closest to @rate the hardware can generate. +- */ +-static long zynq_periphclk_div2_round_rate(struct clk_hw *hw, +- unsigned long rate, unsigned long *prate) +-{ +- u32 div1; +- u32 div2; +- long ret; +- +- ret = zynq_periphclk_get_best_divs2(*prate, rate, &div1, &div2); +- if (!ret) +- return -EINVAL; +- +- return ret; +-} +- +-/** +- * zynq_periphclk_div1_recalc_rate() - Recalculate clock frequency +- * @hw: Handle between common and hardware-specific interfaces +- * @parent_rate: Clock frequency of parent clock +- * Returns current clock frequency. +- */ +-static unsigned long zynq_periphclk_div2_recalc_rate(struct clk_hw *hw, +- unsigned long parent_rate) +-{ +- u32 div1; +- u32 div2; +- struct zynq_periph_clk *clk = +- to_zynq_periph_clk(hw); +- +- /* +- * makes probably sense to redundantly save div in the struct +- * zynq_periphclk_gd1m to save the IO access. Should we use spinlock for +- * reading? +- */ +- div1 = (readl(clk->clkctrl) & CLKCTRL_DIV1_MASK) >> CLKCTRL_DIV1_SHIFT; +- div2 = (readl(clk->clkctrl) & CLKCTRL_DIV2_MASK) >> CLKCTRL_DIV2_SHIFT; +- if (div1 < 1) +- div1 = 1; +- if (div2 < 1) +- div2 = 1; +- +- return (parent_rate / div1) / div2; +-} +- +-/* Muxing functions for peripheral clocks */ +-/** +- * zynq_periphclk_set_parent() - Reparent clock +- * @hw: Handle between common and hardware-specific interfaces +- * @index: Index of new parent. +- * Returns 0 on success, negative errno otherwise. +- */ +-static int zynq_periphclk_set_parent(struct clk_hw *hw, u8 index) +-{ +- u32 reg; +- unsigned long flags = 0; +- struct zynq_periph_clk *clk = +- to_zynq_periph_clk(hw); +- +- spin_lock_irqsave(clk->lock, flags); +- +- reg = readl(clk->clkctrl); +- reg &= ~CLKCTRL_CLKSRC_MASK; +- reg |= index << CLKCTRL_CLKSRC_SHIFT; +- writel(reg, clk->clkctrl); +- +- spin_unlock_irqrestore(clk->lock, flags); +- +- return 0; +-} +- +-/** +- * zynq_periphclk_get_parent() - Reparent clock +- * @hw: Handle between common and hardware-specific interfaces +- * Returns the index of the current clock parent. +- */ +-static u8 zynq_periphclk_get_parent(struct clk_hw *hw) +-{ +- struct zynq_periph_clk *clk = +- to_zynq_periph_clk(hw); +- +- return (readl(clk->clkctrl) & CLKCTRL_CLKSRC_MASK) >> +- CLKCTRL_CLKSRC_SHIFT; +-} +- +-/* Clk register functions */ +-/** +- * clk_register_zynq_common() - Register a clock with the clock framework +- * @name: Clock name +- * @clkctrl: Pointer to clock control register +- * @ops: Pointer to the struct clock_ops +- * @pnames: Array of names of clock parents +- * @num_parents:Number of parents +- * @lock: Register lock +- * Returns clk_register() return value or errpointer. +- */ +-static struct clk *clk_register_zynq_common(const char *name, +- void __iomem *clkctrl, const struct clk_ops *ops, +- const char **pnames, u8 num_parents, spinlock_t *lock) +-{ +- struct clk *ret; +- struct zynq_periph_clk *clk; +- struct clk_init_data initd = { +- .name = name, +- .ops = ops, +- .parent_names = pnames, +- .num_parents = num_parents, +- .flags = 0 +- }; +- +- clk = kmalloc(sizeof(*clk), GFP_KERNEL); +- if (!clk) { +- pr_err("%s: could not allocate Zynq clock\n", __func__); +- return ERR_PTR(-ENOMEM); +- } +- +- /* Populate the struct */ +- clk->hw.init = &initd; +- clk->clkctrl = clkctrl; +- clk->lock = lock; +- +- ret = clk_register(NULL, &clk->hw); +- if (IS_ERR(ret)) +- kfree(clk); +- +- return ret; +-} +- +-/* Clock ops structs for the different peripheral clock types */ +-static const struct clk_ops zynq_periphclk_gd1m_ops = { +- .enable = zynq_periphclk_gate1_enable, +- .disable = zynq_periphclk_gate1_disable, +- .is_enabled = zynq_periphclk_gate1_is_enabled, +- .set_parent = zynq_periphclk_set_parent, +- .get_parent = zynq_periphclk_get_parent, +- .set_rate = zynq_periphclk_div1_set_rate, +- .round_rate = zynq_periphclk_div1_round_rate, +- .recalc_rate = zynq_periphclk_div1_recalc_rate +-}; +- +-static const struct clk_ops zynq_periphclk_gd2m_ops = { +- .enable = zynq_periphclk_gate1_enable, +- .disable = zynq_periphclk_gate1_disable, +- .is_enabled = zynq_periphclk_gate1_is_enabled, +- .set_parent = zynq_periphclk_set_parent, +- .get_parent = zynq_periphclk_get_parent, +- .set_rate = zynq_periphclk_div2_set_rate, +- .round_rate = zynq_periphclk_div2_round_rate, +- .recalc_rate = zynq_periphclk_div2_recalc_rate +-}; +- +-static const struct clk_ops zynq_periphclk_d2m_ops = { +- .set_parent = zynq_periphclk_set_parent, +- .get_parent = zynq_periphclk_get_parent, +- .set_rate = zynq_periphclk_div2_set_rate, +- .round_rate = zynq_periphclk_div2_round_rate, +- .recalc_rate = zynq_periphclk_div2_recalc_rate +-}; +- +-static const struct clk_ops zynq_periphclk_d1m_ops = { +- .set_parent = zynq_periphclk_set_parent, +- .get_parent = zynq_periphclk_get_parent, +- .set_rate = zynq_periphclk_div1_set_rate, +- .round_rate = zynq_periphclk_div1_round_rate, +- .recalc_rate = zynq_periphclk_div1_recalc_rate +-}; +- +-/* Clock register functions for the different peripheral clock types */ +-/** +- * clk_register_zynq_gd1m() - Register a gd1m clock with the clock framework +- * @name: Clock name +- * @clkctrl: Pointer to clock control register +- * @pnames: Array of names of clock parents +- * @lock: Register lock +- * Returns clk_register() return value or errpointer. +- */ +-struct clk *clk_register_zynq_gd1m(const char *name, +- void __iomem *clkctrl, const char **pnames, spinlock_t *lock) +-{ +- return clk_register_zynq_common(name, clkctrl, &zynq_periphclk_gd1m_ops, +- pnames, 4, lock); +-} +- +-/** +- * clk_register_zynq_gd2m() - Register a gd2m clock with the clock framework +- * @name: Clock name +- * @clkctrl: Pointer to clock control register +- * @pnames: Array of names of clock parents +- * @num_parents:Number of parents +- * @lock: Register lock +- * Returns clk_register() return value or errpointer. +- */ +-struct clk *clk_register_zynq_gd2m(const char *name, +- void __iomem *clkctrl, const char **pnames, u8 num_parents, +- spinlock_t *lock) +-{ +- return clk_register_zynq_common(name, clkctrl, &zynq_periphclk_gd2m_ops, +- pnames, num_parents, lock); +-} +- +-/** +- * clk_register_zynq_d2m() - Register a d2m clock with the clock framework +- * @name: Clock name +- * @clkctrl: Pointer to clock control register +- * @pnames: Array of names of clock parents +- * @lock: Register lock +- * Returns clk_register() return value or errpointer. +- */ +-struct clk *clk_register_zynq_d2m(const char *name, +- void __iomem *clkctrl, const char **pnames, spinlock_t *lock) +-{ +- return clk_register_zynq_common(name, clkctrl, &zynq_periphclk_d2m_ops, +- pnames, 4, lock); +-} +- +-/** +- * clk_register_zynq_d1m() - Register a d1m clock with the clock framework +- * @name: Clock name +- * @clkctrl: Pointer to clock control register +- * @pnames: Array of names of clock parents +- * @num_parents:Number of parents +- * @lock: Register lock +- * Returns clk_register() return value or errpointer. +- */ +-struct clk *clk_register_zynq_d1m(const char *name, +- void __iomem *clkctrl, const char **pnames, u8 num_parents, +- spinlock_t *lock) +-{ +- return clk_register_zynq_common(name, clkctrl, &zynq_periphclk_d1m_ops, +- pnames, num_parents, lock); +-} +diff --git a/drivers/clk/zynq/pll.c b/drivers/clk/zynq/pll.c +new file mode 100644 +index 0000000..26a8d8b +--- /dev/null ++++ b/drivers/clk/zynq/pll.c +@@ -0,0 +1,243 @@ ++/* ++ * Zynq PLL driver ++ * ++ * Copyright (C) 2013 Xilinx ++ * ++ * Sören Brinkmann ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License v2 as published by ++ * the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ * ++ */ ++#include ++#include ++#include ++#include ++ ++/** ++ * struct zynq_pll ++ * @hw: Handle between common and hardware-specific interfaces ++ * @pll_ctrl: PLL control register ++ * @pll_status: PLL status register ++ * @lock: Register lock ++ * @lockbit: Indicates the associated PLL_LOCKED bit in the PLL status ++ * register. ++ */ ++struct zynq_pll { ++ struct clk_hw hw; ++ void __iomem *pll_ctrl; ++ void __iomem *pll_status; ++ spinlock_t *lock; ++ u8 lockbit; ++}; ++#define to_zynq_pll(_hw) container_of(_hw, struct zynq_pll, hw) ++ ++/* Register bitfield defines */ ++#define PLLCTRL_FBDIV_MASK 0x7f000 ++#define PLLCTRL_FBDIV_SHIFT 12 ++#define PLLCTRL_BPQUAL_MASK (1 << 3) ++#define PLLCTRL_PWRDWN_MASK 2 ++#define PLLCTRL_PWRDWN_SHIFT 1 ++#define PLLCTRL_RESET_MASK 1 ++#define PLLCTRL_RESET_SHIFT 0 ++ ++#define PLL_FBDIV_MIN 13 ++#define PLL_FBDIV_MAX 66 ++ ++/** ++ * zynq_pll_round_rate() - Round a clock frequency ++ * @hw: Handle between common and hardware-specific interfaces ++ * @rate: Desired clock frequency ++ * @prate: Clock frequency of parent clock ++ * Returns frequency closest to @rate the hardware can generate. ++ */ ++static long zynq_pll_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *prate) ++{ ++ u32 fbdiv; ++ ++ fbdiv = DIV_ROUND_CLOSEST(rate, *prate); ++ if (fbdiv < PLL_FBDIV_MIN) ++ fbdiv = PLL_FBDIV_MIN; ++ else if (fbdiv > PLL_FBDIV_MAX) ++ fbdiv = PLL_FBDIV_MAX; ++ ++ return *prate * fbdiv; ++} ++ ++/** ++ * zynq_pll_recalc_rate() - Recalculate clock frequency ++ * @hw: Handle between common and hardware-specific interfaces ++ * @parent_rate: Clock frequency of parent clock ++ * Returns current clock frequency. ++ */ ++static unsigned long zynq_pll_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct zynq_pll *clk = to_zynq_pll(hw); ++ u32 fbdiv; ++ ++ /* ++ * makes probably sense to redundantly save fbdiv in the struct ++ * zynq_pll to save the IO access. ++ */ ++ fbdiv = (readl(clk->pll_ctrl) & PLLCTRL_FBDIV_MASK) >> ++ PLLCTRL_FBDIV_SHIFT; ++ ++ return parent_rate * fbdiv; ++} ++ ++/** ++ * zynq_pll_is_enabled - Check if a clock is enabled ++ * @hw: Handle between common and hardware-specific interfaces ++ * Returns 1 if the clock is enabled, 0 otherwise. ++ * ++ * Not sure this is a good idea, but since disabled means bypassed for ++ * this clock implementation we say we are always enabled. ++ */ ++static int zynq_pll_is_enabled(struct clk_hw *hw) ++{ ++ unsigned long flags = 0; ++ u32 reg; ++ struct zynq_pll *clk = to_zynq_pll(hw); ++ ++ spin_lock_irqsave(clk->lock, flags); ++ ++ reg = readl(clk->pll_ctrl); ++ ++ spin_unlock_irqrestore(clk->lock, flags); ++ ++ return !(reg & (PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK)); ++} ++ ++/** ++ * zynq_pll_enable - Enable clock ++ * @hw: Handle between common and hardware-specific interfaces ++ * Returns 0 on success ++ */ ++static int zynq_pll_enable(struct clk_hw *hw) ++{ ++ unsigned long flags = 0; ++ u32 reg; ++ struct zynq_pll *clk = to_zynq_pll(hw); ++ ++ if (zynq_pll_is_enabled(hw)) ++ return 0; ++ ++ pr_info("PLL: enable\n"); ++ ++ /* Power up PLL and wait for lock */ ++ spin_lock_irqsave(clk->lock, flags); ++ ++ reg = readl(clk->pll_ctrl); ++ reg &= ~(PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK); ++ writel(reg, clk->pll_ctrl); ++ while (!(readl(clk->pll_status) & (1 << clk->lockbit))) ++ ; ++ ++ spin_unlock_irqrestore(clk->lock, flags); ++ ++ return 0; ++} ++ ++/** ++ * zynq_pll_disable - Disable clock ++ * @hw: Handle between common and hardware-specific interfaces ++ * Returns 0 on success ++ */ ++static void zynq_pll_disable(struct clk_hw *hw) ++{ ++ unsigned long flags = 0; ++ u32 reg; ++ struct zynq_pll *clk = to_zynq_pll(hw); ++ ++ if (!zynq_pll_is_enabled(hw)) ++ return; ++ ++ pr_info("PLL: shutdown\n"); ++ ++ /* shut down PLL */ ++ spin_lock_irqsave(clk->lock, flags); ++ ++ reg = readl(clk->pll_ctrl); ++ reg |= PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK; ++ writel(reg, clk->pll_ctrl); ++ ++ spin_unlock_irqrestore(clk->lock, flags); ++} ++ ++static const struct clk_ops zynq_pll_ops = { ++ .enable = zynq_pll_enable, ++ .disable = zynq_pll_disable, ++ .is_enabled = zynq_pll_is_enabled, ++ .round_rate = zynq_pll_round_rate, ++ .recalc_rate = zynq_pll_recalc_rate ++}; ++ ++/** ++ * clk_register_zynq_pll() - Register PLL with the clock framework ++ * @name PLL name ++ * @parent Parent clock name ++ * @pll_ctrl Pointer to PLL control register ++ * @pll_status Pointer to PLL status register ++ * @lock_index Bit index to this PLL's lock status bit in @pll_status ++ * @lock Register lock ++ */ ++struct clk *clk_register_zynq_pll(const char *name, const char *parent, ++ void __iomem *pll_ctrl, void __iomem *pll_status, u8 lock_index, ++ spinlock_t *lock) ++{ ++ struct zynq_pll *pll; ++ struct clk *clk; ++ u32 reg; ++ const char *parent_arr[1] = {parent}; ++ unsigned long flags = 0; ++ struct clk_init_data initd = { ++ .name = name, ++ .parent_names = parent_arr, ++ .ops = &zynq_pll_ops, ++ .num_parents = 1, ++ .flags = 0 ++ }; ++ ++ pll = kmalloc(sizeof(*pll), GFP_KERNEL); ++ if (!pll) { ++ pr_err("%s: Could not allocate Zynq PLL clk.\n", __func__); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ /* Populate the struct */ ++ pll->hw.init = &initd; ++ pll->pll_ctrl = pll_ctrl; ++ pll->pll_status = pll_status; ++ pll->lockbit = lock_index; ++ pll->lock = lock; ++ ++ spin_lock_irqsave(pll->lock, flags); ++ ++ reg = readl(pll->pll_ctrl); ++ reg &= ~PLLCTRL_BPQUAL_MASK; ++ writel(reg, pll->pll_ctrl); ++ ++ spin_unlock_irqrestore(pll->lock, flags); ++ ++ clk = clk_register(NULL, &pll->hw); ++ if (WARN_ON(IS_ERR(clk))) ++ goto free_pll; ++ ++ return clk; ++ ++free_pll: ++ kfree(pll); ++ ++ return clk; ++} +diff --git a/drivers/cpufreq/zynq-cpufreq.c b/drivers/cpufreq/zynq-cpufreq.c +index a5c18ff..d53994f 100644 +--- a/drivers/cpufreq/zynq-cpufreq.c ++++ b/drivers/cpufreq/zynq-cpufreq.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -27,16 +28,6 @@ + #include + #include + +-#ifdef CONFIG_SMP +-struct lpj_info { +- unsigned long ref; +- unsigned int freq; +-}; +- +-static DEFINE_PER_CPU(struct lpj_info, lpj_ref); +-static struct lpj_info global_lpj_ref; +-#endif +- + static atomic_t freq_table_users = ATOMIC_INIT(0); + static struct cpufreq_frequency_table *freq_table; + static struct device *mpu_dev; +@@ -68,6 +59,11 @@ static int zynq_target(struct cpufreq_policy *policy, + int ret = 0; + struct cpufreq_freqs freqs; + ++#ifdef CONFIG_SUSPEND ++ if (zynq_clk_suspended) ++ return -EPERM; ++#endif ++ + if (!freq_table) { + dev_err(mpu_dev, "%s: cpu%d: no freq table!\n", __func__, + policy->cpu); +@@ -106,31 +102,6 @@ static int zynq_target(struct cpufreq_policy *policy, + ret = clk_set_rate(cpuclk, freqs.new * 1000); + + freqs.new = zynq_getspeed(policy->cpu); +-#ifdef CONFIG_SMP +- /* +- * Note that loops_per_jiffy is not updated on SMP systems in +- * cpufreq driver. So, update the per-CPU loops_per_jiffy value +- * on frequency transition. We need to update all dependent CPUs. +- */ +- for_each_cpu(i, policy->cpus) { +- struct lpj_info *lpj = &per_cpu(lpj_ref, i); +- if (!lpj->freq) { +- lpj->ref = per_cpu(cpu_data, i).loops_per_jiffy; +- lpj->freq = freqs.old; +- } +- +- per_cpu(cpu_data, i).loops_per_jiffy = +- cpufreq_scale(lpj->ref, lpj->freq, freqs.new); +- } +- +- /* And don't forget to adjust the global one */ +- if (!global_lpj_ref.freq) { +- global_lpj_ref.ref = loops_per_jiffy; +- global_lpj_ref.freq = freqs.old; +- } +- loops_per_jiffy = cpufreq_scale(global_lpj_ref.ref, global_lpj_ref.freq, +- freqs.new); +-#endif + + /* notifiers */ + for_each_cpu(i, policy->cpus) { +@@ -151,9 +122,9 @@ static int __cpuinit zynq_cpu_init(struct cpufreq_policy *policy) + { + int result = 0; + +- cpuclk = clk_get_sys("CPU_6OR4X_CLK", NULL); ++ cpuclk = clk_get(NULL, "cpufreq_clk"); + if (IS_ERR(cpuclk)) { +- pr_warn("Xilinx: cpufreq: Clock not found."); ++ pr_warn("Xilinx: cpufreq: cpufreq_clk clock not found."); + return PTR_ERR(cpuclk); + } + +diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c +index c9303ed..0ca1ca7 100644 +--- a/drivers/edac/edac_mc_sysfs.c ++++ b/drivers/edac/edac_mc_sysfs.c +@@ -330,17 +330,17 @@ static struct device_attribute *dynamic_csrow_dimm_attr[] = { + }; + + /* possible dynamic channel ce_count attribute files */ +-DEVICE_CHANNEL(ch0_ce_count, S_IRUGO, ++DEVICE_CHANNEL(ch0_ce_count, S_IRUGO | S_IWUSR, + channel_ce_count_show, NULL, 0); +-DEVICE_CHANNEL(ch1_ce_count, S_IRUGO, ++DEVICE_CHANNEL(ch1_ce_count, S_IRUGO | S_IWUSR, + channel_ce_count_show, NULL, 1); +-DEVICE_CHANNEL(ch2_ce_count, S_IRUGO, ++DEVICE_CHANNEL(ch2_ce_count, S_IRUGO | S_IWUSR, + channel_ce_count_show, NULL, 2); +-DEVICE_CHANNEL(ch3_ce_count, S_IRUGO, ++DEVICE_CHANNEL(ch3_ce_count, S_IRUGO | S_IWUSR, + channel_ce_count_show, NULL, 3); +-DEVICE_CHANNEL(ch4_ce_count, S_IRUGO, ++DEVICE_CHANNEL(ch4_ce_count, S_IRUGO | S_IWUSR, + channel_ce_count_show, NULL, 4); +-DEVICE_CHANNEL(ch5_ce_count, S_IRUGO, ++DEVICE_CHANNEL(ch5_ce_count, S_IRUGO | S_IWUSR, + channel_ce_count_show, NULL, 5); + + /* Total possible dynamic ce_count attribute file table */ +diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c +index 529c488..edae963 100644 +--- a/drivers/gpio/gpio-sch.c ++++ b/drivers/gpio/gpio-sch.c +@@ -125,17 +125,13 @@ static int sch_gpio_resume_direction_in(struct gpio_chip *gc, + unsigned gpio_num) + { + u8 curr_dirs; +- unsigned short offset, bit; + + spin_lock(&gpio_lock); + +- offset = RGIO + gpio_num / 8; +- bit = gpio_num % 8; +- +- curr_dirs = inb(gpio_ba + offset); ++ curr_dirs = inb(gpio_ba + RGIO); + +- if (!(curr_dirs & (1 << bit))) +- outb(curr_dirs | (1 << bit) , gpio_ba + offset); ++ if (!(curr_dirs & (1 << gpio_num))) ++ outb(curr_dirs | (1 << gpio_num) , gpio_ba + RGIO); + + spin_unlock(&gpio_lock); + return 0; +@@ -143,31 +139,22 @@ static int sch_gpio_resume_direction_in(struct gpio_chip *gc, + + static int sch_gpio_resume_get(struct gpio_chip *gc, unsigned gpio_num) + { +- unsigned short offset, bit; +- +- offset = RGLV + gpio_num / 8; +- bit = gpio_num % 8; +- +- return !!(inb(gpio_ba + offset) & (1 << bit)); ++ return !!(inb(gpio_ba + RGLV) & (1 << gpio_num)); + } + + static void sch_gpio_resume_set(struct gpio_chip *gc, + unsigned gpio_num, int val) + { + u8 curr_vals; +- unsigned short offset, bit; + + spin_lock(&gpio_lock); + +- offset = RGLV + gpio_num / 8; +- bit = gpio_num % 8; +- +- curr_vals = inb(gpio_ba + offset); ++ curr_vals = inb(gpio_ba + RGLV); + + if (val) +- outb(curr_vals | (1 << bit), gpio_ba + offset); ++ outb(curr_vals | (1 << gpio_num), gpio_ba + RGLV); + else +- outb((curr_vals & ~(1 << bit)), gpio_ba + offset); ++ outb((curr_vals & ~(1 << gpio_num)), gpio_ba + RGLV); + + spin_unlock(&gpio_lock); + } +@@ -176,18 +163,14 @@ static int sch_gpio_resume_direction_out(struct gpio_chip *gc, + unsigned gpio_num, int val) + { + u8 curr_dirs; +- unsigned short offset, bit; + + sch_gpio_resume_set(gc, gpio_num, val); + +- offset = RGIO + gpio_num / 8; +- bit = gpio_num % 8; +- + spin_lock(&gpio_lock); + +- curr_dirs = inb(gpio_ba + offset); +- if (curr_dirs & (1 << bit)) +- outb(curr_dirs & ~(1 << bit), gpio_ba + offset); ++ curr_dirs = inb(gpio_ba + RGIO); ++ if (curr_dirs & (1 << gpio_num)) ++ outb(curr_dirs & ~(1 << gpio_num), gpio_ba + RGIO); + + spin_unlock(&gpio_lock); + return 0; +diff --git a/drivers/gpio/gpio-xilinxps.c b/drivers/gpio/gpio-xilinxps.c +index 8c51700..dbe0a9f 100644 +--- a/drivers/gpio/gpio-xilinxps.c ++++ b/drivers/gpio/gpio-xilinxps.c +@@ -426,8 +426,7 @@ static void xgpiops_irqhandler(unsigned int irq, struct irq_desc *desc) + generic_handle_irq(gpio_irq); + } + /* shift to first virtual irq of next bank */ +- gpio_irq = (int)irq_get_handler_data(irq) + +- (xgpiops_pin_table[bank_num] + 1); ++ gpio_irq = gpio->irq_base + xgpiops_pin_table[bank_num] + 1; + } + + chip = irq_desc_get_chip(desc); +@@ -628,9 +627,9 @@ static int xgpiops_probe(struct platform_device *pdev) + } + + /* Enable GPIO clock */ +- gpio->clk = clk_get_sys("GPIO_APER", NULL); ++ gpio->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(gpio->clk)) { +- dev_err(&pdev->dev, "Clock not found.\n"); ++ dev_err(&pdev->dev, "input clock not found.\n"); + ret = PTR_ERR(gpio->clk); + goto err_chip_remove; + } +diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h +index cac9c9a..5ccf984 100644 +--- a/drivers/gpu/drm/ast/ast_drv.h ++++ b/drivers/gpu/drm/ast/ast_drv.h +@@ -239,8 +239,6 @@ struct ast_fbdev { + void *sysram; + int size; + struct ttm_bo_kmap_obj mapping; +- int x1, y1, x2, y2; /* dirty rect */ +- spinlock_t dirty_lock; + }; + + #define to_ast_crtc(x) container_of(x, struct ast_crtc, base) +diff --git a/drivers/gpu/drm/ast/ast_fb.c b/drivers/gpu/drm/ast/ast_fb.c +index 9138678..d9ec779 100644 +--- a/drivers/gpu/drm/ast/ast_fb.c ++++ b/drivers/gpu/drm/ast/ast_fb.c +@@ -52,52 +52,16 @@ static void ast_dirty_update(struct ast_fbdev *afbdev, + int bpp = (afbdev->afb.base.bits_per_pixel + 7)/8; + int ret; + bool unmap = false; +- bool store_for_later = false; +- int x2, y2; +- unsigned long flags; + + obj = afbdev->afb.obj; + bo = gem_to_ast_bo(obj); + +- /* +- * try and reserve the BO, if we fail with busy +- * then the BO is being moved and we should +- * store up the damage until later. +- */ + ret = ast_bo_reserve(bo, true); + if (ret) { +- if (ret != -EBUSY) +- return; +- +- store_for_later = true; +- } +- +- x2 = x + width - 1; +- y2 = y + height - 1; +- spin_lock_irqsave(&afbdev->dirty_lock, flags); +- +- if (afbdev->y1 < y) +- y = afbdev->y1; +- if (afbdev->y2 > y2) +- y2 = afbdev->y2; +- if (afbdev->x1 < x) +- x = afbdev->x1; +- if (afbdev->x2 > x2) +- x2 = afbdev->x2; +- +- if (store_for_later) { +- afbdev->x1 = x; +- afbdev->x2 = x2; +- afbdev->y1 = y; +- afbdev->y2 = y2; +- spin_unlock_irqrestore(&afbdev->dirty_lock, flags); ++ DRM_ERROR("failed to reserve fb bo\n"); + return; + } + +- afbdev->x1 = afbdev->y1 = INT_MAX; +- afbdev->x2 = afbdev->y2 = 0; +- spin_unlock_irqrestore(&afbdev->dirty_lock, flags); +- + if (!bo->kmap.virtual) { + ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); + if (ret) { +@@ -107,10 +71,10 @@ static void ast_dirty_update(struct ast_fbdev *afbdev, + } + unmap = true; + } +- for (i = y; i <= y2; i++) { ++ for (i = y; i < y + height; i++) { + /* assume equal stride for now */ + src_offset = dst_offset = i * afbdev->afb.base.pitches[0] + (x * bpp); +- memcpy_toio(bo->kmap.virtual + src_offset, afbdev->sysram + src_offset, (x2 - x + 1) * bpp); ++ memcpy_toio(bo->kmap.virtual + src_offset, afbdev->sysram + src_offset, width * bpp); + + } + if (unmap) +@@ -341,7 +305,6 @@ int ast_fbdev_init(struct drm_device *dev) + + ast->fbdev = afbdev; + afbdev->helper.funcs = &ast_fb_helper_funcs; +- spin_lock_init(&afbdev->dirty_lock); + ret = drm_fb_helper_init(dev, &afbdev->helper, + 1, 1); + if (ret) { +diff --git a/drivers/gpu/drm/ast/ast_ttm.c b/drivers/gpu/drm/ast/ast_ttm.c +index 09da339..3602731 100644 +--- a/drivers/gpu/drm/ast/ast_ttm.c ++++ b/drivers/gpu/drm/ast/ast_ttm.c +@@ -316,7 +316,7 @@ int ast_bo_reserve(struct ast_bo *bo, bool no_wait) + + ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0); + if (ret) { +- if (ret != -ERESTARTSYS && ret != -EBUSY) ++ if (ret != -ERESTARTSYS) + DRM_ERROR("reserve failed %p\n", bo); + return ret; + } +diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.h b/drivers/gpu/drm/cirrus/cirrus_drv.h +index 7ca0595..6e0cc72 100644 +--- a/drivers/gpu/drm/cirrus/cirrus_drv.h ++++ b/drivers/gpu/drm/cirrus/cirrus_drv.h +@@ -154,8 +154,6 @@ struct cirrus_fbdev { + struct list_head fbdev_list; + void *sysram; + int size; +- int x1, y1, x2, y2; /* dirty rect */ +- spinlock_t dirty_lock; + }; + + struct cirrus_bo { +diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c +index 1e64d6f..6c6b4c8 100644 +--- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c ++++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c +@@ -26,51 +26,16 @@ static void cirrus_dirty_update(struct cirrus_fbdev *afbdev, + int bpp = (afbdev->gfb.base.bits_per_pixel + 7)/8; + int ret; + bool unmap = false; +- bool store_for_later = false; +- int x2, y2; +- unsigned long flags; + + obj = afbdev->gfb.obj; + bo = gem_to_cirrus_bo(obj); + +- /* +- * try and reserve the BO, if we fail with busy +- * then the BO is being moved and we should +- * store up the damage until later. +- */ + ret = cirrus_bo_reserve(bo, true); + if (ret) { +- if (ret != -EBUSY) +- return; +- store_for_later = true; +- } +- +- x2 = x + width - 1; +- y2 = y + height - 1; +- spin_lock_irqsave(&afbdev->dirty_lock, flags); +- +- if (afbdev->y1 < y) +- y = afbdev->y1; +- if (afbdev->y2 > y2) +- y2 = afbdev->y2; +- if (afbdev->x1 < x) +- x = afbdev->x1; +- if (afbdev->x2 > x2) +- x2 = afbdev->x2; +- +- if (store_for_later) { +- afbdev->x1 = x; +- afbdev->x2 = x2; +- afbdev->y1 = y; +- afbdev->y2 = y2; +- spin_unlock_irqrestore(&afbdev->dirty_lock, flags); ++ DRM_ERROR("failed to reserve fb bo\n"); + return; + } + +- afbdev->x1 = afbdev->y1 = INT_MAX; +- afbdev->x2 = afbdev->y2 = 0; +- spin_unlock_irqrestore(&afbdev->dirty_lock, flags); +- + if (!bo->kmap.virtual) { + ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); + if (ret) { +@@ -317,7 +282,6 @@ int cirrus_fbdev_init(struct cirrus_device *cdev) + + cdev->mode_info.gfbdev = gfbdev; + gfbdev->helper.funcs = &cirrus_fb_helper_funcs; +- spin_lock_init(&gfbdev->dirty_lock); + + ret = drm_fb_helper_init(cdev->dev, &gfbdev->helper, + cdev->num_crtc, CIRRUSFB_CONN_LIMIT); +diff --git a/drivers/gpu/drm/cirrus/cirrus_ttm.c b/drivers/gpu/drm/cirrus/cirrus_ttm.c +index 2ed8cfc..1413a26 100644 +--- a/drivers/gpu/drm/cirrus/cirrus_ttm.c ++++ b/drivers/gpu/drm/cirrus/cirrus_ttm.c +@@ -321,7 +321,7 @@ int cirrus_bo_reserve(struct cirrus_bo *bo, bool no_wait) + + ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0); + if (ret) { +- if (ret != -ERESTARTSYS && ret != -EBUSY) ++ if (ret != -ERESTARTSYS) + DRM_ERROR("reserve failed %p\n", bo); + return ret; + } +diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c +index 539bae9..24efae4 100644 +--- a/drivers/gpu/drm/drm_gem.c ++++ b/drivers/gpu/drm/drm_gem.c +@@ -205,11 +205,11 @@ static void + drm_gem_remove_prime_handles(struct drm_gem_object *obj, struct drm_file *filp) + { + if (obj->import_attach) { +- drm_prime_remove_buf_handle(&filp->prime, ++ drm_prime_remove_imported_buf_handle(&filp->prime, + obj->import_attach->dmabuf); + } + if (obj->export_dma_buf) { +- drm_prime_remove_buf_handle(&filp->prime, ++ drm_prime_remove_imported_buf_handle(&filp->prime, + obj->export_dma_buf); + } + } +diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c +index 4f6439d..7f12573 100644 +--- a/drivers/gpu/drm/drm_prime.c ++++ b/drivers/gpu/drm/drm_prime.c +@@ -61,7 +61,6 @@ struct drm_prime_member { + struct dma_buf *dma_buf; + uint32_t handle; + }; +-static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle); + + int drm_gem_prime_handle_to_fd(struct drm_device *dev, + struct drm_file *file_priv, uint32_t handle, uint32_t flags, +@@ -69,8 +68,7 @@ int drm_gem_prime_handle_to_fd(struct drm_device *dev, + { + struct drm_gem_object *obj; + void *buf; +- int ret = 0; +- struct dma_buf *dmabuf; ++ int ret; + + obj = drm_gem_object_lookup(dev, file_priv, handle); + if (!obj) +@@ -79,44 +77,43 @@ int drm_gem_prime_handle_to_fd(struct drm_device *dev, + mutex_lock(&file_priv->prime.lock); + /* re-export the original imported object */ + if (obj->import_attach) { +- dmabuf = obj->import_attach->dmabuf; +- goto out_have_obj; ++ get_dma_buf(obj->import_attach->dmabuf); ++ *prime_fd = dma_buf_fd(obj->import_attach->dmabuf, flags); ++ drm_gem_object_unreference_unlocked(obj); ++ mutex_unlock(&file_priv->prime.lock); ++ return 0; + } + + if (obj->export_dma_buf) { +- dmabuf = obj->export_dma_buf; +- goto out_have_obj; +- } +- +- buf = dev->driver->gem_prime_export(dev, obj, flags); +- if (IS_ERR(buf)) { +- /* normally the created dma-buf takes ownership of the ref, +- * but if that fails then drop the ref +- */ +- ret = PTR_ERR(buf); +- goto out; ++ get_dma_buf(obj->export_dma_buf); ++ *prime_fd = dma_buf_fd(obj->export_dma_buf, flags); ++ drm_gem_object_unreference_unlocked(obj); ++ } else { ++ buf = dev->driver->gem_prime_export(dev, obj, flags); ++ if (IS_ERR(buf)) { ++ /* normally the created dma-buf takes ownership of the ref, ++ * but if that fails then drop the ref ++ */ ++ drm_gem_object_unreference_unlocked(obj); ++ mutex_unlock(&file_priv->prime.lock); ++ return PTR_ERR(buf); ++ } ++ obj->export_dma_buf = buf; ++ *prime_fd = dma_buf_fd(buf, flags); + } +- obj->export_dma_buf = buf; +- + /* if we've exported this buffer the cheat and add it to the import list + * so we get the correct handle back + */ +- ret = drm_prime_add_buf_handle(&file_priv->prime, +- obj->export_dma_buf, handle); +- if (ret) +- goto out; ++ ret = drm_prime_add_imported_buf_handle(&file_priv->prime, ++ obj->export_dma_buf, handle); ++ if (ret) { ++ drm_gem_object_unreference_unlocked(obj); ++ mutex_unlock(&file_priv->prime.lock); ++ return ret; ++ } + +- *prime_fd = dma_buf_fd(buf, flags); + mutex_unlock(&file_priv->prime.lock); + return 0; +- +-out_have_obj: +- get_dma_buf(dmabuf); +- *prime_fd = dma_buf_fd(dmabuf, flags); +-out: +- drm_gem_object_unreference_unlocked(obj); +- mutex_unlock(&file_priv->prime.lock); +- return ret; + } + EXPORT_SYMBOL(drm_gem_prime_handle_to_fd); + +@@ -133,7 +130,7 @@ int drm_gem_prime_fd_to_handle(struct drm_device *dev, + + mutex_lock(&file_priv->prime.lock); + +- ret = drm_prime_lookup_buf_handle(&file_priv->prime, ++ ret = drm_prime_lookup_imported_buf_handle(&file_priv->prime, + dma_buf, handle); + if (!ret) { + ret = 0; +@@ -152,7 +149,7 @@ int drm_gem_prime_fd_to_handle(struct drm_device *dev, + if (ret) + goto out_put; + +- ret = drm_prime_add_buf_handle(&file_priv->prime, ++ ret = drm_prime_add_imported_buf_handle(&file_priv->prime, + dma_buf, *handle); + if (ret) + goto fail; +@@ -310,7 +307,7 @@ void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv) + } + EXPORT_SYMBOL(drm_prime_destroy_file_private); + +-static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle) ++int drm_prime_add_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle) + { + struct drm_prime_member *member; + +@@ -318,14 +315,14 @@ static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv, + if (!member) + return -ENOMEM; + +- get_dma_buf(dma_buf); + member->dma_buf = dma_buf; + member->handle = handle; + list_add(&member->entry, &prime_fpriv->head); + return 0; + } ++EXPORT_SYMBOL(drm_prime_add_imported_buf_handle); + +-int drm_prime_lookup_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t *handle) ++int drm_prime_lookup_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t *handle) + { + struct drm_prime_member *member; + +@@ -337,20 +334,19 @@ int drm_prime_lookup_buf_handle(struct drm_prime_file_private *prime_fpriv, stru + } + return -ENOENT; + } +-EXPORT_SYMBOL(drm_prime_lookup_buf_handle); ++EXPORT_SYMBOL(drm_prime_lookup_imported_buf_handle); + +-void drm_prime_remove_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf) ++void drm_prime_remove_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf) + { + struct drm_prime_member *member, *safe; + + mutex_lock(&prime_fpriv->lock); + list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) { + if (member->dma_buf == dma_buf) { +- dma_buf_put(dma_buf); + list_del(&member->entry); + kfree(member); + } + } + mutex_unlock(&prime_fpriv->lock); + } +-EXPORT_SYMBOL(drm_prime_remove_buf_handle); ++EXPORT_SYMBOL(drm_prime_remove_imported_buf_handle); +diff --git a/drivers/gpu/drm/gma500/psb_irq.c b/drivers/gpu/drm/gma500/psb_irq.c +index 029eccf..8652cdf 100644 +--- a/drivers/gpu/drm/gma500/psb_irq.c ++++ b/drivers/gpu/drm/gma500/psb_irq.c +@@ -211,7 +211,7 @@ irqreturn_t psb_irq_handler(DRM_IRQ_ARGS) + + vdc_stat = PSB_RVDC32(PSB_INT_IDENTITY_R); + +- if (vdc_stat & (_PSB_PIPE_EVENT_FLAG|_PSB_IRQ_ASLE)) ++ if (vdc_stat & _PSB_PIPE_EVENT_FLAG) + dsp_int = 1; + + /* FIXME: Handle Medfield +diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h +index e78419f..7339a4b 100644 +--- a/drivers/gpu/drm/i915/i915_drv.h ++++ b/drivers/gpu/drm/i915/i915_drv.h +@@ -711,7 +711,6 @@ typedef struct drm_i915_private { + unsigned int int_crt_support:1; + unsigned int lvds_use_ssc:1; + unsigned int display_clock_mode:1; +- unsigned int fdi_rx_polarity_inverted:1; + int lvds_ssc_freq; + unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */ + unsigned int lvds_val; /* used for checking LVDS channel mode */ +@@ -775,7 +774,6 @@ typedef struct drm_i915_private { + unsigned long gtt_start; + unsigned long gtt_mappable_end; + unsigned long gtt_end; +- unsigned long stolen_base; /* limited to low memory (32-bit) */ + + struct io_mapping *gtt_mapping; + phys_addr_t gtt_base_addr; +diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c +index 3b9d18b..de45b60 100644 +--- a/drivers/gpu/drm/i915/i915_gem.c ++++ b/drivers/gpu/drm/i915/i915_gem.c +@@ -2662,35 +2662,17 @@ static inline int fence_number(struct drm_i915_private *dev_priv, + return fence - dev_priv->fence_regs; + } + +-static void i915_gem_write_fence__ipi(void *data) +-{ +- wbinvd(); +-} +- + static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj, + struct drm_i915_fence_reg *fence, + bool enable) + { +- struct drm_device *dev = obj->base.dev; +- struct drm_i915_private *dev_priv = dev->dev_private; +- int fence_reg = fence_number(dev_priv, fence); +- +- /* In order to fully serialize access to the fenced region and +- * the update to the fence register we need to take extreme +- * measures on SNB+. In theory, the write to the fence register +- * flushes all memory transactions before, and coupled with the +- * mb() placed around the register write we serialise all memory +- * operations with respect to the changes in the tiler. Yet, on +- * SNB+ we need to take a step further and emit an explicit wbinvd() +- * on each processor in order to manually flush all memory +- * transactions before updating the fence register. +- */ +- if (HAS_LLC(obj->base.dev)) +- on_each_cpu(i915_gem_write_fence__ipi, NULL, 1); +- i915_gem_write_fence(dev, fence_reg, enable ? obj : NULL); ++ struct drm_i915_private *dev_priv = obj->base.dev->dev_private; ++ int reg = fence_number(dev_priv, fence); ++ ++ i915_gem_write_fence(obj->base.dev, reg, enable ? obj : NULL); + + if (enable) { +- obj->fence_reg = fence_reg; ++ obj->fence_reg = reg; + fence->obj = obj; + list_move_tail(&fence->lru_list, &dev_priv->mm.fence_list); + } else { +diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c +index d8ac0a3..a3f06bc 100644 +--- a/drivers/gpu/drm/i915/i915_gem_context.c ++++ b/drivers/gpu/drm/i915/i915_gem_context.c +@@ -157,13 +157,6 @@ create_hw_context(struct drm_device *dev, + return ERR_PTR(-ENOMEM); + } + +- if (INTEL_INFO(dev)->gen >= 7) { +- ret = i915_gem_object_set_cache_level(ctx->obj, +- I915_CACHE_LLC_MLC); +- if (ret) +- goto err_out; +- } +- + /* The ring associated with the context object is handled by the normal + * object tracking code. We give an initial ring value simple to pass an + * assertion in the context switch code. +diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c +index be24312..8e91083 100644 +--- a/drivers/gpu/drm/i915/i915_gem_stolen.c ++++ b/drivers/gpu/drm/i915/i915_gem_stolen.c +@@ -42,50 +42,56 @@ + * for is a boon. + */ + +-static unsigned long i915_stolen_to_physical(struct drm_device *dev) ++#define PTE_ADDRESS_MASK 0xfffff000 ++#define PTE_ADDRESS_MASK_HIGH 0x000000f0 /* i915+ */ ++#define PTE_MAPPING_TYPE_UNCACHED (0 << 1) ++#define PTE_MAPPING_TYPE_DCACHE (1 << 1) /* i830 only */ ++#define PTE_MAPPING_TYPE_CACHED (3 << 1) ++#define PTE_MAPPING_TYPE_MASK (3 << 1) ++#define PTE_VALID (1 << 0) ++ ++/** ++ * i915_stolen_to_phys - take an offset into stolen memory and turn it into ++ * a physical one ++ * @dev: drm device ++ * @offset: address to translate ++ * ++ * Some chip functions require allocations from stolen space and need the ++ * physical address of the memory in question. ++ */ ++static unsigned long i915_stolen_to_phys(struct drm_device *dev, u32 offset) + { + struct drm_i915_private *dev_priv = dev->dev_private; + struct pci_dev *pdev = dev_priv->bridge_dev; + u32 base; + ++#if 0 + /* On the machines I have tested the Graphics Base of Stolen Memory +- * is unreliable, so on those compute the base by subtracting the +- * stolen memory from the Top of Low Usable DRAM which is where the +- * BIOS places the graphics stolen memory. +- * +- * On gen2, the layout is slightly different with the Graphics Segment +- * immediately following Top of Memory (or Top of Usable DRAM). Note +- * it appears that TOUD is only reported by 865g, so we just use the +- * top of memory as determined by the e820 probe. +- * +- * XXX gen2 requires an unavailable symbol and 945gm fails with +- * its value of TOLUD. ++ * is unreliable, so compute the base by subtracting the stolen memory ++ * from the Top of Low Usable DRAM which is where the BIOS places ++ * the graphics stolen memory. + */ +- base = 0; +- if (INTEL_INFO(dev)->gen >= 6) { +- /* Read Base Data of Stolen Memory Register (BDSM) directly. +- * Note that there is also a MCHBAR miror at 0x1080c0 or +- * we could use device 2:0x5c instead. +- */ +- pci_read_config_dword(pdev, 0xB0, &base); +- base &= ~4095; /* lower bits used for locking register */ +- } else if (INTEL_INFO(dev)->gen > 3 || IS_G33(dev)) { +- /* Read Graphics Base of Stolen Memory directly */ ++ if (INTEL_INFO(dev)->gen > 3 || IS_G33(dev)) { ++ /* top 32bits are reserved = 0 */ + pci_read_config_dword(pdev, 0xA4, &base); +-#if 0 +- } else if (IS_GEN3(dev)) { ++ } else { ++ /* XXX presume 8xx is the same as i915 */ ++ pci_bus_read_config_dword(pdev->bus, 2, 0x5C, &base); ++ } ++#else ++ if (INTEL_INFO(dev)->gen > 3 || IS_G33(dev)) { ++ u16 val; ++ pci_read_config_word(pdev, 0xb0, &val); ++ base = val >> 4 << 20; ++ } else { + u8 val; +- /* Stolen is immediately below Top of Low Usable DRAM */ + pci_read_config_byte(pdev, 0x9c, &val); + base = val >> 3 << 27; +- base -= dev_priv->mm.gtt->stolen_size; +- } else { +- /* Stolen is immediately above Top of Memory */ +- base = max_low_pfn_mapped << PAGE_SHIFT; +-#endif + } ++ base -= dev_priv->mm.gtt->stolen_size; ++#endif + +- return base; ++ return base + offset; + } + + static void i915_warn_stolen(struct drm_device *dev) +@@ -110,7 +116,7 @@ static void i915_setup_compression(struct drm_device *dev, int size) + if (!compressed_fb) + goto err; + +- cfb_base = dev_priv->mm.stolen_base + compressed_fb->start; ++ cfb_base = i915_stolen_to_phys(dev, compressed_fb->start); + if (!cfb_base) + goto err_fb; + +@@ -123,7 +129,7 @@ static void i915_setup_compression(struct drm_device *dev, int size) + if (!compressed_llb) + goto err_fb; + +- ll_base = dev_priv->mm.stolen_base + compressed_llb->start; ++ ll_base = i915_stolen_to_phys(dev, compressed_llb->start); + if (!ll_base) + goto err_llb; + } +@@ -142,7 +148,7 @@ static void i915_setup_compression(struct drm_device *dev, int size) + } + + DRM_DEBUG_KMS("FBC base 0x%08lx, ll base 0x%08lx, size %dM\n", +- (long)cfb_base, (long)ll_base, size >> 20); ++ cfb_base, ll_base, size >> 20); + return; + + err_llb: +@@ -174,13 +180,6 @@ int i915_gem_init_stolen(struct drm_device *dev) + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long prealloc_size = dev_priv->mm.gtt->stolen_size; + +- dev_priv->mm.stolen_base = i915_stolen_to_physical(dev); +- if (dev_priv->mm.stolen_base == 0) +- return 0; +- +- DRM_DEBUG_KMS("found %d bytes of stolen memory at %08lx\n", +- dev_priv->mm.gtt->stolen_size, dev_priv->mm.stolen_base); +- + /* Basic memrange allocator for stolen space */ + drm_mm_init(&dev_priv->mm.stolen, 0, prealloc_size); + +diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h +index ce70f0a..2bfd05a 100644 +--- a/drivers/gpu/drm/i915/i915_reg.h ++++ b/drivers/gpu/drm/i915/i915_reg.h +@@ -3839,7 +3839,7 @@ + #define _TRANSB_CHICKEN2 0xf1064 + #define TRANS_CHICKEN2(pipe) _PIPE(pipe, _TRANSA_CHICKEN2, _TRANSB_CHICKEN2) + #define TRANS_CHICKEN2_TIMING_OVERRIDE (1<<31) +-#define TRANS_CHICKEN2_FDI_POLARITY_REVERSED (1<<29) ++ + + #define SOUTH_CHICKEN1 0xc2000 + #define FDIA_PHASE_SYNC_SHIFT_OVR 19 +diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c +index bd83391..55ffba1 100644 +--- a/drivers/gpu/drm/i915/intel_bios.c ++++ b/drivers/gpu/drm/i915/intel_bios.c +@@ -351,14 +351,12 @@ parse_general_features(struct drm_i915_private *dev_priv, + dev_priv->lvds_ssc_freq = + intel_bios_ssc_frequency(dev, general->ssc_freq); + dev_priv->display_clock_mode = general->display_clock_mode; +- dev_priv->fdi_rx_polarity_inverted = general->fdi_rx_polarity_inverted; +- DRM_DEBUG_KMS("BDB_GENERAL_FEATURES int_tv_support %d int_crt_support %d lvds_use_ssc %d lvds_ssc_freq %d display_clock_mode %d fdi_rx_polarity_inverted %d\n", ++ DRM_DEBUG_KMS("BDB_GENERAL_FEATURES int_tv_support %d int_crt_support %d lvds_use_ssc %d lvds_ssc_freq %d display_clock_mode %d\n", + dev_priv->int_tv_support, + dev_priv->int_crt_support, + dev_priv->lvds_use_ssc, + dev_priv->lvds_ssc_freq, +- dev_priv->display_clock_mode, +- dev_priv->fdi_rx_polarity_inverted); ++ dev_priv->display_clock_mode); + } + } + +diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h +index e088d6f..36e57f9 100644 +--- a/drivers/gpu/drm/i915/intel_bios.h ++++ b/drivers/gpu/drm/i915/intel_bios.h +@@ -127,9 +127,7 @@ struct bdb_general_features { + /* bits 3 */ + u8 disable_smooth_vision:1; + u8 single_dvi:1; +- u8 rsvd9:1; +- u8 fdi_rx_polarity_inverted:1; +- u8 rsvd10:4; /* finish byte */ ++ u8 rsvd9:6; /* finish byte */ + + /* bits 4 */ + u8 legacy_monitor_detect; +diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c +index faeaebc..d3f834a 100644 +--- a/drivers/gpu/drm/i915/intel_display.c ++++ b/drivers/gpu/drm/i915/intel_display.c +@@ -7732,25 +7732,22 @@ intel_modeset_affected_pipes(struct drm_crtc *crtc, unsigned *modeset_pipes, + if (crtc->enabled) + *prepare_pipes |= 1 << intel_crtc->pipe; + +- /* +- * For simplicity do a full modeset on any pipe where the output routing +- * changed. We could be more clever, but that would require us to be +- * more careful with calling the relevant encoder->mode_set functions. +- */ ++ /* We only support modeset on one single crtc, hence we need to do that ++ * only for the passed in crtc iff we change anything else than just ++ * disable crtcs. ++ * ++ * This is actually not true, to be fully compatible with the old crtc ++ * helper we automatically disable _any_ output (i.e. doesn't need to be ++ * connected to the crtc we're modesetting on) if it's disconnected. ++ * Which is a rather nutty api (since changed the output configuration ++ * without userspace's explicit request can lead to confusion), but ++ * alas. Hence we currently need to modeset on all pipes we prepare. */ + if (*prepare_pipes) + *modeset_pipes = *prepare_pipes; + + /* ... and mask these out. */ + *modeset_pipes &= ~(*disable_pipes); + *prepare_pipes &= ~(*disable_pipes); +- +- /* +- * HACK: We don't (yet) fully support global modesets. intel_set_config +- * obies this rule, but the modeset restore mode of +- * intel_modeset_setup_hw_state does not. +- */ +- *modeset_pipes &= 1 << intel_crtc->pipe; +- *prepare_pipes &= 1 << intel_crtc->pipe; + } + + static bool intel_crtc_in_use(struct drm_crtc *crtc) +@@ -9391,9 +9388,6 @@ void intel_modeset_cleanup(struct drm_device *dev) + /* flush any delayed tasks or pending work */ + flush_scheduled_work(); + +- /* destroy backlight, if any, before the connectors */ +- intel_panel_destroy_backlight(dev); +- + drm_mode_config_cleanup(dev); + } + +diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c +index cbe1ec3..73ce6e9 100644 +--- a/drivers/gpu/drm/i915/intel_dp.c ++++ b/drivers/gpu/drm/i915/intel_dp.c +@@ -2467,14 +2467,17 @@ done: + static void + intel_dp_destroy(struct drm_connector *connector) + { ++ struct drm_device *dev = connector->dev; + struct intel_dp *intel_dp = intel_attached_dp(connector); + struct intel_connector *intel_connector = to_intel_connector(connector); + + if (!IS_ERR_OR_NULL(intel_connector->edid)) + kfree(intel_connector->edid); + +- if (is_edp(intel_dp)) ++ if (is_edp(intel_dp)) { ++ intel_panel_destroy_backlight(dev); + intel_panel_fini(&intel_connector->panel); ++ } + + drm_sysfs_connector_remove(connector); + drm_connector_cleanup(connector); +diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c +index ba96e04..15da995 100644 +--- a/drivers/gpu/drm/i915/intel_dvo.c ++++ b/drivers/gpu/drm/i915/intel_dvo.c +@@ -449,7 +449,6 @@ void intel_dvo_init(struct drm_device *dev) + const struct intel_dvo_device *dvo = &intel_dvo_devices[i]; + struct i2c_adapter *i2c; + int gpio; +- bool dvoinit; + + /* Allow the I2C driver info to specify the GPIO to be used in + * special cases, but otherwise default to what's defined +@@ -469,17 +468,7 @@ void intel_dvo_init(struct drm_device *dev) + i2c = intel_gmbus_get_adapter(dev_priv, gpio); + + intel_dvo->dev = *dvo; +- +- /* GMBUS NAK handling seems to be unstable, hence let the +- * transmitter detection run in bit banging mode for now. +- */ +- intel_gmbus_force_bit(i2c, true); +- +- dvoinit = dvo->dev_ops->init(&intel_dvo->dev, i2c); +- +- intel_gmbus_force_bit(i2c, false); +- +- if (!dvoinit) ++ if (!dvo->dev_ops->init(&intel_dvo->dev, i2c)) + continue; + + intel_encoder->type = INTEL_OUTPUT_DVO; +diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c +index 8b383a6..17aee74 100644 +--- a/drivers/gpu/drm/i915/intel_lvds.c ++++ b/drivers/gpu/drm/i915/intel_lvds.c +@@ -556,6 +556,7 @@ static void intel_lvds_destroy(struct drm_connector *connector) + if (!IS_ERR_OR_NULL(lvds_connector->base.edid)) + kfree(lvds_connector->base.edid); + ++ intel_panel_destroy_backlight(connector->dev); + intel_panel_fini(&lvds_connector->base.panel); + + drm_sysfs_connector_remove(connector); +@@ -789,14 +790,6 @@ static const struct dmi_system_id intel_no_lvds[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "X7SPA-H"), + }, + }, +- { +- .callback = intel_no_lvds_dmi_callback, +- .ident = "Fujitsu Esprimo Q900", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), +- DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Q900"), +- }, +- }, + + { } /* terminating entry */ + }; +diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c +index 94d895b..bee8cb6 100644 +--- a/drivers/gpu/drm/i915/intel_panel.c ++++ b/drivers/gpu/drm/i915/intel_panel.c +@@ -422,9 +422,6 @@ int intel_panel_setup_backlight(struct drm_connector *connector) + + intel_panel_init_backlight(dev); + +- if (WARN_ON(dev_priv->backlight)) +- return -ENODEV; +- + memset(&props, 0, sizeof(props)); + props.type = BACKLIGHT_RAW; + props.max_brightness = _intel_panel_get_max_backlight(dev); +@@ -450,10 +447,8 @@ int intel_panel_setup_backlight(struct drm_connector *connector) + void intel_panel_destroy_backlight(struct drm_device *dev) + { + struct drm_i915_private *dev_priv = dev->dev_private; +- if (dev_priv->backlight) { ++ if (dev_priv->backlight) + backlight_device_unregister(dev_priv->backlight); +- dev_priv->backlight = NULL; +- } + } + #else + int intel_panel_setup_backlight(struct drm_connector *connector) +diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c +index 253bcf3..dde0ded 100644 +--- a/drivers/gpu/drm/i915/intel_pm.c ++++ b/drivers/gpu/drm/i915/intel_pm.c +@@ -3560,7 +3560,6 @@ static void cpt_init_clock_gating(struct drm_device *dev) + { + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe; +- uint32_t val; + + /* + * On Ibex Peak and Cougar Point, we need to disable clock +@@ -3573,12 +3572,8 @@ static void cpt_init_clock_gating(struct drm_device *dev) + /* The below fixes the weird display corruption, a few pixels shifted + * downward, on (only) LVDS of some HP laptops with IVY. + */ +- for_each_pipe(pipe) { +- val = TRANS_CHICKEN2_TIMING_OVERRIDE; +- if (dev_priv->fdi_rx_polarity_inverted) +- val |= TRANS_CHICKEN2_FDI_POLARITY_REVERSED; +- I915_WRITE(TRANS_CHICKEN2(pipe), val); +- } ++ for_each_pipe(pipe) ++ I915_WRITE(TRANS_CHICKEN2(pipe), TRANS_CHICKEN2_TIMING_OVERRIDE); + /* WADP0ClockGatingDisable */ + for_each_pipe(pipe) { + I915_WRITE(TRANS_CHICKEN1(pipe), +diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c +index 506c331..c275bf0 100644 +--- a/drivers/gpu/drm/i915/intel_sdvo.c ++++ b/drivers/gpu/drm/i915/intel_sdvo.c +@@ -1213,13 +1213,11 @@ static bool intel_sdvo_get_hw_state(struct intel_encoder *encoder, + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base); +- u16 active_outputs; + u32 tmp; + + tmp = I915_READ(intel_sdvo->sdvo_reg); +- intel_sdvo_get_active_outputs(intel_sdvo, &active_outputs); + +- if (!(tmp & SDVO_ENABLE) && (active_outputs == 0)) ++ if (!(tmp & SDVO_ENABLE)) + return false; + + if (HAS_PCH_CPT(dev)) +@@ -2706,6 +2704,7 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob) + struct intel_sdvo *intel_sdvo; + u32 hotplug_mask; + int i; ++ + intel_sdvo = kzalloc(sizeof(struct intel_sdvo), GFP_KERNEL); + if (!intel_sdvo) + return false; +diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h +index a657709..5ea5033 100644 +--- a/drivers/gpu/drm/mgag200/mgag200_drv.h ++++ b/drivers/gpu/drm/mgag200/mgag200_drv.h +@@ -116,8 +116,6 @@ struct mga_fbdev { + void *sysram; + int size; + struct ttm_bo_kmap_obj mapping; +- int x1, y1, x2, y2; /* dirty rect */ +- spinlock_t dirty_lock; + }; + + struct mga_crtc { +diff --git a/drivers/gpu/drm/mgag200/mgag200_fb.c b/drivers/gpu/drm/mgag200/mgag200_fb.c +index 41eefc4..2f48648 100644 +--- a/drivers/gpu/drm/mgag200/mgag200_fb.c ++++ b/drivers/gpu/drm/mgag200/mgag200_fb.c +@@ -28,52 +28,16 @@ static void mga_dirty_update(struct mga_fbdev *mfbdev, + int bpp = (mfbdev->mfb.base.bits_per_pixel + 7)/8; + int ret; + bool unmap = false; +- bool store_for_later = false; +- int x2, y2; +- unsigned long flags; + + obj = mfbdev->mfb.obj; + bo = gem_to_mga_bo(obj); + +- /* +- * try and reserve the BO, if we fail with busy +- * then the BO is being moved and we should +- * store up the damage until later. +- */ + ret = mgag200_bo_reserve(bo, true); + if (ret) { +- if (ret != -EBUSY) +- return; +- +- store_for_later = true; +- } +- +- x2 = x + width - 1; +- y2 = y + height - 1; +- spin_lock_irqsave(&mfbdev->dirty_lock, flags); +- +- if (mfbdev->y1 < y) +- y = mfbdev->y1; +- if (mfbdev->y2 > y2) +- y2 = mfbdev->y2; +- if (mfbdev->x1 < x) +- x = mfbdev->x1; +- if (mfbdev->x2 > x2) +- x2 = mfbdev->x2; +- +- if (store_for_later) { +- mfbdev->x1 = x; +- mfbdev->x2 = x2; +- mfbdev->y1 = y; +- mfbdev->y2 = y2; +- spin_unlock_irqrestore(&mfbdev->dirty_lock, flags); ++ DRM_ERROR("failed to reserve fb bo\n"); + return; + } + +- mfbdev->x1 = mfbdev->y1 = INT_MAX; +- mfbdev->x2 = mfbdev->y2 = 0; +- spin_unlock_irqrestore(&mfbdev->dirty_lock, flags); +- + if (!bo->kmap.virtual) { + ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); + if (ret) { +@@ -83,10 +47,10 @@ static void mga_dirty_update(struct mga_fbdev *mfbdev, + } + unmap = true; + } +- for (i = y; i <= y2; i++) { ++ for (i = y; i < y + height; i++) { + /* assume equal stride for now */ + src_offset = dst_offset = i * mfbdev->mfb.base.pitches[0] + (x * bpp); +- memcpy_toio(bo->kmap.virtual + src_offset, mfbdev->sysram + src_offset, (x2 - x + 1) * bpp); ++ memcpy_toio(bo->kmap.virtual + src_offset, mfbdev->sysram + src_offset, width * bpp); + + } + if (unmap) +@@ -305,7 +269,6 @@ int mgag200_fbdev_init(struct mga_device *mdev) + + mdev->mfbdev = mfbdev; + mfbdev->helper.funcs = &mga_fb_helper_funcs; +- spin_lock_init(&mfbdev->dirty_lock); + + ret = drm_fb_helper_init(mdev->dev, &mfbdev->helper, + mdev->num_crtc, MGAG200FB_CONN_LIMIT); +diff --git a/drivers/gpu/drm/mgag200/mgag200_ttm.c b/drivers/gpu/drm/mgag200/mgag200_ttm.c +index 401c989..8fc9d92 100644 +--- a/drivers/gpu/drm/mgag200/mgag200_ttm.c ++++ b/drivers/gpu/drm/mgag200/mgag200_ttm.c +@@ -315,8 +315,8 @@ int mgag200_bo_reserve(struct mgag200_bo *bo, bool no_wait) + + ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0); + if (ret) { +- if (ret != -ERESTARTSYS && ret != -EBUSY) +- DRM_ERROR("reserve failed %p %d\n", bo, ret); ++ if (ret != -ERESTARTSYS) ++ DRM_ERROR("reserve failed %p\n", bo); + return ret; + } + return 0; +diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c +index 43672b6..5ce9bf5 100644 +--- a/drivers/gpu/drm/radeon/atom.c ++++ b/drivers/gpu/drm/radeon/atom.c +@@ -1389,10 +1389,10 @@ int atom_allocate_fb_scratch(struct atom_context *ctx) + firmware_usage = (struct _ATOM_VRAM_USAGE_BY_FIRMWARE *)(ctx->bios + data_offset); + + DRM_DEBUG("atom firmware requested %08x %dkb\n", +- le32_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware), +- le16_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb)); ++ firmware_usage->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware, ++ firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb); + +- usage_bytes = le16_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb) * 1024; ++ usage_bytes = firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb * 1024; + } + ctx->scratch_size_bytes = 0; + if (usage_bytes == 0) +diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c +index 6d6fdb3..21a892c 100644 +--- a/drivers/gpu/drm/radeon/atombios_crtc.c ++++ b/drivers/gpu/drm/radeon/atombios_crtc.c +@@ -557,9 +557,6 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, + /* use frac fb div on APUs */ + if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev)) + radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; +- /* use frac fb div on RS780/RS880 */ +- if ((rdev->family == CHIP_RS780) || (rdev->family == CHIP_RS880)) +- radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; + if (ASIC_IS_DCE32(rdev) && mode->clock > 165000) + radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; + } else { +diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c +index 90dc470..1b0a4ec 100644 +--- a/drivers/gpu/drm/radeon/evergreen.c ++++ b/drivers/gpu/drm/radeon/evergreen.c +@@ -105,27 +105,6 @@ void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev) + } + } + +-static bool dce4_is_in_vblank(struct radeon_device *rdev, int crtc) +-{ +- if (RREG32(EVERGREEN_CRTC_STATUS + crtc_offsets[crtc]) & EVERGREEN_CRTC_V_BLANK) +- return true; +- else +- return false; +-} +- +-static bool dce4_is_counter_moving(struct radeon_device *rdev, int crtc) +-{ +- u32 pos1, pos2; +- +- pos1 = RREG32(EVERGREEN_CRTC_STATUS_POSITION + crtc_offsets[crtc]); +- pos2 = RREG32(EVERGREEN_CRTC_STATUS_POSITION + crtc_offsets[crtc]); +- +- if (pos1 != pos2) +- return true; +- else +- return false; +-} +- + /** + * dce4_wait_for_vblank - vblank wait asic callback. + * +@@ -136,28 +115,21 @@ static bool dce4_is_counter_moving(struct radeon_device *rdev, int crtc) + */ + void dce4_wait_for_vblank(struct radeon_device *rdev, int crtc) + { +- unsigned i = 0; ++ int i; + + if (crtc >= rdev->num_crtc) + return; + +- if (!(RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[crtc]) & EVERGREEN_CRTC_MASTER_EN)) +- return; +- +- /* depending on when we hit vblank, we may be close to active; if so, +- * wait for another frame. +- */ +- while (dce4_is_in_vblank(rdev, crtc)) { +- if (i++ % 100 == 0) { +- if (!dce4_is_counter_moving(rdev, crtc)) ++ if (RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[crtc]) & EVERGREEN_CRTC_MASTER_EN) { ++ for (i = 0; i < rdev->usec_timeout; i++) { ++ if (!(RREG32(EVERGREEN_CRTC_STATUS + crtc_offsets[crtc]) & EVERGREEN_CRTC_V_BLANK)) + break; ++ udelay(1); + } +- } +- +- while (!dce4_is_in_vblank(rdev, crtc)) { +- if (i++ % 100 == 0) { +- if (!dce4_is_counter_moving(rdev, crtc)) ++ for (i = 0; i < rdev->usec_timeout; i++) { ++ if (RREG32(EVERGREEN_CRTC_STATUS + crtc_offsets[crtc]) & EVERGREEN_CRTC_V_BLANK) + break; ++ udelay(1); + } + } + } +@@ -636,16 +608,6 @@ void evergreen_hpd_init(struct radeon_device *rdev) + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); +- +- if (connector->connector_type == DRM_MODE_CONNECTOR_eDP || +- connector->connector_type == DRM_MODE_CONNECTOR_LVDS) { +- /* don't try to enable hpd on eDP or LVDS avoid breaking the +- * aux dp channel on imac and help (but not completely fix) +- * https://bugzilla.redhat.com/show_bug.cgi?id=726143 +- * also avoid interrupt storms during dpms. +- */ +- continue; +- } + switch (radeon_connector->hpd.hpd) { + case RADEON_HPD_1: + WREG32(DC_HPD1_CONTROL, tmp); +@@ -1363,16 +1325,17 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav + tmp = RREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i]); + if (!(tmp & EVERGREEN_CRTC_BLANK_DATA_EN)) { + radeon_wait_for_vblank(rdev, i); +- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1); + tmp |= EVERGREEN_CRTC_BLANK_DATA_EN; ++ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1); + WREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i], tmp); ++ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0); + } + } else { + tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]); + if (!(tmp & EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE)) { + radeon_wait_for_vblank(rdev, i); +- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1); + tmp |= EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE; ++ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1); + WREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i], tmp); + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0); + } +@@ -1384,15 +1347,6 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav + break; + udelay(1); + } +- +- /* XXX this is a hack to avoid strange behavior with EFI on certain systems */ +- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1); +- tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]); +- tmp &= ~EVERGREEN_CRTC_MASTER_EN; +- WREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i], tmp); +- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0); +- save->crtc_enabled[i] = false; +- /* ***** */ + } else { + save->crtc_enabled[i] = false; + } +@@ -1410,22 +1364,6 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav + } + /* wait for the MC to settle */ + udelay(100); +- +- /* lock double buffered regs */ +- for (i = 0; i < rdev->num_crtc; i++) { +- if (save->crtc_enabled[i]) { +- tmp = RREG32(EVERGREEN_GRPH_UPDATE + crtc_offsets[i]); +- if (!(tmp & EVERGREEN_GRPH_UPDATE_LOCK)) { +- tmp |= EVERGREEN_GRPH_UPDATE_LOCK; +- WREG32(EVERGREEN_GRPH_UPDATE + crtc_offsets[i], tmp); +- } +- tmp = RREG32(EVERGREEN_MASTER_UPDATE_LOCK + crtc_offsets[i]); +- if (!(tmp & 1)) { +- tmp |= 1; +- WREG32(EVERGREEN_MASTER_UPDATE_LOCK + crtc_offsets[i], tmp); +- } +- } +- } + } + + void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save) +@@ -1447,33 +1385,6 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s + WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS_HIGH, upper_32_bits(rdev->mc.vram_start)); + WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS, (u32)rdev->mc.vram_start); + +- /* unlock regs and wait for update */ +- for (i = 0; i < rdev->num_crtc; i++) { +- if (save->crtc_enabled[i]) { +- tmp = RREG32(EVERGREEN_MASTER_UPDATE_MODE + crtc_offsets[i]); +- if ((tmp & 0x3) != 0) { +- tmp &= ~0x3; +- WREG32(EVERGREEN_MASTER_UPDATE_MODE + crtc_offsets[i], tmp); +- } +- tmp = RREG32(EVERGREEN_GRPH_UPDATE + crtc_offsets[i]); +- if (tmp & EVERGREEN_GRPH_UPDATE_LOCK) { +- tmp &= ~EVERGREEN_GRPH_UPDATE_LOCK; +- WREG32(EVERGREEN_GRPH_UPDATE + crtc_offsets[i], tmp); +- } +- tmp = RREG32(EVERGREEN_MASTER_UPDATE_LOCK + crtc_offsets[i]); +- if (tmp & 1) { +- tmp &= ~1; +- WREG32(EVERGREEN_MASTER_UPDATE_LOCK + crtc_offsets[i], tmp); +- } +- for (j = 0; j < rdev->usec_timeout; j++) { +- tmp = RREG32(EVERGREEN_GRPH_UPDATE + crtc_offsets[i]); +- if ((tmp & EVERGREEN_GRPH_SURFACE_UPDATE_PENDING) == 0) +- break; +- udelay(1); +- } +- } +- } +- + /* unblackout the MC */ + tmp = RREG32(MC_SHARED_BLACKOUT_CNTL); + tmp &= ~BLACKOUT_MODE_MASK; +diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h +index 3e9773a..034f4c2 100644 +--- a/drivers/gpu/drm/radeon/evergreen_reg.h ++++ b/drivers/gpu/drm/radeon/evergreen_reg.h +@@ -225,8 +225,6 @@ + #define EVERGREEN_CRTC_STATUS_POSITION 0x6e90 + #define EVERGREEN_MASTER_UPDATE_MODE 0x6ef8 + #define EVERGREEN_CRTC_UPDATE_LOCK 0x6ed4 +-#define EVERGREEN_MASTER_UPDATE_LOCK 0x6ef4 +-#define EVERGREEN_MASTER_UPDATE_MODE 0x6ef8 + + #define EVERGREEN_DC_GPIO_HPD_MASK 0x64b0 + #define EVERGREEN_DC_GPIO_HPD_A 0x64b4 +diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c +index 10e1bd1..b64e55d 100644 +--- a/drivers/gpu/drm/radeon/ni.c ++++ b/drivers/gpu/drm/radeon/ni.c +@@ -471,8 +471,7 @@ static void cayman_gpu_init(struct radeon_device *rdev) + (rdev->pdev->device == 0x990F) || + (rdev->pdev->device == 0x9910) || + (rdev->pdev->device == 0x9917) || +- (rdev->pdev->device == 0x9999) || +- (rdev->pdev->device == 0x999C)) { ++ (rdev->pdev->device == 0x9999)) { + rdev->config.cayman.max_simds_per_se = 6; + rdev->config.cayman.max_backends_per_se = 2; + } else if ((rdev->pdev->device == 0x9903) || +@@ -481,8 +480,7 @@ static void cayman_gpu_init(struct radeon_device *rdev) + (rdev->pdev->device == 0x990D) || + (rdev->pdev->device == 0x990E) || + (rdev->pdev->device == 0x9913) || +- (rdev->pdev->device == 0x9918) || +- (rdev->pdev->device == 0x999D)) { ++ (rdev->pdev->device == 0x9918)) { + rdev->config.cayman.max_simds_per_se = 4; + rdev->config.cayman.max_backends_per_se = 2; + } else if ((rdev->pdev->device == 0x9919) || +@@ -621,8 +619,6 @@ static void cayman_gpu_init(struct radeon_device *rdev) + + WREG32(GB_ADDR_CONFIG, gb_addr_config); + WREG32(DMIF_ADDR_CONFIG, gb_addr_config); +- if (ASIC_IS_DCE6(rdev)) +- WREG32(DMIF_ADDR_CALC, gb_addr_config); + WREG32(HDP_ADDR_CONFIG, gb_addr_config); + WREG32(DMA_TILING_CONFIG + DMA0_REGISTER_OFFSET, gb_addr_config); + WREG32(DMA_TILING_CONFIG + DMA1_REGISTER_OFFSET, gb_addr_config); +diff --git a/drivers/gpu/drm/radeon/nid.h b/drivers/gpu/drm/radeon/nid.h +index e045f8c..48e5022 100644 +--- a/drivers/gpu/drm/radeon/nid.h ++++ b/drivers/gpu/drm/radeon/nid.h +@@ -45,10 +45,6 @@ + #define ARUBA_GB_ADDR_CONFIG_GOLDEN 0x12010001 + + #define DMIF_ADDR_CONFIG 0xBD4 +- +-/* DCE6 only */ +-#define DMIF_ADDR_CALC 0xC00 +- + #define SRBM_GFX_CNTL 0x0E44 + #define RINGID(x) (((x) & 0x3) << 0) + #define VMID(x) (((x) & 0x7) << 0) +diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c +index 62719ec..8ff7cac 100644 +--- a/drivers/gpu/drm/radeon/r100.c ++++ b/drivers/gpu/drm/radeon/r100.c +@@ -69,38 +69,6 @@ MODULE_FIRMWARE(FIRMWARE_R520); + * and others in some cases. + */ + +-static bool r100_is_in_vblank(struct radeon_device *rdev, int crtc) +-{ +- if (crtc == 0) { +- if (RREG32(RADEON_CRTC_STATUS) & RADEON_CRTC_VBLANK_CUR) +- return true; +- else +- return false; +- } else { +- if (RREG32(RADEON_CRTC2_STATUS) & RADEON_CRTC2_VBLANK_CUR) +- return true; +- else +- return false; +- } +-} +- +-static bool r100_is_counter_moving(struct radeon_device *rdev, int crtc) +-{ +- u32 vline1, vline2; +- +- if (crtc == 0) { +- vline1 = (RREG32(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL; +- vline2 = (RREG32(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL; +- } else { +- vline1 = (RREG32(RADEON_CRTC2_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL; +- vline2 = (RREG32(RADEON_CRTC2_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL; +- } +- if (vline1 != vline2) +- return true; +- else +- return false; +-} +- + /** + * r100_wait_for_vblank - vblank wait asic callback. + * +@@ -111,33 +79,36 @@ static bool r100_is_counter_moving(struct radeon_device *rdev, int crtc) + */ + void r100_wait_for_vblank(struct radeon_device *rdev, int crtc) + { +- unsigned i = 0; ++ int i; + + if (crtc >= rdev->num_crtc) + return; + + if (crtc == 0) { +- if (!(RREG32(RADEON_CRTC_GEN_CNTL) & RADEON_CRTC_EN)) +- return; +- } else { +- if (!(RREG32(RADEON_CRTC2_GEN_CNTL) & RADEON_CRTC2_EN)) +- return; +- } +- +- /* depending on when we hit vblank, we may be close to active; if so, +- * wait for another frame. +- */ +- while (r100_is_in_vblank(rdev, crtc)) { +- if (i++ % 100 == 0) { +- if (!r100_is_counter_moving(rdev, crtc)) +- break; ++ if (RREG32(RADEON_CRTC_GEN_CNTL) & RADEON_CRTC_EN) { ++ for (i = 0; i < rdev->usec_timeout; i++) { ++ if (!(RREG32(RADEON_CRTC_STATUS) & RADEON_CRTC_VBLANK_CUR)) ++ break; ++ udelay(1); ++ } ++ for (i = 0; i < rdev->usec_timeout; i++) { ++ if (RREG32(RADEON_CRTC_STATUS) & RADEON_CRTC_VBLANK_CUR) ++ break; ++ udelay(1); ++ } + } +- } +- +- while (!r100_is_in_vblank(rdev, crtc)) { +- if (i++ % 100 == 0) { +- if (!r100_is_counter_moving(rdev, crtc)) +- break; ++ } else { ++ if (RREG32(RADEON_CRTC2_GEN_CNTL) & RADEON_CRTC2_EN) { ++ for (i = 0; i < rdev->usec_timeout; i++) { ++ if (!(RREG32(RADEON_CRTC2_STATUS) & RADEON_CRTC2_VBLANK_CUR)) ++ break; ++ udelay(1); ++ } ++ for (i = 0; i < rdev->usec_timeout; i++) { ++ if (RREG32(RADEON_CRTC2_STATUS) & RADEON_CRTC2_VBLANK_CUR) ++ break; ++ udelay(1); ++ } + } + } + } +diff --git a/drivers/gpu/drm/radeon/r500_reg.h b/drivers/gpu/drm/radeon/r500_reg.h +index 8ec2376..ec576aa 100644 +--- a/drivers/gpu/drm/radeon/r500_reg.h ++++ b/drivers/gpu/drm/radeon/r500_reg.h +@@ -357,9 +357,7 @@ + #define AVIVO_D1CRTC_FRAME_COUNT 0x60a4 + #define AVIVO_D1CRTC_STEREO_CONTROL 0x60c4 + +-#define AVIVO_D1MODE_MASTER_UPDATE_LOCK 0x60e0 + #define AVIVO_D1MODE_MASTER_UPDATE_MODE 0x60e4 +-#define AVIVO_D1CRTC_UPDATE_LOCK 0x60e8 + + /* master controls */ + #define AVIVO_DC_CRTC_MASTER_EN 0x60f8 +diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c +index d89a1f8..95970ec 100644 +--- a/drivers/gpu/drm/radeon/r600_hdmi.c ++++ b/drivers/gpu/drm/radeon/r600_hdmi.c +@@ -489,7 +489,7 @@ void r600_hdmi_enable(struct drm_encoder *encoder) + offset = dig->afmt->offset; + + /* Older chipsets require setting HDMI and routing manually */ +- if (ASIC_IS_DCE2(rdev) && !ASIC_IS_DCE3(rdev)) { ++ if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) { + hdmi = HDMI0_ERROR_ACK | HDMI0_ENABLE; + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: +@@ -557,7 +557,7 @@ void r600_hdmi_disable(struct drm_encoder *encoder) + radeon_irq_kms_disable_afmt(rdev, dig->afmt->id); + + /* Older chipsets not handled by AtomBIOS */ +- if (ASIC_IS_DCE2(rdev) && !ASIC_IS_DCE3(rdev)) { ++ if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) { + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + WREG32_P(AVIVO_TMDSA_CNTL, 0, +diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c +index 96168ef..f22eb57 100644 +--- a/drivers/gpu/drm/radeon/radeon_atombios.c ++++ b/drivers/gpu/drm/radeon/radeon_atombios.c +@@ -2028,8 +2028,6 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev) + num_modes = power_info->info.ucNumOfPowerModeEntries; + if (num_modes > ATOM_MAX_NUMBEROF_POWER_BLOCK) + num_modes = ATOM_MAX_NUMBEROF_POWER_BLOCK; +- if (num_modes == 0) +- return state_index; + rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) * num_modes, GFP_KERNEL); + if (!rdev->pm.power_state) + return state_index; +@@ -2434,8 +2432,6 @@ static int radeon_atombios_parse_power_table_4_5(struct radeon_device *rdev) + power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); + + radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController); +- if (power_info->pplib.ucNumStates == 0) +- return state_index; + rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) * + power_info->pplib.ucNumStates, GFP_KERNEL); + if (!rdev->pm.power_state) +@@ -2518,7 +2514,6 @@ static int radeon_atombios_parse_power_table_6(struct radeon_device *rdev) + int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); + u16 data_offset; + u8 frev, crev; +- u8 *power_state_offset; + + if (!atom_parse_data_header(mode_info->atom_context, index, NULL, + &frev, &crev, &data_offset)) +@@ -2535,17 +2530,15 @@ static int radeon_atombios_parse_power_table_6(struct radeon_device *rdev) + non_clock_info_array = (struct _NonClockInfoArray *) + (mode_info->atom_context->bios + data_offset + + le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset)); +- if (state_array->ucNumEntries == 0) +- return state_index; + rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) * + state_array->ucNumEntries, GFP_KERNEL); + if (!rdev->pm.power_state) + return state_index; +- power_state_offset = (u8 *)state_array->states; + for (i = 0; i < state_array->ucNumEntries; i++) { + mode_index = 0; +- power_state = (union pplib_power_state *)power_state_offset; +- non_clock_array_index = power_state->v2.nonClockInfoIndex; ++ power_state = (union pplib_power_state *)&state_array->states[i]; ++ /* XXX this might be an inagua bug... */ ++ non_clock_array_index = i; /* power_state->v2.nonClockInfoIndex */ + non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) + &non_clock_info_array->nonClockInfo[non_clock_array_index]; + rdev->pm.power_state[i].clock_info = kzalloc(sizeof(struct radeon_pm_clock_info) * +@@ -2557,6 +2550,9 @@ static int radeon_atombios_parse_power_table_6(struct radeon_device *rdev) + if (power_state->v2.ucNumDPMLevels) { + for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) { + clock_array_index = power_state->v2.clockInfoIndex[j]; ++ /* XXX this might be an inagua bug... */ ++ if (clock_array_index >= clock_info_array->ucNumEntries) ++ continue; + clock_info = (union pplib_clock_info *) + &clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize]; + valid = radeon_atombios_parse_pplib_clock_info(rdev, +@@ -2578,7 +2574,6 @@ static int radeon_atombios_parse_power_table_6(struct radeon_device *rdev) + non_clock_info); + state_index++; + } +- power_state_offset += 2 + power_state->v2.ucNumDPMLevels; + } + /* if multiple clock modes, mark the lowest as no display */ + for (i = 0; i < state_index; i++) { +@@ -2625,9 +2620,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) + default: + break; + } +- } +- +- if (state_index == 0) { ++ } else { + rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state), GFP_KERNEL); + if (rdev->pm.power_state) { + rdev->pm.power_state[0].clock_info = +diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c +index bc36922..9c312f9 100644 +--- a/drivers/gpu/drm/radeon/radeon_kms.c ++++ b/drivers/gpu/drm/radeon/radeon_kms.c +@@ -50,13 +50,9 @@ int radeon_driver_unload_kms(struct drm_device *dev) + + if (rdev == NULL) + return 0; +- if (rdev->rmmio == NULL) +- goto done_free; + radeon_acpi_fini(rdev); + radeon_modeset_fini(rdev); + radeon_device_fini(rdev); +- +-done_free: + kfree(rdev); + dev->dev_private = NULL; + return 0; +diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c +index 788c64c..338fd6a 100644 +--- a/drivers/gpu/drm/radeon/radeon_pm.c ++++ b/drivers/gpu/drm/radeon/radeon_pm.c +@@ -843,11 +843,7 @@ static int radeon_debugfs_pm_info(struct seq_file *m, void *data) + struct radeon_device *rdev = dev->dev_private; + + seq_printf(m, "default engine clock: %u0 kHz\n", rdev->pm.default_sclk); +- /* radeon_get_engine_clock is not reliable on APUs so just print the current clock */ +- if ((rdev->family >= CHIP_PALM) && (rdev->flags & RADEON_IS_IGP)) +- seq_printf(m, "current engine clock: %u0 kHz\n", rdev->pm.current_sclk); +- else +- seq_printf(m, "current engine clock: %u0 kHz\n", radeon_get_engine_clock(rdev)); ++ seq_printf(m, "current engine clock: %u0 kHz\n", radeon_get_engine_clock(rdev)); + seq_printf(m, "default memory clock: %u0 kHz\n", rdev->pm.default_mclk); + if (rdev->asic->pm.get_memory_clock) + seq_printf(m, "current memory clock: %u0 kHz\n", radeon_get_memory_clock(rdev)); +diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c +index 8adc5b5..cd72062 100644 +--- a/drivers/gpu/drm/radeon/radeon_ring.c ++++ b/drivers/gpu/drm/radeon/radeon_ring.c +@@ -161,8 +161,7 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib, + radeon_semaphore_free(rdev, &ib->semaphore, NULL); + } + /* if we can't remember our last VM flush then flush now! */ +- /* XXX figure out why we have to flush for every IB */ +- if (ib->vm /*&& !ib->vm->last_flush*/) { ++ if (ib->vm && !ib->vm->last_flush) { + radeon_ring_vm_flush(rdev, ib->ring, ib->vm); + } + if (const_ib) { +diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c +index 46fa1b0..5a0fc74 100644 +--- a/drivers/gpu/drm/radeon/rs600.c ++++ b/drivers/gpu/drm/radeon/rs600.c +@@ -52,59 +52,23 @@ static const u32 crtc_offsets[2] = + AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL + }; + +-static bool avivo_is_in_vblank(struct radeon_device *rdev, int crtc) +-{ +- if (RREG32(AVIVO_D1CRTC_STATUS + crtc_offsets[crtc]) & AVIVO_D1CRTC_V_BLANK) +- return true; +- else +- return false; +-} +- +-static bool avivo_is_counter_moving(struct radeon_device *rdev, int crtc) +-{ +- u32 pos1, pos2; +- +- pos1 = RREG32(AVIVO_D1CRTC_STATUS_POSITION + crtc_offsets[crtc]); +- pos2 = RREG32(AVIVO_D1CRTC_STATUS_POSITION + crtc_offsets[crtc]); +- +- if (pos1 != pos2) +- return true; +- else +- return false; +-} +- +-/** +- * avivo_wait_for_vblank - vblank wait asic callback. +- * +- * @rdev: radeon_device pointer +- * @crtc: crtc to wait for vblank on +- * +- * Wait for vblank on the requested crtc (r5xx-r7xx). +- */ + void avivo_wait_for_vblank(struct radeon_device *rdev, int crtc) + { +- unsigned i = 0; ++ int i; + + if (crtc >= rdev->num_crtc) + return; + +- if (!(RREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[crtc]) & AVIVO_CRTC_EN)) +- return; +- +- /* depending on when we hit vblank, we may be close to active; if so, +- * wait for another frame. +- */ +- while (avivo_is_in_vblank(rdev, crtc)) { +- if (i++ % 100 == 0) { +- if (!avivo_is_counter_moving(rdev, crtc)) ++ if (RREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[crtc]) & AVIVO_CRTC_EN) { ++ for (i = 0; i < rdev->usec_timeout; i++) { ++ if (!(RREG32(AVIVO_D1CRTC_STATUS + crtc_offsets[crtc]) & AVIVO_D1CRTC_V_BLANK)) + break; ++ udelay(1); + } +- } +- +- while (!avivo_is_in_vblank(rdev, crtc)) { +- if (i++ % 100 == 0) { +- if (!avivo_is_counter_moving(rdev, crtc)) ++ for (i = 0; i < rdev->usec_timeout; i++) { ++ if (RREG32(AVIVO_D1CRTC_STATUS + crtc_offsets[crtc]) & AVIVO_D1CRTC_V_BLANK) + break; ++ udelay(1); + } + } + } +diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c +index ffcba73..435ed35 100644 +--- a/drivers/gpu/drm/radeon/rv515.c ++++ b/drivers/gpu/drm/radeon/rv515.c +@@ -303,10 +303,8 @@ void rv515_mc_stop(struct radeon_device *rdev, struct rv515_mc_save *save) + tmp = RREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[i]); + if (!(tmp & AVIVO_CRTC_DISP_READ_REQUEST_DISABLE)) { + radeon_wait_for_vblank(rdev, i); +- WREG32(AVIVO_D1CRTC_UPDATE_LOCK + crtc_offsets[i], 1); + tmp |= AVIVO_CRTC_DISP_READ_REQUEST_DISABLE; + WREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[i], tmp); +- WREG32(AVIVO_D1CRTC_UPDATE_LOCK + crtc_offsets[i], 0); + } + /* wait for the next frame */ + frame_count = radeon_get_vblank_counter(rdev, i); +@@ -315,15 +313,6 @@ void rv515_mc_stop(struct radeon_device *rdev, struct rv515_mc_save *save) + break; + udelay(1); + } +- +- /* XXX this is a hack to avoid strange behavior with EFI on certain systems */ +- WREG32(AVIVO_D1CRTC_UPDATE_LOCK + crtc_offsets[i], 1); +- tmp = RREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[i]); +- tmp &= ~AVIVO_CRTC_EN; +- WREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[i], tmp); +- WREG32(AVIVO_D1CRTC_UPDATE_LOCK + crtc_offsets[i], 0); +- save->crtc_enabled[i] = false; +- /* ***** */ + } else { + save->crtc_enabled[i] = false; + } +@@ -349,22 +338,6 @@ void rv515_mc_stop(struct radeon_device *rdev, struct rv515_mc_save *save) + } + /* wait for the MC to settle */ + udelay(100); +- +- /* lock double buffered regs */ +- for (i = 0; i < rdev->num_crtc; i++) { +- if (save->crtc_enabled[i]) { +- tmp = RREG32(AVIVO_D1GRPH_UPDATE + crtc_offsets[i]); +- if (!(tmp & AVIVO_D1GRPH_UPDATE_LOCK)) { +- tmp |= AVIVO_D1GRPH_UPDATE_LOCK; +- WREG32(AVIVO_D1GRPH_UPDATE + crtc_offsets[i], tmp); +- } +- tmp = RREG32(AVIVO_D1MODE_MASTER_UPDATE_LOCK + crtc_offsets[i]); +- if (!(tmp & 1)) { +- tmp |= 1; +- WREG32(AVIVO_D1MODE_MASTER_UPDATE_LOCK + crtc_offsets[i], tmp); +- } +- } +- } + } + + void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save) +@@ -375,7 +348,7 @@ void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save) + /* update crtc base addresses */ + for (i = 0; i < rdev->num_crtc; i++) { + if (rdev->family >= CHIP_RV770) { +- if (i == 0) { ++ if (i == 1) { + WREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, + upper_32_bits(rdev->mc.vram_start)); + WREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, +@@ -394,33 +367,6 @@ void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save) + } + WREG32(R_000310_VGA_MEMORY_BASE_ADDRESS, (u32)rdev->mc.vram_start); + +- /* unlock regs and wait for update */ +- for (i = 0; i < rdev->num_crtc; i++) { +- if (save->crtc_enabled[i]) { +- tmp = RREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + crtc_offsets[i]); +- if ((tmp & 0x3) != 0) { +- tmp &= ~0x3; +- WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + crtc_offsets[i], tmp); +- } +- tmp = RREG32(AVIVO_D1GRPH_UPDATE + crtc_offsets[i]); +- if (tmp & AVIVO_D1GRPH_UPDATE_LOCK) { +- tmp &= ~AVIVO_D1GRPH_UPDATE_LOCK; +- WREG32(AVIVO_D1GRPH_UPDATE + crtc_offsets[i], tmp); +- } +- tmp = RREG32(AVIVO_D1MODE_MASTER_UPDATE_LOCK + crtc_offsets[i]); +- if (tmp & 1) { +- tmp &= ~1; +- WREG32(AVIVO_D1MODE_MASTER_UPDATE_LOCK + crtc_offsets[i], tmp); +- } +- for (j = 0; j < rdev->usec_timeout; j++) { +- tmp = RREG32(AVIVO_D1GRPH_UPDATE + crtc_offsets[i]); +- if ((tmp & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING) == 0) +- break; +- udelay(1); +- } +- } +- } +- + if (rdev->family >= CHIP_R600) { + /* unblackout the MC */ + if (rdev->family >= CHIP_RV770) +diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c +index 40d766e..dd00721 100644 +--- a/drivers/gpu/drm/radeon/si.c ++++ b/drivers/gpu/drm/radeon/si.c +@@ -1374,7 +1374,7 @@ static void si_select_se_sh(struct radeon_device *rdev, + u32 data = INSTANCE_BROADCAST_WRITES; + + if ((se_num == 0xffffffff) && (sh_num == 0xffffffff)) +- data |= SH_BROADCAST_WRITES | SE_BROADCAST_WRITES; ++ data = SH_BROADCAST_WRITES | SE_BROADCAST_WRITES; + else if (se_num == 0xffffffff) + data |= SE_BROADCAST_WRITES | SH_INDEX(sh_num); + else if (sh_num == 0xffffffff) +@@ -1659,7 +1659,6 @@ static void si_gpu_init(struct radeon_device *rdev) + + WREG32(GB_ADDR_CONFIG, gb_addr_config); + WREG32(DMIF_ADDR_CONFIG, gb_addr_config); +- WREG32(DMIF_ADDR_CALC, gb_addr_config); + WREG32(HDP_ADDR_CONFIG, gb_addr_config); + WREG32(DMA_TILING_CONFIG + DMA0_REGISTER_OFFSET, gb_addr_config); + WREG32(DMA_TILING_CONFIG + DMA1_REGISTER_OFFSET, gb_addr_config); +diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h +index e9a01f0..c056aae 100644 +--- a/drivers/gpu/drm/radeon/sid.h ++++ b/drivers/gpu/drm/radeon/sid.h +@@ -60,8 +60,6 @@ + + #define DMIF_ADDR_CONFIG 0xBD4 + +-#define DMIF_ADDR_CALC 0xC00 +- + #define SRBM_STATUS 0xE50 + + #define SRBM_SOFT_RESET 0x0E60 +diff --git a/drivers/hwmon/xilinx-xadcps.c b/drivers/hwmon/xilinx-xadcps.c +index 13463a1..9ff73d6 100644 +--- a/drivers/hwmon/xilinx-xadcps.c ++++ b/drivers/hwmon/xilinx-xadcps.c +@@ -703,7 +703,7 @@ static int xadc_probe(struct platform_device *pdev) + goto err_io_remap; + } + +- xadc->clk = clk_get_sys("PCAP", NULL); ++ xadc->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(xadc->clk)) { + dev_err(&pdev->dev, "input clock not found\n"); + ret = PTR_ERR(xadc->clk); +diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c +index fd7d66d..f042f6d 100644 +--- a/drivers/i2c/busses/i2c-xiic.c ++++ b/drivers/i2c/busses/i2c-xiic.c +@@ -312,8 +312,10 @@ static void xiic_fill_tx_fifo(struct xiic_i2c *i2c) + /* last message in transfer -> STOP */ + data |= XIIC_TX_DYN_STOP_MASK; + dev_dbg(i2c->adap.dev.parent, "%s TX STOP\n", __func__); +- } +- xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, data); ++ ++ xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, data); ++ } else ++ xiic_setreg8(i2c, XIIC_DTR_REG_OFFSET, data); + } + } + +diff --git a/drivers/i2c/busses/i2c-xilinx_ps.c b/drivers/i2c/busses/i2c-xilinx_ps.c +index 1191a8b..65709c1 100644 +--- a/drivers/i2c/busses/i2c-xilinx_ps.c ++++ b/drivers/i2c/busses/i2c-xilinx_ps.c +@@ -114,6 +114,7 @@ + * @xfer_done: Transfer complete status + * @p_send_buf: Pointer to transmit buffer + * @p_recv_buf: Pointer to receive buffer ++ * @suspended: Flag holding the device's PM status + * @send_count: Number of bytes still expected to send + * @recv_count: Number of bytes still expected to receive + * @irq: IRQ number +@@ -132,6 +133,7 @@ struct xi2cps { + struct completion xfer_done; + unsigned char *p_send_buf; + unsigned char *p_recv_buf; ++ u8 suspended; + int send_count; + int recv_count; + int irq; +@@ -455,6 +457,7 @@ static int xi2cps_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + struct xi2cps *id = adap->algo_data; + unsigned int count, retries; + unsigned long timeout; ++ int ret; + + /* Waiting for bus-ready. If bus not ready, it returns after timeout */ + timeout = jiffies + XI2CPS_TIMEOUT; +@@ -517,7 +520,13 @@ retry: + xi2cps_msend(id); + + /* Wait for the signal of completion */ +- wait_for_completion_interruptible(&id->xfer_done); ++ ret = wait_for_completion_interruptible_timeout( ++ &id->xfer_done, HZ); ++ if (ret == 0) { ++ dev_err(id->adap.dev.parent, ++ "timeout waiting on completion\n"); ++ return -ETIMEDOUT; ++ } + xi2cps_writereg(XI2CPS_IXR_ALL_INTR_MASK, XI2CPS_IDR_OFFSET); + + /* If it is bus arbitration error, try again */ +@@ -702,6 +711,9 @@ static int xi2cps_clk_notifier_cb(struct notifier_block *nb, unsigned long + struct clk_notifier_data *ndata = data; + struct xi2cps *id = to_xi2cps(nb); + ++ if (id->suspended) ++ return NOTIFY_OK; ++ + switch (event) { + case PRE_RATE_CHANGE: + { +@@ -752,6 +764,7 @@ static int xi2cps_suspend(struct device *_dev) + struct xi2cps *xi2c = platform_get_drvdata(pdev); + + clk_disable(xi2c->clk); ++ xi2c->suspended = 1; + + return 0; + } +@@ -776,6 +789,8 @@ static int xi2cps_resume(struct device *_dev) + return ret; + } + ++ xi2c->suspended = 0; ++ + return 0; + } + +@@ -862,12 +877,9 @@ static int xi2cps_probe(struct platform_device *pdev) + "XILINX I2C at %08lx", (unsigned long)r_mem->start); + + id->cur_timeout = id->adap.timeout; +- if (id->irq == 80) +- id->clk = clk_get_sys("I2C1_APER", NULL); +- else +- id->clk = clk_get_sys("I2C0_APER", NULL); ++ id->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(id->clk)) { +- dev_err(&pdev->dev, "Clock not found.\n"); ++ dev_err(&pdev->dev, "input clock not found.\n"); + ret = PTR_ERR(id->clk); + goto err_unmap; + } +diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c +index 892cd87..05bfe53 100644 +--- a/drivers/infiniband/hw/cxgb4/qp.c ++++ b/drivers/infiniband/hw/cxgb4/qp.c +@@ -100,16 +100,6 @@ static int alloc_host_sq(struct c4iw_rdev *rdev, struct t4_sq *sq) + return 0; + } + +-static int alloc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq, int user) +-{ +- int ret = -ENOSYS; +- if (user) +- ret = alloc_oc_sq(rdev, sq); +- if (ret) +- ret = alloc_host_sq(rdev, sq); +- return ret; +-} +- + static int destroy_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, + struct c4iw_dev_ucontext *uctx) + { +@@ -178,9 +168,18 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, + goto free_sw_rq; + } + +- ret = alloc_sq(rdev, &wq->sq, user); +- if (ret) +- goto free_hwaddr; ++ if (user) { ++ ret = alloc_oc_sq(rdev, &wq->sq); ++ if (ret) ++ goto free_hwaddr; ++ ++ ret = alloc_host_sq(rdev, &wq->sq); ++ if (ret) ++ goto free_sq; ++ } else ++ ret = alloc_host_sq(rdev, &wq->sq); ++ if (ret) ++ goto free_hwaddr; + memset(wq->sq.queue, 0, wq->sq.memsize); + dma_unmap_addr_set(&wq->sq, mapping, wq->sq.dma_addr); + +diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c +index 4c867f4..4647b50 100644 +--- a/drivers/iommu/amd_iommu.c ++++ b/drivers/iommu/amd_iommu.c +@@ -3948,9 +3948,6 @@ static struct irq_remap_table *get_irq_table(u16 devid, bool ioapic) + if (!table) + goto out; + +- /* Initialize table spin-lock */ +- spin_lock_init(&table->lock); +- + if (ioapic) + /* Keep the first 32 indexes free for IOAPIC interrupts */ + table->min_index = 32; +diff --git a/drivers/md/md.c b/drivers/md/md.c +index 0411bde..f363135 100644 +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -1564,8 +1564,8 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_ + sector, count, 1) == 0) + return -EINVAL; + } +- } else if (sb->bblog_offset != 0) +- rdev->badblocks.shift = 0; ++ } else if (sb->bblog_offset == 0) ++ rdev->badblocks.shift = -1; + + if (!refdev) { + ret = 1; +@@ -3221,7 +3221,7 @@ int md_rdev_init(struct md_rdev *rdev) + * be used - I wonder if that matters + */ + rdev->badblocks.count = 0; +- rdev->badblocks.shift = -1; /* disabled until explicitly enabled */ ++ rdev->badblocks.shift = 0; + rdev->badblocks.page = kmalloc(PAGE_SIZE, GFP_KERNEL); + seqlock_init(&rdev->badblocks.lock); + if (rdev->badblocks.page == NULL) +@@ -3293,6 +3293,9 @@ static struct md_rdev *md_import_device(dev_t newdev, int super_format, int supe + goto abort_free; + } + } ++ if (super_format == -1) ++ /* hot-add for 0.90, or non-persistent: so no badblocks */ ++ rdev->badblocks.shift = -1; + + return rdev; + +diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c +index 6af167f..fd86b37 100644 +--- a/drivers/md/raid1.c ++++ b/drivers/md/raid1.c +@@ -981,12 +981,7 @@ static void raid1_unplug(struct blk_plug_cb *cb, bool from_schedule) + while (bio) { /* submit pending writes */ + struct bio *next = bio->bi_next; + bio->bi_next = NULL; +- if (unlikely((bio->bi_rw & REQ_DISCARD) && +- !blk_queue_discard(bdev_get_queue(bio->bi_bdev)))) +- /* Just ignore it */ +- bio_endio(bio, 0); +- else +- generic_make_request(bio); ++ generic_make_request(bio); + bio = next; + } + kfree(plug); +diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c +index 61ab219..b3898d4 100644 +--- a/drivers/md/raid10.c ++++ b/drivers/md/raid10.c +@@ -1087,12 +1087,7 @@ static void raid10_unplug(struct blk_plug_cb *cb, bool from_schedule) + while (bio) { /* submit pending writes */ + struct bio *next = bio->bi_next; + bio->bi_next = NULL; +- if (unlikely((bio->bi_rw & REQ_DISCARD) && +- !blk_queue_discard(bdev_get_queue(bio->bi_bdev)))) +- /* Just ignore it */ +- bio_endio(bio, 0); +- else +- generic_make_request(bio); ++ generic_make_request(bio); + bio = next; + } + kfree(plug); +diff --git a/drivers/memory/zynq-smc.c b/drivers/memory/zynq-smc.c +index e073530..86f5c27 100644 +--- a/drivers/memory/zynq-smc.c ++++ b/drivers/memory/zynq-smc.c +@@ -474,16 +474,16 @@ static int xsmcps_probe(struct platform_device *pdev) + return -ENOMEM; + } + +- xsmcps->aperclk = clk_get_sys("SMC_APER", NULL); ++ xsmcps->aperclk = clk_get(&pdev->dev, "aper_clk"); + if (IS_ERR(xsmcps->aperclk)) { +- dev_err(&pdev->dev, "APER clock not found.\n"); ++ dev_err(&pdev->dev, "aper_clk clock not found.\n"); + err = PTR_ERR(xsmcps->aperclk); + goto out_free; + } + +- xsmcps->devclk = clk_get_sys("SMC", NULL); ++ xsmcps->devclk = clk_get(&pdev->dev, "ref_clk"); + if (IS_ERR(xsmcps->devclk)) { +- dev_err(&pdev->dev, "Device clock not found.\n"); ++ dev_err(&pdev->dev, "ref_clk clock not found.\n"); + err = PTR_ERR(xsmcps->devclk); + goto out_clk_put_aper; + } +diff --git a/drivers/mfd/adp5520.c b/drivers/mfd/adp5520.c +index 6b40e0c..210dd03 100644 +--- a/drivers/mfd/adp5520.c ++++ b/drivers/mfd/adp5520.c +@@ -36,7 +36,6 @@ struct adp5520_chip { + struct blocking_notifier_head notifier_list; + int irq; + unsigned long id; +- uint8_t mode; + }; + + static int __adp5520_read(struct i2c_client *client, +@@ -327,10 +326,7 @@ static int adp5520_suspend(struct device *dev) + struct i2c_client *client = to_i2c_client(dev); + struct adp5520_chip *chip = dev_get_drvdata(&client->dev); + +- adp5520_read(chip->dev, ADP5520_MODE_STATUS, &chip->mode); +- /* All other bits are W1C */ +- chip->mode &= ADP5520_BL_EN | ADP5520_DIM_EN | ADP5520_nSTNBY; +- adp5520_write(chip->dev, ADP5520_MODE_STATUS, 0); ++ adp5520_clr_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY); + return 0; + } + +@@ -339,7 +335,7 @@ static int adp5520_resume(struct device *dev) + struct i2c_client *client = to_i2c_client(dev); + struct adp5520_chip *chip = dev_get_drvdata(&client->dev); + +- adp5520_write(chip->dev, ADP5520_MODE_STATUS, chip->mode); ++ adp5520_set_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY); + return 0; + } + #endif +diff --git a/drivers/mfd/lpc_sch.c b/drivers/mfd/lpc_sch.c +index 8cc6aac..5624fcb 100644 +--- a/drivers/mfd/lpc_sch.c ++++ b/drivers/mfd/lpc_sch.c +@@ -45,32 +45,34 @@ static struct resource smbus_sch_resource = { + .flags = IORESOURCE_IO, + }; + +-static struct resource gpio_sch_resource = { +- .flags = IORESOURCE_IO, +-}; + +-static struct resource wdt_sch_resource = { ++static struct resource gpio_sch_resource = { + .flags = IORESOURCE_IO, + }; + +-static struct mfd_cell lpc_sch_cells[3]; +- +-static struct mfd_cell isch_smbus_cell = { +- .name = "isch_smbus", +- .num_resources = 1, +- .resources = &smbus_sch_resource, ++static struct mfd_cell lpc_sch_cells[] = { ++ { ++ .name = "isch_smbus", ++ .num_resources = 1, ++ .resources = &smbus_sch_resource, ++ }, ++ { ++ .name = "sch_gpio", ++ .num_resources = 1, ++ .resources = &gpio_sch_resource, ++ }, + }; + +-static struct mfd_cell sch_gpio_cell = { +- .name = "sch_gpio", +- .num_resources = 1, +- .resources = &gpio_sch_resource, ++static struct resource wdt_sch_resource = { ++ .flags = IORESOURCE_IO, + }; + +-static struct mfd_cell wdt_sch_cell = { +- .name = "ie6xx_wdt", +- .num_resources = 1, +- .resources = &wdt_sch_resource, ++static struct mfd_cell tunnelcreek_cells[] = { ++ { ++ .name = "ie6xx_wdt", ++ .num_resources = 1, ++ .resources = &wdt_sch_resource, ++ }, + }; + + static DEFINE_PCI_DEVICE_TABLE(lpc_sch_ids) = { +@@ -86,76 +88,79 @@ static int lpc_sch_probe(struct pci_dev *dev, + { + unsigned int base_addr_cfg; + unsigned short base_addr; +- int i, cells = 0; ++ int i; + int ret; + + pci_read_config_dword(dev, SMBASE, &base_addr_cfg); +- base_addr = 0; +- if (!(base_addr_cfg & (1 << 31))) +- dev_warn(&dev->dev, "Decode of the SMBus I/O range disabled\n"); +- else +- base_addr = (unsigned short)base_addr_cfg; +- +- if (base_addr == 0) { +- dev_warn(&dev->dev, "I/O space for SMBus uninitialized\n"); +- } else { +- lpc_sch_cells[cells++] = isch_smbus_cell; +- smbus_sch_resource.start = base_addr; +- smbus_sch_resource.end = base_addr + SMBUS_IO_SIZE - 1; ++ if (!(base_addr_cfg & (1 << 31))) { ++ dev_err(&dev->dev, "Decode of the SMBus I/O range disabled\n"); ++ return -ENODEV; + } +- +- pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg); +- base_addr = 0; +- if (!(base_addr_cfg & (1 << 31))) +- dev_warn(&dev->dev, "Decode of the GPIO I/O range disabled\n"); +- else +- base_addr = (unsigned short)base_addr_cfg; +- ++ base_addr = (unsigned short)base_addr_cfg; + if (base_addr == 0) { +- dev_warn(&dev->dev, "I/O space for GPIO uninitialized\n"); +- } else { +- lpc_sch_cells[cells++] = sch_gpio_cell; +- gpio_sch_resource.start = base_addr; +- if (id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB) +- gpio_sch_resource.end = base_addr + GPIO_IO_SIZE_CENTERTON - 1; +- else +- gpio_sch_resource.end = base_addr + GPIO_IO_SIZE - 1; ++ dev_err(&dev->dev, "I/O space for SMBus uninitialized\n"); ++ return -ENODEV; + } + +- if (id->device == PCI_DEVICE_ID_INTEL_ITC_LPC +- || id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB) { +- pci_read_config_dword(dev, WDTBASE, &base_addr_cfg); +- base_addr = 0; +- if (!(base_addr_cfg & (1 << 31))) +- dev_warn(&dev->dev, "Decode of the WDT I/O range disabled\n"); +- else +- base_addr = (unsigned short)base_addr_cfg; +- if (base_addr == 0) +- dev_warn(&dev->dev, "I/O space for WDT uninitialized\n"); +- else { +- lpc_sch_cells[cells++] = wdt_sch_cell; +- wdt_sch_resource.start = base_addr; +- wdt_sch_resource.end = base_addr + WDT_IO_SIZE - 1; +- } +- } ++ smbus_sch_resource.start = base_addr; ++ smbus_sch_resource.end = base_addr + SMBUS_IO_SIZE - 1; + +- if (WARN_ON(cells > ARRAY_SIZE(lpc_sch_cells))) { +- dev_err(&dev->dev, "Cell count exceeds array size"); ++ pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg); ++ if (!(base_addr_cfg & (1 << 31))) { ++ dev_err(&dev->dev, "Decode of the GPIO I/O range disabled\n"); + return -ENODEV; + } +- +- if (cells == 0) { +- dev_err(&dev->dev, "All decode registers disabled.\n"); ++ base_addr = (unsigned short)base_addr_cfg; ++ if (base_addr == 0) { ++ dev_err(&dev->dev, "I/O space for GPIO uninitialized\n"); + return -ENODEV; + } + +- for (i = 0; i < cells; i++) ++ gpio_sch_resource.start = base_addr; ++ ++ if (id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB) ++ gpio_sch_resource.end = base_addr + GPIO_IO_SIZE_CENTERTON - 1; ++ else ++ gpio_sch_resource.end = base_addr + GPIO_IO_SIZE - 1; ++ ++ for (i=0; i < ARRAY_SIZE(lpc_sch_cells); i++) + lpc_sch_cells[i].id = id->device; + +- ret = mfd_add_devices(&dev->dev, 0, lpc_sch_cells, cells, NULL, 0, NULL); ++ ret = mfd_add_devices(&dev->dev, 0, ++ lpc_sch_cells, ARRAY_SIZE(lpc_sch_cells), NULL, ++ 0, NULL); + if (ret) +- mfd_remove_devices(&dev->dev); ++ goto out_dev; ++ ++ if (id->device == PCI_DEVICE_ID_INTEL_ITC_LPC ++ || id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB) { ++ pci_read_config_dword(dev, WDTBASE, &base_addr_cfg); ++ if (!(base_addr_cfg & (1 << 31))) { ++ dev_err(&dev->dev, "Decode of the WDT I/O range disabled\n"); ++ ret = -ENODEV; ++ goto out_dev; ++ } ++ base_addr = (unsigned short)base_addr_cfg; ++ if (base_addr == 0) { ++ dev_err(&dev->dev, "I/O space for WDT uninitialized\n"); ++ ret = -ENODEV; ++ goto out_dev; ++ } ++ ++ wdt_sch_resource.start = base_addr; ++ wdt_sch_resource.end = base_addr + WDT_IO_SIZE - 1; + ++ for (i = 0; i < ARRAY_SIZE(tunnelcreek_cells); i++) ++ tunnelcreek_cells[i].id = id->device; ++ ++ ret = mfd_add_devices(&dev->dev, 0, tunnelcreek_cells, ++ ARRAY_SIZE(tunnelcreek_cells), NULL, ++ 0, NULL); ++ } ++ ++ return ret; ++out_dev: ++ mfd_remove_devices(&dev->dev); + return ret; + } + +diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c +index 2743b7d..089e8ea 100644 +--- a/drivers/mmc/core/mmc.c ++++ b/drivers/mmc/core/mmc.c +@@ -368,13 +368,13 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) + ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]; + card->ext_csd.raw_trim_mult = + ext_csd[EXT_CSD_TRIM_MULT]; +- card->ext_csd.raw_partition_support = ext_csd[EXT_CSD_PARTITION_SUPPORT]; + if (card->ext_csd.rev >= 4) { + /* + * Enhanced area feature support -- check whether the eMMC + * card has the Enhanced area enabled. If so, export enhanced + * area offset and size to user by adding sysfs interface. + */ ++ card->ext_csd.raw_partition_support = ext_csd[EXT_CSD_PARTITION_SUPPORT]; + if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) && + (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) { + hc_erase_grp_sz = +diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig +index 920280a..3d2e608 100644 +--- a/drivers/mmc/host/Kconfig ++++ b/drivers/mmc/host/Kconfig +@@ -305,6 +305,16 @@ config MMC_ATMELMCI + + If unsure, say N. + ++config MMC_ATMELMCI_DMA ++ bool "Atmel MCI DMA support" ++ depends on MMC_ATMELMCI && (AVR32 || ARCH_AT91SAM9G45) && DMA_ENGINE ++ help ++ Say Y here to have the Atmel MCI driver use a DMA engine to ++ do data transfers and thus increase the throughput and ++ reduce the CPU utilization. ++ ++ If unsure, say N. ++ + config MMC_MSM + tristate "Qualcomm SDCC Controller Support" + depends on MMC && ARCH_MSM +diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c +index e75774f..722af1d 100644 +--- a/drivers/mmc/host/atmel-mci.c ++++ b/drivers/mmc/host/atmel-mci.c +@@ -178,7 +178,6 @@ struct atmel_mci { + void __iomem *regs; + + struct scatterlist *sg; +- unsigned int sg_len; + unsigned int pio_offset; + unsigned int *buffer; + unsigned int buf_size; +@@ -893,7 +892,6 @@ static u32 atmci_prepare_data(struct atmel_mci *host, struct mmc_data *data) + data->error = -EINPROGRESS; + + host->sg = data->sg; +- host->sg_len = data->sg_len; + host->data = data; + host->data_chan = NULL; + +@@ -1828,8 +1826,7 @@ static void atmci_read_data_pio(struct atmel_mci *host) + if (offset == sg->length) { + flush_dcache_page(sg_page(sg)); + host->sg = sg = sg_next(sg); +- host->sg_len--; +- if (!sg || !host->sg_len) ++ if (!sg) + goto done; + + offset = 0; +@@ -1842,8 +1839,7 @@ static void atmci_read_data_pio(struct atmel_mci *host) + + flush_dcache_page(sg_page(sg)); + host->sg = sg = sg_next(sg); +- host->sg_len--; +- if (!sg || !host->sg_len) ++ if (!sg) + goto done; + + offset = 4 - remaining; +@@ -1894,8 +1890,7 @@ static void atmci_write_data_pio(struct atmel_mci *host) + nbytes += 4; + if (offset == sg->length) { + host->sg = sg = sg_next(sg); +- host->sg_len--; +- if (!sg || !host->sg_len) ++ if (!sg) + goto done; + + offset = 0; +@@ -1909,8 +1904,7 @@ static void atmci_write_data_pio(struct atmel_mci *host) + nbytes += remaining; + + host->sg = sg = sg_next(sg); +- host->sg_len--; +- if (!sg || !host->sg_len) { ++ if (!sg) { + atmci_writel(host, ATMCI_TDR, value); + goto done; + } +@@ -2493,8 +2487,10 @@ static int __exit atmci_remove(struct platform_device *pdev) + atmci_readl(host, ATMCI_SR); + clk_disable(host->mck); + ++#ifdef CONFIG_MMC_ATMELMCI_DMA + if (host->dma.chan) + dma_release_channel(host->dma.chan); ++#endif + + free_irq(platform_get_irq(pdev, 0), host); + iounmap(host->regs); +diff --git a/drivers/mmc/host/sdhci-of-xilinxps.c b/drivers/mmc/host/sdhci-of-xilinxps.c +index f79e0db..4a4a9b0 100644 +--- a/drivers/mmc/host/sdhci-of-xilinxps.c ++++ b/drivers/mmc/host/sdhci-of-xilinxps.c +@@ -143,7 +143,6 @@ static const struct dev_pm_ops xsdhcips_dev_pm_ops = { + static int sdhci_zynq_probe(struct platform_device *pdev) + { + int ret; +- int irq = platform_get_irq(pdev, 0); + const void *prop; + struct device_node *np = pdev->dev.of_node; + struct sdhci_host *host; +@@ -156,24 +155,16 @@ static int sdhci_zynq_probe(struct platform_device *pdev) + return -ENOMEM; + } + +- if (irq == 56) +- xsdhcips->aperclk = clk_get_sys("SDIO0_APER", NULL); +- else +- xsdhcips->aperclk = clk_get_sys("SDIO1_APER", NULL); +- ++ xsdhcips->aperclk = clk_get(&pdev->dev, "aper_clk"); + if (IS_ERR(xsdhcips->aperclk)) { +- dev_err(&pdev->dev, "APER clock not found.\n"); ++ dev_err(&pdev->dev, "aper_clk clock not found.\n"); + ret = PTR_ERR(xsdhcips->aperclk); + goto err_free; + } + +- if (irq == 56) +- xsdhcips->devclk = clk_get_sys("SDIO0", NULL); +- else +- xsdhcips->devclk = clk_get_sys("SDIO1", NULL); +- ++ xsdhcips->devclk = clk_get(&pdev->dev, "ref_clk"); + if (IS_ERR(xsdhcips->devclk)) { +- dev_err(&pdev->dev, "Device clock not found.\n"); ++ dev_err(&pdev->dev, "ref_clk clock not found.\n"); + ret = PTR_ERR(xsdhcips->devclk); + goto clk_put_aper; + } +diff --git a/drivers/net/ethernet/freescale/gianfar_ptp.c b/drivers/net/ethernet/freescale/gianfar_ptp.c +index a3f8a25..2e5daee 100644 +--- a/drivers/net/ethernet/freescale/gianfar_ptp.c ++++ b/drivers/net/ethernet/freescale/gianfar_ptp.c +@@ -127,6 +127,7 @@ struct gianfar_ptp_registers { + + #define DRIVER "gianfar_ptp" + #define DEFAULT_CKSEL 1 ++#define N_ALARM 1 /* first alarm is used internally to reset fipers */ + #define N_EXT_TS 2 + #define REG_SIZE sizeof(struct gianfar_ptp_registers) + +@@ -409,7 +410,7 @@ static struct ptp_clock_info ptp_gianfar_caps = { + .owner = THIS_MODULE, + .name = "gianfar clock", + .max_adj = 512000, +- .n_alarm = 0, ++ .n_alarm = N_ALARM, + .n_ext_ts = N_EXT_TS, + .n_per_out = 0, + .pps = 1, +diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c +index 82c63ac..f2fdbb7 100644 +--- a/drivers/net/ethernet/ibm/ibmveth.c ++++ b/drivers/net/ethernet/ibm/ibmveth.c +@@ -1326,7 +1326,7 @@ static const struct net_device_ops ibmveth_netdev_ops = { + + static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) + { +- int rc, i, mac_len; ++ int rc, i; + struct net_device *netdev; + struct ibmveth_adapter *adapter; + unsigned char *mac_addr_p; +@@ -1336,19 +1336,11 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) + dev->unit_address); + + mac_addr_p = (unsigned char *)vio_get_attribute(dev, VETH_MAC_ADDR, +- &mac_len); ++ NULL); + if (!mac_addr_p) { + dev_err(&dev->dev, "Can't find VETH_MAC_ADDR attribute\n"); + return -EINVAL; + } +- /* Workaround for old/broken pHyp */ +- if (mac_len == 8) +- mac_addr_p += 2; +- else if (mac_len != 6) { +- dev_err(&dev->dev, "VETH_MAC_ADDR attribute wrong len %d\n", +- mac_len); +- return -EINVAL; +- } + + mcastFilterSize_p = (unsigned int *)vio_get_attribute(dev, + VETH_MCAST_FILTER_SIZE, NULL); +@@ -1373,6 +1365,17 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) + + netif_napi_add(netdev, &adapter->napi, ibmveth_poll, 16); + ++ /* ++ * Some older boxes running PHYP non-natively have an OF that returns ++ * a 8-byte local-mac-address field (and the first 2 bytes have to be ++ * ignored) while newer boxes' OF return a 6-byte field. Note that ++ * IEEE 1275 specifies that local-mac-address must be a 6-byte field. ++ * The RPA doc specifies that the first byte must be 10b, so we'll ++ * just look for it to solve this 8 vs. 6 byte field issue ++ */ ++ if ((*mac_addr_p & 0x3) != 0x02) ++ mac_addr_p += 2; ++ + adapter->mac_addr = 0; + memcpy(&adapter->mac_addr, mac_addr_p, 6); + +diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c +index 522fb10..fd4772a 100644 +--- a/drivers/net/ethernet/intel/e1000e/ethtool.c ++++ b/drivers/net/ethernet/intel/e1000e/ethtool.c +@@ -35,7 +35,6 @@ + #include + #include + #include +-#include + + #include "e1000.h" + +@@ -2054,19 +2053,7 @@ static int e1000_get_rxnfc(struct net_device *netdev, + } + } + +-static int e1000e_ethtool_begin(struct net_device *netdev) +-{ +- return pm_runtime_get_sync(netdev->dev.parent); +-} +- +-static void e1000e_ethtool_complete(struct net_device *netdev) +-{ +- pm_runtime_put_sync(netdev->dev.parent); +-} +- + static const struct ethtool_ops e1000_ethtool_ops = { +- .begin = e1000e_ethtool_begin, +- .complete = e1000e_ethtool_complete, + .get_settings = e1000_get_settings, + .set_settings = e1000_set_settings, + .get_drvinfo = e1000_get_drvinfo, +diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c +index 8692eca..1f93880 100644 +--- a/drivers/net/ethernet/intel/e1000e/netdev.c ++++ b/drivers/net/ethernet/intel/e1000e/netdev.c +@@ -3952,7 +3952,6 @@ static int e1000_open(struct net_device *netdev) + netif_start_queue(netdev); + + adapter->idle_check = true; +- hw->mac.get_link_status = true; + pm_runtime_put(&pdev->dev); + + /* fire a link status change interrupt to start the watchdog */ +@@ -4313,7 +4312,6 @@ static void e1000_phy_read_status(struct e1000_adapter *adapter) + (adapter->hw.phy.media_type == e1000_media_type_copper)) { + int ret_val; + +- pm_runtime_get_sync(&adapter->pdev->dev); + ret_val = e1e_rphy(hw, PHY_CONTROL, &phy->bmcr); + ret_val |= e1e_rphy(hw, PHY_STATUS, &phy->bmsr); + ret_val |= e1e_rphy(hw, PHY_AUTONEG_ADV, &phy->advertise); +@@ -4324,7 +4322,6 @@ static void e1000_phy_read_status(struct e1000_adapter *adapter) + ret_val |= e1e_rphy(hw, PHY_EXT_STATUS, &phy->estatus); + if (ret_val) + e_warn("Error reading PHY register\n"); +- pm_runtime_put_sync(&adapter->pdev->dev); + } else { + /* Do not read PHY registers if link is not up + * Set values to typical power-on defaults +@@ -5453,7 +5450,8 @@ release: + return retval; + } + +-static int __e1000_shutdown(struct pci_dev *pdev, bool runtime) ++static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake, ++ bool runtime) + { + struct net_device *netdev = pci_get_drvdata(pdev); + struct e1000_adapter *adapter = netdev_priv(netdev); +@@ -5477,6 +5475,10 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime) + } + e1000e_reset_interrupt_capability(adapter); + ++ retval = pci_save_state(pdev); ++ if (retval) ++ return retval; ++ + status = er32(STATUS); + if (status & E1000_STATUS_LU) + wufc &= ~E1000_WUFC_LNKC; +@@ -5532,6 +5534,13 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime) + ew32(WUFC, 0); + } + ++ *enable_wake = !!wufc; ++ ++ /* make sure adapter isn't asleep if manageability is enabled */ ++ if ((adapter->flags & FLAG_MNG_PT_ENABLED) || ++ (hw->mac.ops.check_mng_mode(hw))) ++ *enable_wake = true; ++ + if (adapter->hw.phy.type == e1000_phy_igp_3) + e1000e_igp3_phy_powerdown_workaround_ich8lan(&adapter->hw); + +@@ -5542,6 +5551,26 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime) + + pci_clear_master(pdev); + ++ return 0; ++} ++ ++static void e1000_power_off(struct pci_dev *pdev, bool sleep, bool wake) ++{ ++ if (sleep && wake) { ++ pci_prepare_to_sleep(pdev); ++ return; ++ } ++ ++ pci_wake_from_d3(pdev, wake); ++ pci_set_power_state(pdev, PCI_D3hot); ++} ++ ++static void e1000_complete_shutdown(struct pci_dev *pdev, bool sleep, ++ bool wake) ++{ ++ struct net_device *netdev = pci_get_drvdata(pdev); ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ + /* The pci-e switch on some quad port adapters will report a + * correctable error when the MAC transitions from D0 to D3. To + * prevent this we need to mask off the correctable errors on the +@@ -5555,13 +5584,12 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime) + pcie_capability_write_word(us_dev, PCI_EXP_DEVCTL, + (devctl & ~PCI_EXP_DEVCTL_CERE)); + +- pci_save_state(pdev); +- pci_prepare_to_sleep(pdev); ++ e1000_power_off(pdev, sleep, wake); + + pcie_capability_write_word(us_dev, PCI_EXP_DEVCTL, devctl); ++ } else { ++ e1000_power_off(pdev, sleep, wake); + } +- +- return 0; + } + + #ifdef CONFIG_PCIEASPM +@@ -5612,7 +5640,9 @@ static int __e1000_resume(struct pci_dev *pdev) + if (aspm_disable_flag) + e1000e_disable_aspm(pdev, aspm_disable_flag); + +- pci_set_master(pdev); ++ pci_set_power_state(pdev, PCI_D0); ++ pci_restore_state(pdev); ++ pci_save_state(pdev); + + e1000e_set_interrupt_capability(adapter); + if (netif_running(netdev)) { +@@ -5678,8 +5708,14 @@ static int __e1000_resume(struct pci_dev *pdev) + static int e1000_suspend(struct device *dev) + { + struct pci_dev *pdev = to_pci_dev(dev); ++ int retval; ++ bool wake; ++ ++ retval = __e1000_shutdown(pdev, &wake, false); ++ if (!retval) ++ e1000_complete_shutdown(pdev, true, wake); + +- return __e1000_shutdown(pdev, false); ++ return retval; + } + + static int e1000_resume(struct device *dev) +@@ -5702,10 +5738,13 @@ static int e1000_runtime_suspend(struct device *dev) + struct net_device *netdev = pci_get_drvdata(pdev); + struct e1000_adapter *adapter = netdev_priv(netdev); + +- if (!e1000e_pm_ready(adapter)) +- return 0; ++ if (e1000e_pm_ready(adapter)) { ++ bool wake; + +- return __e1000_shutdown(pdev, true); ++ __e1000_shutdown(pdev, &wake, true); ++ } ++ ++ return 0; + } + + static int e1000_idle(struct device *dev) +@@ -5743,7 +5782,12 @@ static int e1000_runtime_resume(struct device *dev) + + static void e1000_shutdown(struct pci_dev *pdev) + { +- __e1000_shutdown(pdev, false); ++ bool wake = false; ++ ++ __e1000_shutdown(pdev, &wake, false); ++ ++ if (system_state == SYSTEM_POWER_OFF) ++ e1000_complete_shutdown(pdev, false, wake); + } + + #ifdef CONFIG_NET_POLL_CONTROLLER +@@ -5864,9 +5908,9 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev) + "Cannot re-enable PCI device after reset.\n"); + result = PCI_ERS_RESULT_DISCONNECT; + } else { ++ pci_set_master(pdev); + pdev->state_saved = true; + pci_restore_state(pdev); +- pci_set_master(pdev); + + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); +@@ -6297,11 +6341,7 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + + /* initialize the wol settings based on the eeprom settings */ + adapter->wol = adapter->eeprom_wol; +- +- /* make sure adapter isn't asleep if manageability is enabled */ +- if (adapter->wol || (adapter->flags & FLAG_MNG_PT_ENABLED) || +- (hw->mac.ops.check_mng_mode(hw))) +- device_wakeup_enable(&pdev->dev); ++ device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol); + + /* save off EEPROM version number */ + e1000_read_nvm(&adapter->hw, 5, 1, &adapter->eeprom_vers); +diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +index 911956e..0d03d38 100644 +--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c ++++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +@@ -2407,16 +2407,6 @@ static irqreturn_t ixgbe_msix_other(int irq, void *data) + * with the write to EICR. + */ + eicr = IXGBE_READ_REG(hw, IXGBE_EICS); +- +- /* The lower 16bits of the EICR register are for the queue interrupts +- * which should be masked here in order to not accidently clear them if +- * the bits are high when ixgbe_msix_other is called. There is a race +- * condition otherwise which results in possible performance loss +- * especially if the ixgbe_msix_other interrupt is triggering +- * consistently (as it would when PPS is turned on for the X540 device) +- */ +- eicr &= 0xFFFF0000; +- + IXGBE_WRITE_REG(hw, IXGBE_EICR, eicr); + + if (eicr & IXGBE_EICR_LSC) +diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c +index 8adeb4d..73ce7dd 100644 +--- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c ++++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c +@@ -670,7 +670,7 @@ static int pch_gbe_init_phy(struct pch_gbe_adapter *adapter) + } + adapter->hw.phy.addr = adapter->mii.phy_id; + pr_debug("phy_addr = %d\n", adapter->mii.phy_id); +- if (addr == PCH_GBE_PHY_REGS_LEN) ++ if (addr == 32) + return -EAGAIN; + /* Selected the phy and isolate the rest */ + for (addr = 0; addr < PCH_GBE_PHY_REGS_LEN; addr++) { +diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c +index 2d56d71..2d849da 100644 +--- a/drivers/net/ethernet/realtek/r8169.c ++++ b/drivers/net/ethernet/realtek/r8169.c +@@ -5779,14 +5779,6 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, + goto err_stop_0; + } + +- /* 8168evl does not automatically pad to minimum length. */ +- if (unlikely(tp->mac_version == RTL_GIGA_MAC_VER_34 && +- skb->len < ETH_ZLEN)) { +- if (skb_padto(skb, ETH_ZLEN)) +- goto err_update_stats; +- skb_put(skb, ETH_ZLEN - skb->len); +- } +- + if (unlikely(le32_to_cpu(txd->opts1) & DescOwn)) + goto err_stop_0; + +@@ -5858,7 +5850,6 @@ err_dma_1: + rtl8169_unmap_tx_skb(d, tp->tx_skb + entry, txd); + err_dma_0: + dev_kfree_skb(skb); +-err_update_stats: + dev->stats.tx_dropped++; + return NETDEV_TX_OK; + +diff --git a/drivers/net/ethernet/xilinx/xilinx_emacps.c b/drivers/net/ethernet/xilinx/xilinx_emacps.c +index 1a0db68..d770ab1 100644 +--- a/drivers/net/ethernet/xilinx/xilinx_emacps.c ++++ b/drivers/net/ethernet/xilinx/xilinx_emacps.c +@@ -489,6 +489,7 @@ MDC_DIV_64, MDC_DIV_96, MDC_DIV_128, MDC_DIV_224 }; + struct ring_info { + struct sk_buff *skb; + dma_addr_t mapping; ++ size_t len; + }; + + /* DMA buffer descriptor structure. Each BD is two words */ +@@ -524,6 +525,7 @@ struct net_local { + + spinlock_t tx_lock; + spinlock_t rx_lock; ++ spinlock_t nwctrlreg_lock; + + struct platform_device *pdev; + struct net_device *ndev; /* this device */ +@@ -551,7 +553,6 @@ struct net_local { + /* RX ip/tcp/udp checksum */ + unsigned ip_summed; + unsigned int enetnum; +- unsigned int board_type; + unsigned int lastrxfrmscntr; + #ifdef CONFIG_XILINX_PS_EMAC_HWTSTAMP + unsigned int ptpenetclk; +@@ -650,39 +651,6 @@ static int xemacps_mdio_reset(struct mii_bus *bus) + return 0; + } + +-static void xemacps_phy_init(struct net_device *ndev) +-{ +- struct net_local *lp = netdev_priv(ndev); +- u16 regval; +- int i = 0; +- +- /* set RX delay */ +- regval = xemacps_mdio_read(lp->mii_bus, lp->phy_dev->addr, 20); +- /* 0x0080 for 100Mbps, 0x0060 for 1Gbps. */ +- regval |= 0x0080; +- xemacps_mdio_write(lp->mii_bus, lp->phy_dev->addr, 20, regval); +- +- /* 0x2100 for 100Mbps, 0x0140 for 1Gbps. */ +- xemacps_mdio_write(lp->mii_bus, lp->phy_dev->addr, 0, 0x2100); +- +- regval = xemacps_mdio_read(lp->mii_bus, lp->phy_dev->addr, 0); +- regval |= 0x8000; +- xemacps_mdio_write(lp->mii_bus, lp->phy_dev->addr, 0, regval); +- for (i = 0; i < 10; i++) +- mdelay(500); +-#ifdef DEBUG_VERBOSE +- dev_dbg(&lp->pdev->dev, +- "phy register dump, start from 0, four in a row."); +- for (i = 0; i <= 30; i++) { +- if (!(i%4)) +- dev_dbg(&lp->pdev->dev, "\n %02d: ", i); +- regval = xemacps_mdio_read(lp->mii_bus, lp->phy_dev->addr, i); +- dev_dbg(&lp->pdev->dev, " 0x%08x", regval); +- } +- dev_dbg(&lp->pdev->dev, "\n"); +-#endif +-} +- + /** + * xemacps_set_freq() - Set a clock to a new frequency + * @clk Pointer to the clock to change +@@ -692,10 +660,8 @@ static void xemacps_phy_init(struct net_device *ndev) + static void xemacps_set_freq(struct clk *clk, long rate, struct device *dev) + { + rate = clk_round_rate(clk, rate); +- if (rate < 0) { +- dev_warn(dev, "round rate failed\n"); ++ if (rate < 0) + return; +- } + + dev_info(dev, "Set clk to %ld Hz\n", rate); + if (clk_set_rate(clk, rate)) +@@ -749,23 +715,24 @@ static void xemacps_adjust_link(struct net_device *ndev) + xemacps_write(lp->baseaddr, XEMACPS_NWCFG_OFFSET, + regval); + +- if (regval & XEMACPS_NWCFG_1000_MASK) { +- xemacps_mdio_write(lp->mii_bus, +- gmii2rgmii_phydev->addr, +- XEMACPS_GMII2RGMII_REG_NUM, +- XEMACPS_GMII2RGMII_SPEED1000_FD); +- } else if (regval & XEMACPS_NWCFG_100_MASK) { +- xemacps_mdio_write(lp->mii_bus, +- gmii2rgmii_phydev->addr, +- XEMACPS_GMII2RGMII_REG_NUM, +- XEMACPS_GMII2RGMII_SPEED100_FD); +- } else { +- xemacps_mdio_write(lp->mii_bus, +- gmii2rgmii_phydev->addr, +- XEMACPS_GMII2RGMII_REG_NUM, +- XEMACPS_GMII2RGMII_SPEED10_FD); ++ if (gmii2rgmii_phydev != NULL) { ++ if (regval & XEMACPS_NWCFG_1000_MASK) { ++ xemacps_mdio_write(lp->mii_bus, ++ gmii2rgmii_phydev->addr, ++ XEMACPS_GMII2RGMII_REG_NUM, ++ XEMACPS_GMII2RGMII_SPEED1000_FD); ++ } else if (regval & XEMACPS_NWCFG_100_MASK) { ++ xemacps_mdio_write(lp->mii_bus, ++ gmii2rgmii_phydev->addr, ++ XEMACPS_GMII2RGMII_REG_NUM, ++ XEMACPS_GMII2RGMII_SPEED100_FD); ++ } else { ++ xemacps_mdio_write(lp->mii_bus, ++ gmii2rgmii_phydev->addr, ++ XEMACPS_GMII2RGMII_REG_NUM, ++ XEMACPS_GMII2RGMII_SPEED10_FD); ++ } + } +- + lp->speed = phydev->speed; + lp->duplex = phydev->duplex; + status_change = 1; +@@ -855,10 +822,7 @@ static int xemacps_mii_probe(struct net_device *ndev) + lp->duplex = -1; + lp->phy_dev = phydev; + +- if (lp->board_type == BOARD_TYPE_ZYNQ) +- phy_start(lp->phy_dev); +- else +- xemacps_phy_init(lp->ndev); ++ phy_start(lp->phy_dev); + + dev_dbg(&lp->pdev->dev, "phy_addr 0x%x, phy_id 0x%08x\n", + lp->phy_dev->addr, lp->phy_dev->phy_id); +@@ -876,9 +840,9 @@ static int xemacps_mii_probe(struct net_device *ndev) + ndev->name); + return -1; + } +- } +- +- lp->gmii2rgmii_phy_dev = phydev; ++ lp->gmii2rgmii_phy_dev = phydev; ++ } else ++ lp->gmii2rgmii_phy_dev = NULL; + + return 0; + } +@@ -1153,7 +1117,7 @@ static int xemacps_rx(struct net_local *lp, int budget) + skb = lp->rx_skb[lp->rx_bd_ci].skb; + dma_unmap_single(lp->ndev->dev.parent, + lp->rx_skb[lp->rx_bd_ci].mapping, +- XEMACPS_RX_BUF_SIZE, ++ lp->rx_skb[lp->rx_bd_ci].len, + DMA_FROM_DEVICE); + + /* setup received skb and send it upstream */ +@@ -1193,6 +1157,7 @@ static int xemacps_rx(struct net_local *lp, int budget) + new_skb = netdev_alloc_skb(lp->ndev, XEMACPS_RX_BUF_SIZE); + if (new_skb == NULL) { + dev_err(&lp->ndev->dev, "no memory for new sk_buff\n"); ++ lp->rx_skb[lp->rx_bd_ci].skb = NULL; + return 0; + } + /* Get dma handle of skb->data */ +@@ -1204,6 +1169,7 @@ static int xemacps_rx(struct net_local *lp, int budget) + | (new_skb_baddr); + lp->rx_skb[lp->rx_bd_ci].skb = new_skb; + lp->rx_skb[lp->rx_bd_ci].mapping = new_skb_baddr; ++ lp->rx_skb[lp->rx_bd_ci].len = XEMACPS_RX_BUF_SIZE; + + cur_p->ctrl = 0; + cur_p->addr &= (~XEMACPS_RXBUF_NEW_MASK); +@@ -1240,6 +1206,8 @@ static int xemacps_rx_poll(struct napi_struct *napi, int budget) + while (work_done < budget) { + regval = xemacps_read(lp->baseaddr, XEMACPS_RXSR_OFFSET); + xemacps_write(lp->baseaddr, XEMACPS_RXSR_OFFSET, regval); ++ if (regval & XEMACPS_RXSR_HRESPNOK_MASK) ++ dev_err(&lp->pdev->dev, "RX error 0x%x\n", regval); + temp_work_done = xemacps_rx(lp, budget - work_done); + work_done += temp_work_done; + if (temp_work_done <= 0) +@@ -1271,7 +1239,6 @@ static void xemacps_tx_poll(unsigned long data) + struct net_local *lp = netdev_priv(ndev); + u32 regval; + u32 len = 0; +- u32 leninbd = 0; + unsigned int bdcount = 0; + unsigned int bdpartialcount = 0; + unsigned int sop = 0; +@@ -1285,6 +1252,8 @@ static void xemacps_tx_poll(unsigned long data) + regval = xemacps_read(lp->baseaddr, XEMACPS_TXSR_OFFSET); + xemacps_write(lp->baseaddr, XEMACPS_TXSR_OFFSET, regval); + dev_dbg(&lp->pdev->dev, "TX status 0x%x\n", regval); ++ if (regval & (XEMACPS_TXSR_HRESPNOK_MASK | XEMACPS_TXSR_BUFEXH_MASK)) ++ dev_err(&lp->pdev->dev, "TX error 0x%x\n", regval); + + /* This may happen when a buffer becomes complete + * between reading the ISR and scanning the descriptors. +@@ -1327,8 +1296,7 @@ static void xemacps_tx_poll(unsigned long data) + rp = &lp->tx_skb[lp->tx_bd_ci]; + skb = rp->skb; + +- leninbd = cur_p->ctrl & XEMACPS_TXBUF_LEN_MASK; +- len += leninbd; ++ len += (cur_p->ctrl & XEMACPS_TXBUF_LEN_MASK); + + #ifdef CONFIG_XILINX_PS_EMAC_HWTSTAMP + if ((lp->hwtstamp_config.tx_type == HWTSTAMP_TX_ON) && +@@ -1349,22 +1317,21 @@ static void xemacps_tx_poll(unsigned long data) + } + #endif /* CONFIG_XILINX_PS_EMAC_HWTSTAMP */ + +- dma_unmap_single(&lp->pdev->dev, rp->mapping, leninbd, ++ dma_unmap_single(&lp->pdev->dev, rp->mapping, rp->len, + DMA_TO_DEVICE); +- if (skb != NULL) +- dev_kfree_skb(skb); + rp->skb = NULL; ++ dev_kfree_skb(skb); + /* log tx completed packets and bytes, errors logs + * are in other error counters. + */ + if (cur_p->ctrl & XEMACPS_TXBUF_LAST_MASK) { +- if (!(cur_p->ctrl & XEMACPS_TXBUF_ERR_MASK)) { +- lp->stats.tx_packets++; +- lp->stats.tx_bytes += len; +- } ++ lp->stats.tx_packets++; ++ lp->stats.tx_bytes += len; ++ len = 0; + } + +- /* Preserve used and wrap bits; clear everything else. */ ++ /* Set used bit, preserve wrap bit; clear everything else. */ ++ cur_p->ctrl |= XEMACPS_TXBUF_USED_MASK; + cur_p->ctrl &= (XEMACPS_TXBUF_USED_MASK | + XEMACPS_TXBUF_WRAP_MASK); + +@@ -1407,11 +1374,13 @@ static irqreturn_t xemacps_interrupt(int irq, void *dev_id) + } + + if (regisr & XEMACPS_IXR_RXUSED_MASK) { ++ spin_lock(&lp->nwctrlreg_lock); + regctrl = xemacps_read(lp->baseaddr, + XEMACPS_NWCTRL_OFFSET); + regctrl |= XEMACPS_NWCTRL_FLUSH_DPRAM_MASK; + xemacps_write(lp->baseaddr, + XEMACPS_NWCTRL_OFFSET, regctrl); ++ spin_unlock(&lp->nwctrlreg_lock); + } + + if (regisr & XEMACPS_IXR_FRAMERX_MASK) { +@@ -1437,7 +1406,7 @@ static void xemacps_clean_rings(struct net_local *lp) + if (lp->rx_skb && lp->rx_skb[i].skb) { + dma_unmap_single(lp->ndev->dev.parent, + lp->rx_skb[i].mapping, +- XEMACPS_RX_BUF_SIZE, ++ lp->rx_skb[i].len, + DMA_FROM_DEVICE); + + dev_kfree_skb(lp->rx_skb[i].skb); +@@ -1450,7 +1419,7 @@ static void xemacps_clean_rings(struct net_local *lp) + if (lp->tx_skb && lp->tx_skb[i].skb) { + dma_unmap_single(lp->ndev->dev.parent, + lp->tx_skb[i].mapping, +- lp->tx_skb[i].skb->len, ++ lp->tx_skb[i].len, + DMA_TO_DEVICE); + + dev_kfree_skb(lp->tx_skb[i].skb); +@@ -1545,6 +1514,7 @@ static int xemacps_descriptor_init(struct net_local *lp) + | (new_skb_baddr); + lp->rx_skb[i].skb = new_skb; + lp->rx_skb[i].mapping = new_skb_baddr; ++ lp->rx_skb[i].len = XEMACPS_RX_BUF_SIZE; + wmb(); + } + cur_p = &lp->rx_bd[XEMACPS_RECV_BD_CNT - 1]; +@@ -1660,8 +1630,7 @@ static void xemacps_init_hw(struct net_local *lp) + regval |= XEMACPS_NWCFG_100_MASK; + regval |= XEMACPS_NWCFG_HDRXEN_MASK; + +- if (lp->board_type == BOARD_TYPE_ZYNQ) +- regval |= (MDC_DIV_224 << XEMACPS_NWCFG_MDC_SHIFT_MASK); ++ regval |= (MDC_DIV_224 << XEMACPS_NWCFG_MDC_SHIFT_MASK); + if (lp->ndev->flags & IFF_PROMISC) /* copy all */ + regval |= XEMACPS_NWCFG_COPYALLEN_MASK; + if (!(lp->ndev->flags & IFF_BROADCAST)) /* No broadcast */ +@@ -1719,8 +1688,7 @@ static void xemacps_resetrx_for_no_rxdata(unsigned long data) + + tempcntr = xemacps_read(lp->baseaddr, XEMACPS_RXCNT_OFFSET); + if ((!tempcntr) && (!(lp->lastrxfrmscntr))) { +- spin_lock_bh(&lp->tx_lock); +- spin_lock_irqsave(&lp->rx_lock, flags); ++ spin_lock_irqsave(&lp->nwctrlreg_lock, flags); + regctrl = xemacps_read(lp->baseaddr, + XEMACPS_NWCTRL_OFFSET); + regctrl &= (~XEMACPS_NWCTRL_RXEN_MASK); +@@ -1729,8 +1697,7 @@ static void xemacps_resetrx_for_no_rxdata(unsigned long data) + regctrl = xemacps_read(lp->baseaddr, XEMACPS_NWCTRL_OFFSET); + regctrl |= (XEMACPS_NWCTRL_RXEN_MASK); + xemacps_write(lp->baseaddr, XEMACPS_NWCTRL_OFFSET, regctrl); +- spin_unlock_irqrestore(&lp->rx_lock, flags); +- spin_unlock_bh(&lp->tx_lock); ++ spin_unlock_irqrestore(&lp->nwctrlreg_lock, flags); + } + lp->lastrxfrmscntr = tempcntr; + } +@@ -1744,57 +1711,62 @@ static void xemacps_update_stats(unsigned long data) + { + struct net_local *lp = (struct net_local *)data; + struct net_device_stats *nstat = &lp->stats; ++ u32 cnt; ++ ++ cnt = xemacps_read(lp->baseaddr, XEMACPS_RXUNDRCNT_OFFSET); ++ nstat->rx_errors += cnt; ++ nstat->rx_length_errors += cnt; ++ ++ cnt = xemacps_read(lp->baseaddr, XEMACPS_RXOVRCNT_OFFSET); ++ nstat->rx_errors += cnt; ++ nstat->rx_length_errors += cnt; ++ ++ cnt = xemacps_read(lp->baseaddr, XEMACPS_RXJABCNT_OFFSET); ++ nstat->rx_errors += cnt; ++ nstat->rx_length_errors += cnt; ++ ++ cnt = xemacps_read(lp->baseaddr, XEMACPS_RXFCSCNT_OFFSET); ++ nstat->rx_errors += cnt; ++ nstat->rx_crc_errors += cnt; ++ ++ cnt = xemacps_read(lp->baseaddr, XEMACPS_RXLENGTHCNT_OFFSET); ++ nstat->rx_errors += cnt; ++ nstat->rx_length_errors += cnt; ++ ++ cnt = xemacps_read(lp->baseaddr, XEMACPS_RXALIGNCNT_OFFSET); ++ nstat->rx_errors += cnt; ++ nstat->rx_frame_errors += cnt; ++ ++ cnt = xemacps_read(lp->baseaddr, XEMACPS_RXRESERRCNT_OFFSET); ++ nstat->rx_errors += cnt; ++ nstat->rx_missed_errors += cnt; + +- nstat->rx_errors += +- (xemacps_read(lp->baseaddr, XEMACPS_RXUNDRCNT_OFFSET) + +- xemacps_read(lp->baseaddr, XEMACPS_RXOVRCNT_OFFSET) + +- xemacps_read(lp->baseaddr, XEMACPS_RXJABCNT_OFFSET) + +- xemacps_read(lp->baseaddr, XEMACPS_RXFCSCNT_OFFSET) + +- xemacps_read(lp->baseaddr, XEMACPS_RXLENGTHCNT_OFFSET) + +- xemacps_read(lp->baseaddr, XEMACPS_RXORCNT_OFFSET) + +- xemacps_read(lp->baseaddr, XEMACPS_RXRESERRCNT_OFFSET) + +- xemacps_read(lp->baseaddr, XEMACPS_RXALIGNCNT_OFFSET)); +- nstat->rx_length_errors += +- (xemacps_read(lp->baseaddr, XEMACPS_RXUNDRCNT_OFFSET) + +- xemacps_read(lp->baseaddr, XEMACPS_RXOVRCNT_OFFSET) + +- xemacps_read(lp->baseaddr, XEMACPS_RXJABCNT_OFFSET) + +- xemacps_read(lp->baseaddr, XEMACPS_RXLENGTHCNT_OFFSET)); +- nstat->rx_over_errors += +- xemacps_read(lp->baseaddr, XEMACPS_RXORCNT_OFFSET); +- nstat->rx_crc_errors += +- xemacps_read(lp->baseaddr, XEMACPS_RXFCSCNT_OFFSET); +- nstat->rx_frame_errors += +- xemacps_read(lp->baseaddr, XEMACPS_RXALIGNCNT_OFFSET); +- nstat->rx_fifo_errors += +- xemacps_read(lp->baseaddr, XEMACPS_RXORCNT_OFFSET); +- nstat->tx_errors += +- (xemacps_read(lp->baseaddr, XEMACPS_TXURUNCNT_OFFSET) + +- xemacps_read(lp->baseaddr, +- XEMACPS_SNGLCOLLCNT_OFFSET) + +- xemacps_read(lp->baseaddr, +- XEMACPS_MULTICOLLCNT_OFFSET) + +- xemacps_read(lp->baseaddr, +- XEMACPS_EXCESSCOLLCNT_OFFSET) + +- xemacps_read(lp->baseaddr, +- XEMACPS_LATECOLLCNT_OFFSET) + +- xemacps_read(lp->baseaddr, +- XEMACPS_CSENSECNT_OFFSET)); +- nstat->tx_aborted_errors += +- xemacps_read(lp->baseaddr, +- XEMACPS_EXCESSCOLLCNT_OFFSET); +- nstat->tx_carrier_errors += +- xemacps_read(lp->baseaddr, XEMACPS_CSENSECNT_OFFSET); +- nstat->tx_fifo_errors += +- xemacps_read(lp->baseaddr, XEMACPS_TXURUNCNT_OFFSET); +- nstat->collisions += +- (xemacps_read(lp->baseaddr, +- XEMACPS_SNGLCOLLCNT_OFFSET) + +- xemacps_read(lp->baseaddr, +- XEMACPS_MULTICOLLCNT_OFFSET) + +- xemacps_read(lp->baseaddr, +- XEMACPS_EXCESSCOLLCNT_OFFSET) + +- xemacps_read(lp->baseaddr, +- XEMACPS_LATECOLLCNT_OFFSET)); ++ cnt = xemacps_read(lp->baseaddr, XEMACPS_RXORCNT_OFFSET); ++ nstat->rx_errors += cnt; ++ nstat->rx_fifo_errors += cnt; ++ ++ cnt = xemacps_read(lp->baseaddr, XEMACPS_TXURUNCNT_OFFSET); ++ nstat->tx_errors += cnt; ++ nstat->tx_fifo_errors += cnt; ++ ++ cnt = xemacps_read(lp->baseaddr, XEMACPS_SNGLCOLLCNT_OFFSET); ++ nstat->collisions += cnt; ++ ++ cnt = xemacps_read(lp->baseaddr, XEMACPS_MULTICOLLCNT_OFFSET); ++ nstat->collisions += cnt; ++ ++ cnt = xemacps_read(lp->baseaddr, XEMACPS_EXCESSCOLLCNT_OFFSET); ++ nstat->tx_errors += cnt; ++ nstat->tx_aborted_errors += cnt; ++ nstat->collisions += cnt; ++ ++ cnt = xemacps_read(lp->baseaddr, XEMACPS_LATECOLLCNT_OFFSET); ++ nstat->tx_errors += cnt; ++ nstat->collisions += cnt; ++ ++ cnt = xemacps_read(lp->baseaddr, XEMACPS_CSENSECNT_OFFSET); ++ nstat->tx_errors += cnt; ++ nstat->tx_carrier_errors += cnt; + } + + /** +@@ -1906,19 +1878,13 @@ static int xemacps_close(struct net_device *ndev) + netif_stop_queue(ndev); + napi_disable(&lp->napi); + tasklet_disable(&lp->tx_bdreclaim_tasklet); +- spin_lock_bh(&lp->tx_lock); +- spin_lock(&lp->rx_lock); +- xemacps_reset_hw(lp); + netif_carrier_off(ndev); +- spin_unlock(&lp->rx_lock); +- spin_unlock_bh(&lp->tx_lock); +- if (lp->phy_dev) { +- if (lp->board_type == BOARD_TYPE_ZYNQ) +- phy_disconnect(lp->phy_dev); +- } ++ xemacps_reset_hw(lp); ++ if (lp->phy_dev) ++ phy_disconnect(lp->phy_dev); + if (lp->gmii2rgmii_phy_node) + phy_disconnect(lp->gmii2rgmii_phy_dev); +- ++ mdelay(500); + xemacps_descriptor_free(lp); + + pm_runtime_put(&lp->pdev->dev); +@@ -1944,10 +1910,8 @@ static void xemacps_reinit_for_txtimeout(struct work_struct *data) + xemacps_reset_hw(lp); + spin_unlock_bh(&lp->tx_lock); + +- if (lp->phy_dev) { +- if (lp->board_type == BOARD_TYPE_ZYNQ) +- phy_stop(lp->phy_dev); +- } ++ if (lp->phy_dev) ++ phy_stop(lp->phy_dev); + + xemacps_descriptor_free(lp); + rc = xemacps_descriptor_init(lp); +@@ -1962,10 +1926,8 @@ static void xemacps_reinit_for_txtimeout(struct work_struct *data) + lp->link = 0; + lp->speed = 0; + lp->duplex = -1; +- if (lp->phy_dev) { +- if (lp->board_type == BOARD_TYPE_ZYNQ) +- phy_start(lp->phy_dev); +- } ++ if (lp->phy_dev) ++ phy_start(lp->phy_dev); + napi_enable(&lp->napi); + tasklet_enable(&lp->tx_bdreclaim_tasklet); + netif_start_queue(lp->ndev); +@@ -2028,6 +1990,9 @@ static int xemacps_start_xmit(struct sk_buff *skb, struct net_device *ndev) + void *virt_addr; + skb_frag_t *frag; + struct xemacps_bd *cur_p; ++ unsigned long flags; ++ int bd_tail; ++ int temp_bd_index; + + nr_frags = skb_shinfo(skb)->nr_frags + 1; + spin_lock_bh(&lp->tx_lock); +@@ -2040,7 +2005,7 @@ static int xemacps_start_xmit(struct sk_buff *skb, struct net_device *ndev) + } + lp->tx_bd_freecnt -= nr_frags; + frag = &skb_shinfo(skb)->frags[0]; +- ++ bd_tail = lp->tx_bd_tail; + for (i = 0; i < nr_frags; i++) { + if (i == 0) { + len = skb_headlen(skb); +@@ -2052,23 +2017,23 @@ static int xemacps_start_xmit(struct sk_buff *skb, struct net_device *ndev) + mapping = dma_map_single(&lp->pdev->dev, virt_addr, + len, DMA_TO_DEVICE); + frag++; ++ skb_get(skb); + } + +- if (i == 0) +- lp->tx_skb[lp->tx_bd_tail].skb = skb; +- else +- lp->tx_skb[lp->tx_bd_tail].skb = NULL; ++ lp->tx_skb[lp->tx_bd_tail].skb = skb; + lp->tx_skb[lp->tx_bd_tail].mapping = mapping; ++ lp->tx_skb[lp->tx_bd_tail].len = len; + cur_p->addr = mapping; + + /* Preserve only critical status bits. Packet is NOT to be +- * committed to hardware at this time. ++ * committed to hardware at this time. This ensures that ++ * the Used bit will still be set. The clearing of Used bits ++ * happen in a loop after this loop. + */ + regval = cur_p->ctrl; + regval &= (XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK); + /* update length field */ + regval |= ((regval & ~XEMACPS_TXBUF_LEN_MASK) | len); +- regval &= ~XEMACPS_TXBUF_USED_MASK; + /* last fragment of this packet? */ + if (i == (nr_frags - 1)) + regval |= XEMACPS_TXBUF_LAST_MASK; +@@ -2079,11 +2044,43 @@ static int xemacps_start_xmit(struct sk_buff *skb, struct net_device *ndev) + + cur_p = &(lp->tx_bd[lp->tx_bd_tail]); + } +- wmb(); + ++ /* Remember the bd index for the first bd in the bd chain allocated ++ * for the fragments. The Used bit for the 1st BD will need to be ++ * updated last. ++ */ ++ temp_bd_index = bd_tail; ++ bd_tail++; ++ bd_tail = bd_tail % XEMACPS_SEND_BD_CNT; ++ cur_p = &(lp->tx_bd[bd_tail]); ++ /* Clear the used bits for the BDs for a packet that consists of ++ * multiple BDs. For single BD packets, this loop will not execute. ++ * For multiple BD packets, the Used bit updates will happen for ++ * all BDs except the 1st BD in the BD chain allocated for the packet. ++ */ ++ for (i = 1; i < nr_frags; i++) { ++ regval = cur_p->ctrl; ++ regval &= ~XEMACPS_TXBUF_USED_MASK; ++ cur_p->ctrl = regval; ++ bd_tail++; ++ bd_tail = bd_tail % XEMACPS_SEND_BD_CNT; ++ cur_p = &(lp->tx_bd[bd_tail]); ++ } ++ /* Clear the Used bit. For single BD packets, the clearing of ++ * Used bit happens here. For multi-BD packets, the clearing of ++ * the Used bit of the 1st BD happens here. ++ */ ++ cur_p = &(lp->tx_bd[temp_bd_index]); ++ regval = cur_p->ctrl; ++ regval &= ~XEMACPS_TXBUF_USED_MASK; ++ cur_p->ctrl = regval; ++ ++ wmb(); ++ spin_lock_irqsave(&lp->nwctrlreg_lock, flags); + regval = xemacps_read(lp->baseaddr, XEMACPS_NWCTRL_OFFSET); + xemacps_write(lp->baseaddr, XEMACPS_NWCTRL_OFFSET, + (regval | XEMACPS_NWCTRL_STARTTX_MASK)); ++ spin_unlock_irqrestore(&lp->nwctrlreg_lock, flags); + + spin_unlock_bh(&lp->tx_lock); + ndev->trans_start = jiffies; +@@ -2344,12 +2341,10 @@ static void + xemacps_get_wol(struct net_device *ndev, struct ethtool_wolinfo *ewol) + { + struct net_local *lp = netdev_priv(ndev); +- unsigned long flags; + u32 regval; + + ewol->supported = WAKE_MAGIC | WAKE_ARP | WAKE_UCAST | WAKE_MCAST; +- spin_lock_irqsave(&lp->tx_lock, flags); +- spin_lock(&lp->rx_lock); ++ + regval = xemacps_read(lp->baseaddr, XEMACPS_WOL_OFFSET); + if (regval | XEMACPS_WOL_MCAST_MASK) + ewol->wolopts |= WAKE_MCAST; +@@ -2359,8 +2354,7 @@ xemacps_get_wol(struct net_device *ndev, struct ethtool_wolinfo *ewol) + ewol->wolopts |= WAKE_UCAST; + if (regval | XEMACPS_WOL_MAGIC_MASK) + ewol->wolopts |= WAKE_MAGIC; +- spin_unlock(&lp->rx_lock); +- spin_unlock_irqrestore(&lp->tx_lock, flags); ++ + } + + /** +@@ -2377,14 +2371,11 @@ static int + xemacps_set_wol(struct net_device *ndev, struct ethtool_wolinfo *ewol) + { + struct net_local *lp = netdev_priv(ndev); +- unsigned long flags; + u32 regval; + + if (ewol->wolopts & ~(WAKE_MAGIC | WAKE_ARP | WAKE_UCAST | WAKE_MCAST)) + return -EOPNOTSUPP; + +- spin_lock_irqsave(&lp->tx_lock, flags); +- spin_lock(&lp->rx_lock); + regval = xemacps_read(lp->baseaddr, XEMACPS_WOL_OFFSET); + regval &= ~(XEMACPS_WOL_MCAST_MASK | XEMACPS_WOL_ARP_MASK | + XEMACPS_WOL_SPEREG1_MASK | XEMACPS_WOL_MAGIC_MASK); +@@ -2399,8 +2390,6 @@ xemacps_set_wol(struct net_device *ndev, struct ethtool_wolinfo *ewol) + regval |= XEMACPS_WOL_MCAST_MASK; + + xemacps_write(lp->baseaddr, XEMACPS_WOL_OFFSET, regval); +- spin_unlock(&lp->rx_lock); +- spin_unlock_irqrestore(&lp->tx_lock, flags); + + return 0; + } +@@ -2418,18 +2407,13 @@ xemacps_get_pauseparam(struct net_device *ndev, + struct ethtool_pauseparam *epauseparm) + { + struct net_local *lp = netdev_priv(ndev); +- unsigned long flags; + u32 regval; + + epauseparm->autoneg = 0; + epauseparm->rx_pause = 0; + +- spin_lock_irqsave(&lp->tx_lock, flags); +- spin_lock(&lp->rx_lock); + regval = xemacps_read(lp->baseaddr, XEMACPS_NWCFG_OFFSET); + epauseparm->tx_pause = regval & XEMACPS_NWCFG_PAUSEEN_MASK; +- spin_unlock(&lp->rx_lock); +- spin_unlock_irqrestore(&lp->tx_lock, flags); + } + + /** +@@ -2446,7 +2430,6 @@ xemacps_set_pauseparam(struct net_device *ndev, + struct ethtool_pauseparam *epauseparm) + { + struct net_local *lp = netdev_priv(ndev); +- unsigned long flags; + u32 regval; + + if (netif_running(ndev)) { +@@ -2455,8 +2438,6 @@ xemacps_set_pauseparam(struct net_device *ndev, + return -EFAULT; + } + +- spin_lock_irqsave(&lp->tx_lock, flags); +- spin_lock(&lp->rx_lock); + regval = xemacps_read(lp->baseaddr, XEMACPS_NWCFG_OFFSET); + + if (epauseparm->tx_pause) +@@ -2465,9 +2446,6 @@ xemacps_set_pauseparam(struct net_device *ndev, + regval &= ~XEMACPS_NWCFG_PAUSEEN_MASK; + + xemacps_write(lp->baseaddr, XEMACPS_NWCFG_OFFSET, regval); +- spin_unlock(&lp->rx_lock); +- spin_unlock_irqrestore(&lp->tx_lock, flags); +- + return 0; + } + +@@ -2598,8 +2576,6 @@ static int xemacps_probe(struct platform_device *pdev) + struct resource *r_irq = NULL; + struct net_device *ndev; + struct net_local *lp; +- struct device_node *np; +- const void *prop; + u32 regval = 0; + int rc = -ENXIO; + +@@ -2626,6 +2602,7 @@ static int xemacps_probe(struct platform_device *pdev) + + spin_lock_init(&lp->tx_lock); + spin_lock_init(&lp->rx_lock); ++ spin_lock_init(&lp->nwctrlreg_lock); + + lp->baseaddr = ioremap(r_mem->start, (r_mem->end - r_mem->start + 1)); + if (!lp->baseaddr) { +@@ -2655,7 +2632,6 @@ static int xemacps_probe(struct platform_device *pdev) + netif_napi_add(ndev, &lp->napi, xemacps_rx_poll, XEMACPS_NAPI_WEIGHT); + + lp->ip_summed = CHECKSUM_UNNECESSARY; +- lp->board_type = BOARD_TYPE_ZYNQ; + + rc = register_netdev(ndev); + if (rc) { +@@ -2668,67 +2644,43 @@ static int xemacps_probe(struct platform_device *pdev) + else + lp->enetnum = 1; + +- np = of_get_next_parent(lp->pdev->dev.of_node); +- np = of_get_next_parent(np); +- prop = of_get_property(np, "compatible", NULL); +- +- if (prop != NULL) { +- if ((strcmp((const char *)prop, "xlnx,zynq-ep107")) == 0) +- lp->board_type = BOARD_TYPE_PEEP; +- else +- lp->board_type = BOARD_TYPE_ZYNQ; +- } else { +- lp->board_type = BOARD_TYPE_ZYNQ; ++ lp->aperclk = clk_get(&pdev->dev, "aper_clk"); ++ if (IS_ERR(lp->aperclk)) { ++ dev_err(&pdev->dev, "aper_clk clock not found.\n"); ++ rc = PTR_ERR(lp->aperclk); ++ goto err_out_unregister_netdev; ++ } ++ lp->devclk = clk_get(&pdev->dev, "ref_clk"); ++ if (IS_ERR(lp->devclk)) { ++ dev_err(&pdev->dev, "ref_clk clock not found.\n"); ++ rc = PTR_ERR(lp->devclk); ++ goto err_out_clk_put_aper; + } +- if (lp->board_type == BOARD_TYPE_ZYNQ) { +- if (lp->enetnum == 0) +- lp->aperclk = clk_get_sys("GEM0_APER", NULL); +- else +- lp->aperclk = clk_get_sys("GEM1_APER", NULL); +- if (IS_ERR(lp->aperclk)) { +- dev_err(&pdev->dev, "APER clock not found.\n"); +- rc = PTR_ERR(lp->aperclk); +- goto err_out_unregister_netdev; +- } +- if (lp->enetnum == 0) +- lp->devclk = clk_get_sys("GEM0", NULL); +- else +- lp->devclk = clk_get_sys("GEM1", NULL); +- if (IS_ERR(lp->devclk)) { +- dev_err(&pdev->dev, "Device clock not found.\n"); +- rc = PTR_ERR(lp->devclk); +- goto err_out_clk_put_aper; +- } +- +- rc = clk_prepare_enable(lp->aperclk); +- if (rc) { +- dev_err(&pdev->dev, "Unable to enable APER clock.\n"); +- goto err_out_clk_put; +- } +- rc = clk_prepare_enable(lp->devclk); +- if (rc) { +- dev_err(&pdev->dev, "Unable to enable device clock.\n"); +- goto err_out_clk_dis_aper; +- } + +- lp->clk_rate_change_nb.notifier_call = xemacps_clk_notifier_cb; +- lp->clk_rate_change_nb.next = NULL; +- if (clk_notifier_register(lp->devclk, &lp->clk_rate_change_nb)) +- dev_warn(&pdev->dev, +- "Unable to register clock notifier.\n"); ++ rc = clk_prepare_enable(lp->aperclk); ++ if (rc) { ++ dev_err(&pdev->dev, "Unable to enable APER clock.\n"); ++ goto err_out_clk_put; ++ } ++ rc = clk_prepare_enable(lp->devclk); ++ if (rc) { ++ dev_err(&pdev->dev, "Unable to enable device clock.\n"); ++ goto err_out_clk_dis_aper; + } + ++ lp->clk_rate_change_nb.notifier_call = xemacps_clk_notifier_cb; ++ lp->clk_rate_change_nb.next = NULL; ++ if (clk_notifier_register(lp->devclk, &lp->clk_rate_change_nb)) ++ dev_warn(&pdev->dev, ++ "Unable to register clock notifier.\n"); ++ + #ifdef CONFIG_XILINX_PS_EMAC_HWTSTAMP +- if (lp->board_type == BOARD_TYPE_ZYNQ) { +- prop = of_get_property(lp->pdev->dev.of_node, +- "xlnx,ptp-enet-clock", NULL); +- if (prop) +- lp->ptpenetclk = (u32)be32_to_cpup(prop); +- else +- lp->ptpenetclk = 133333328; +- } else { +- lp->ptpenetclk = PEEP_TSU_CLK; +- } ++ prop = of_get_property(lp->pdev->dev.of_node, ++ "xlnx,ptp-enet-clock", NULL); ++ if (prop) ++ lp->ptpenetclk = (u32)be32_to_cpup(prop); ++ else ++ lp->ptpenetclk = 133333328; + #endif + + lp->phy_node = of_parse_phandle(lp->pdev->dev.of_node, +@@ -2743,11 +2695,10 @@ static int xemacps_probe(struct platform_device *pdev) + + lp->phy_interface = rc; + +- if (lp->board_type == BOARD_TYPE_ZYNQ) { +- /* Set MDIO clock divider */ +- regval = (MDC_DIV_224 << XEMACPS_NWCFG_MDC_SHIFT_MASK); +- xemacps_write(lp->baseaddr, XEMACPS_NWCFG_OFFSET, regval); +- } ++ /* Set MDIO clock divider */ ++ regval = (MDC_DIV_224 << XEMACPS_NWCFG_MDC_SHIFT_MASK); ++ xemacps_write(lp->baseaddr, XEMACPS_NWCFG_OFFSET, regval); ++ + + regval = XEMACPS_NWCTRL_MDEN_MASK; + xemacps_write(lp->baseaddr, XEMACPS_NWCTRL_OFFSET, regval); +diff --git a/drivers/net/wireless/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/iwlwifi/dvm/debugfs.c +index 2c056b1..5b9533e 100644 +--- a/drivers/net/wireless/iwlwifi/dvm/debugfs.c ++++ b/drivers/net/wireless/iwlwifi/dvm/debugfs.c +@@ -2237,15 +2237,15 @@ static ssize_t iwl_dbgfs_log_event_read(struct file *file, + size_t count, loff_t *ppos) + { + struct iwl_priv *priv = file->private_data; +- char *buf = NULL; +- ssize_t ret; ++ char *buf; ++ int pos = 0; ++ ssize_t ret = -ENOMEM; + +- ret = iwl_dump_nic_event_log(priv, true, &buf, true); +- if (ret < 0) +- goto err; +- ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); +-err: +- kfree(buf); ++ ret = pos = iwl_dump_nic_event_log(priv, true, &buf, true); ++ if (buf) { ++ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); ++ kfree(buf); ++ } + return ret; + } + +diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c +index a8632a4..bdba954 100644 +--- a/drivers/net/wireless/iwlwifi/dvm/sta.c ++++ b/drivers/net/wireless/iwlwifi/dvm/sta.c +@@ -707,7 +707,6 @@ void iwl_clear_ucode_stations(struct iwl_priv *priv, + void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx) + { + struct iwl_addsta_cmd sta_cmd; +- static const struct iwl_link_quality_cmd zero_lq = {}; + struct iwl_link_quality_cmd lq; + int i; + bool found = false; +@@ -746,9 +745,7 @@ void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx) + else + memcpy(&lq, priv->stations[i].lq, + sizeof(struct iwl_link_quality_cmd)); +- +- if (!memcmp(&lq, &zero_lq, sizeof(lq))) +- send_lq = true; ++ send_lq = true; + } + spin_unlock_bh(&priv->sta_lock); + ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); +diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c +index b7a5387..0bbea88 100644 +--- a/drivers/net/wireless/mwifiex/pcie.c ++++ b/drivers/net/wireless/mwifiex/pcie.c +@@ -1831,9 +1831,9 @@ static void mwifiex_pcie_cleanup(struct mwifiex_adapter *adapter) + if (pdev) { + pci_iounmap(pdev, card->pci_mmap); + pci_iounmap(pdev, card->pci_mmap1); ++ ++ pci_release_regions(pdev); + pci_disable_device(pdev); +- pci_release_region(pdev, 2); +- pci_release_region(pdev, 0); + pci_set_drvdata(pdev, NULL); + } + } +diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c +index 0b55706..197b446 100644 +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -4386,8 +4386,6 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) + + if (!rt2x00_rt(rt2x00dev, RT5390) && + !rt2x00_rt(rt2x00dev, RT5392)) { +- u8 min_gain = rt2x00_rt(rt2x00dev, RT3070) ? 1 : 2; +- + rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR17_TX_LO1_EN, 0); + if (rt2x00_rt(rt2x00dev, RT3070) || +@@ -4398,10 +4396,8 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) + &rt2x00dev->cap_flags)) + rt2x00_set_field8(&rfcsr, RFCSR17_R, 1); + } +- if (drv_data->txmixer_gain_24g >= min_gain) { +- rt2x00_set_field8(&rfcsr, RFCSR17_TXMIXER_GAIN, +- drv_data->txmixer_gain_24g); +- } ++ rt2x00_set_field8(&rfcsr, RFCSR17_TXMIXER_GAIN, ++ drv_data->txmixer_gain_24g); + rt2800_rfcsr_write(rt2x00dev, 17, rfcsr); + } + +diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c +index 8c1ecc5..f79cbcd 100644 +--- a/drivers/pci/pci-driver.c ++++ b/drivers/pci/pci-driver.c +@@ -628,7 +628,6 @@ static int pci_pm_suspend(struct device *dev) + goto Fixup; + } + +- pci_dev->state_saved = false; + if (pm->suspend) { + pci_power_t prev = pci_dev->current_state; + int error; +@@ -775,7 +774,6 @@ static int pci_pm_freeze(struct device *dev) + return 0; + } + +- pci_dev->state_saved = false; + if (pm->freeze) { + int error; + +@@ -864,7 +862,6 @@ static int pci_pm_poweroff(struct device *dev) + goto Fixup; + } + +- pci_dev->state_saved = false; + if (pm->poweroff) { + int error; + +@@ -990,7 +987,6 @@ static int pci_pm_runtime_suspend(struct device *dev) + if (!pm || !pm->runtime_suspend) + return -ENOSYS; + +- pci_dev->state_saved = false; + pci_dev->no_d3cold = false; + error = pm->runtime_suspend(dev); + suspend_report_result(pm->runtime_suspend, error); +diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c +index d1b4e00..5cb5820 100644 +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -651,11 +651,15 @@ static int pci_platform_power_transition(struct pci_dev *dev, pci_power_t state) + error = platform_pci_set_power_state(dev, state); + if (!error) + pci_update_current_state(dev, state); +- } else ++ /* Fall back to PCI_D0 if native PM is not supported */ ++ if (!dev->pm_cap) ++ dev->current_state = PCI_D0; ++ } else { + error = -ENODEV; +- +- if (error && !dev->pm_cap) /* Fall back to PCI_D0 */ +- dev->current_state = PCI_D0; ++ /* Fall back to PCI_D0 if native PM is not supported */ ++ if (!dev->pm_cap) ++ dev->current_state = PCI_D0; ++ } + + return error; + } +diff --git a/drivers/pwm/pwm-spear.c b/drivers/pwm/pwm-spear.c +index 0c644e7..83b21d9 100644 +--- a/drivers/pwm/pwm-spear.c ++++ b/drivers/pwm/pwm-spear.c +@@ -143,7 +143,7 @@ static int spear_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) + u32 val; + + rc = clk_enable(pc->clk); +- if (rc) ++ if (!rc) + return rc; + + val = spear_pwm_readl(pc, pwm->hwpwm, PWMCR); +@@ -209,12 +209,12 @@ static int spear_pwm_probe(struct platform_device *pdev) + pc->chip.npwm = NUM_PWM; + + ret = clk_prepare(pc->clk); +- if (ret) ++ if (!ret) + return ret; + + if (of_device_is_compatible(np, "st,spear1340-pwm")) { + ret = clk_enable(pc->clk); +- if (ret) { ++ if (!ret) { + clk_unprepare(pc->clk); + return ret; + } +diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig +index 36d7805..c88b8c2 100644 +--- a/drivers/remoteproc/Kconfig ++++ b/drivers/remoteproc/Kconfig +@@ -44,6 +44,8 @@ config STE_MODEM_RPROC + config ZYNQ_REMOTEPROC + tristate "Support ZYNQ remoteproc" + depends on ARCH_ZYNQ && SMP ++ depends on EXPERIMENTAL ++ depends on HAS_DMA + select REMOTEPROC + select RPMSG + select HOTPLUG_CPU +@@ -55,7 +57,8 @@ config ZYNQ_REMOTEPROC + config MB_REMOTEPROC + tristate "Support Microblaze remoteproc" + depends on ARCH_ZYNQ +- select REMOTEPROC ++ depends on EXPERIMENTAL ++ depends on HAS_DMA + select RPMSG + default m + help +diff --git a/drivers/rpmsg/rpmsg_freertos_statistic.c b/drivers/rpmsg/rpmsg_freertos_statistic.c +index 021dd7e..c09301a 100644 +--- a/drivers/rpmsg/rpmsg_freertos_statistic.c ++++ b/drivers/rpmsg/rpmsg_freertos_statistic.c +@@ -24,7 +24,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c +index 1c77423..16630aa 100644 +--- a/drivers/rtc/rtc-cmos.c ++++ b/drivers/rtc/rtc-cmos.c +@@ -805,8 +805,9 @@ static int cmos_suspend(struct device *dev) + mask = RTC_IRQMASK; + tmp &= ~mask; + CMOS_WRITE(tmp, RTC_CONTROL); +- hpet_mask_rtc_irq_bit(mask); + ++ /* shut down hpet emulation - we don't need it for alarm */ ++ hpet_mask_rtc_irq_bit(RTC_PIE|RTC_AIE|RTC_UIE); + cmos_checkintr(cmos, tmp); + } + spin_unlock_irq(&rtc_lock); +@@ -871,7 +872,6 @@ static int cmos_resume(struct device *dev) + rtc_update_irq(cmos->rtc, 1, mask); + tmp &= ~RTC_AIE; + hpet_mask_rtc_irq_bit(RTC_AIE); +- hpet_rtc_timer_init(); + } while (mask & RTC_AIE); + spin_unlock_irq(&rtc_lock); + } +diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c +index 56dcd7c..c44d13f 100644 +--- a/drivers/s390/char/sclp_cmd.c ++++ b/drivers/s390/char/sclp_cmd.c +@@ -567,8 +567,6 @@ static void __init sclp_add_standby_memory(void) + add_memory_merged(0); + } + +-#define MEM_SCT_SIZE (1UL << SECTION_SIZE_BITS) +- + static void __init insert_increment(u16 rn, int standby, int assigned) + { + struct memory_increment *incr, *new_incr; +@@ -581,7 +579,7 @@ static void __init insert_increment(u16 rn, int standby, int assigned) + new_incr->rn = rn; + new_incr->standby = standby; + if (!standby) +- new_incr->usecount = rzm > MEM_SCT_SIZE ? rzm/MEM_SCT_SIZE : 1; ++ new_incr->usecount = 1; + last_rn = 0; + prev = &sclp_mem_list; + list_for_each_entry(incr, &sclp_mem_list, list) { +diff --git a/drivers/spi/spi-xilinx-ps.c b/drivers/spi/spi-xilinx-ps.c +index 04973c3..a30f63b 100644 +--- a/drivers/spi/spi-xilinx-ps.c ++++ b/drivers/spi/spi-xilinx-ps.c +@@ -700,24 +700,16 @@ static int xspips_probe(struct platform_device *dev) + goto unmap_io; + } + +- if (xspi->irq == 58) +- xspi->aperclk = clk_get_sys("SPI0_APER", NULL); +- else +- xspi->aperclk = clk_get_sys("SPI1_APER", NULL); +- ++ xspi->aperclk = clk_get(&dev->dev, "aper_clk"); + if (IS_ERR(xspi->aperclk)) { +- dev_err(&dev->dev, "APER clock not found.\n"); ++ dev_err(&dev->dev, "aper_clk clock not found.\n"); + ret = PTR_ERR(xspi->aperclk); + goto free_irq; + } + +- if (xspi->irq == 58) +- xspi->devclk = clk_get_sys("SPI0", NULL); +- else +- xspi->devclk = clk_get_sys("SPI1", NULL); +- ++ xspi->devclk = clk_get(&dev->dev, "ref_clk"); + if (IS_ERR(xspi->devclk)) { +- dev_err(&dev->dev, "Device clock not found.\n"); ++ dev_err(&dev->dev, "ref_clk clock not found.\n"); + ret = PTR_ERR(xspi->devclk); + goto clk_put_aper; + } +diff --git a/drivers/spi/spi-xilinx-qps.c b/drivers/spi/spi-xilinx-qps.c +index c433cee..f911511 100644 +--- a/drivers/spi/spi-xilinx-qps.c ++++ b/drivers/spi/spi-xilinx-qps.c +@@ -428,6 +428,10 @@ static int xqspips_setup_transfer(struct spi_device *qspi, + return -EINVAL; + } + ++ if (transfer && (transfer->speed_hz == 0)) { ++ req_hz = qspi->max_speed_hz; ++ } ++ + /* Set the clock frequency */ + if (xqspi->speed_hz != req_hz) { + while ((baud_rate_val < 8) && +@@ -1072,16 +1076,16 @@ static int xqspips_probe(struct platform_device *dev) + dev_warn(&dev->dev, "couldn't determine configuration info " + "about dual memories. defaulting to single memory\n"); + +- xqspi->aperclk = clk_get_sys("LQSPI_APER", NULL); ++ xqspi->aperclk = clk_get(&dev->dev, "aper_clk"); + if (IS_ERR(xqspi->aperclk)) { +- dev_err(&dev->dev, "APER clock not found.\n"); ++ dev_err(&dev->dev, "aper_clk clock not found.\n"); + ret = PTR_ERR(xqspi->aperclk); + goto free_irq; + } + +- xqspi->devclk = clk_get_sys("LQSPI", NULL); ++ xqspi->devclk = clk_get(&dev->dev, "ref_clk"); + if (IS_ERR(xqspi->devclk)) { +- dev_err(&dev->dev, "Device clock not found.\n"); ++ dev_err(&dev->dev, "ref_clk clock not found.\n"); + ret = PTR_ERR(xqspi->devclk); + goto clk_put_aper; + } +@@ -1109,15 +1113,6 @@ static int xqspips_probe(struct platform_device *dev) + + init_completion(&xqspi->done); + +- prop = of_get_property(dev->dev.of_node, "bus-num", NULL); +- if (prop) { +- master->bus_num = be32_to_cpup(prop); +- } else { +- ret = -ENXIO; +- dev_err(&dev->dev, "couldn't determine bus-num\n"); +- goto clk_unreg_notif; +- } +- + prop = of_get_property(dev->dev.of_node, "num-chip-select", NULL); + if (prop) { + master->num_chipselect = be32_to_cpup(prop); +diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig +index 329bdb4..2af1c06 100644 +--- a/drivers/staging/Kconfig ++++ b/drivers/staging/Kconfig +@@ -142,4 +142,10 @@ source "drivers/staging/sb105x/Kconfig" + + source "drivers/staging/fwserial/Kconfig" + ++source "drivers/staging/video/axivdma/Kconfig" ++ ++source "drivers/staging/video/imageon/Kconfig" ++ ++source "drivers/staging/apf/Kconfig" ++ + endif # STAGING +diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile +index c7ec486..c40ffbe 100644 +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -63,3 +63,6 @@ obj-$(CONFIG_DRM_IMX) += imx-drm/ + obj-$(CONFIG_DGRP) += dgrp/ + obj-$(CONFIG_SB105X) += sb105x/ + obj-$(CONFIG_FIREWIRE_SERIAL) += fwserial/ ++obj-$(CONFIG_XILINX_VIDEO_IP) += video/axivdma/ ++obj-$(CONFIG_VIDEO_IMAGEON) += video/imageon/ ++obj-$(CONFIG_XILINX_APF) += apf/ +diff --git a/drivers/staging/apf/Kconfig b/drivers/staging/apf/Kconfig +new file mode 100644 +index 0000000..1c07925 +--- /dev/null ++++ b/drivers/staging/apf/Kconfig +@@ -0,0 +1,17 @@ ++# ++# APF driver configuration ++# ++ ++menuconfig XILINX_APF ++ tristate "Xilinx APF Accelerator driver" ++ depends on ARCH_ZYNQ ++ default n ++ help ++ Select if you want to include APF accelerator driver ++ ++config XILINX_DMA_APF ++ bool "Xilinx APF DMA engines support" ++ depends on XILINX_APF ++ select DMA_ENGINE ++ help ++ Enable support for the Xilinx APF DMA controllers. +diff --git a/drivers/staging/apf/Makefile b/drivers/staging/apf/Makefile +new file mode 100644 +index 0000000..bf281a2 +--- /dev/null ++++ b/drivers/staging/apf/Makefile +@@ -0,0 +1,9 @@ ++# gpio support: dedicated expander chips, etc ++ ++ccflags-$(CONFIG_DEBUG_XILINX_APF) += -DDEBUG ++ccflags-$(CONFIG_XILINX_APF) += -Idrivers/dma ++ ++obj-$(CONFIG_XILINX_APF) += xlnk.o ++obj-$(CONFIG_XILINX_APF) += xlnk-eng.o ++obj-$(CONFIG_XILINX_DMA_APF) += xilinx-dma-apf.o ++ +diff --git a/drivers/staging/apf/xilinx-dma-apf.c b/drivers/staging/apf/xilinx-dma-apf.c +new file mode 100644 +index 0000000..6cec4c8 +--- /dev/null ++++ b/drivers/staging/apf/xilinx-dma-apf.c +@@ -0,0 +1,1120 @@ ++/* ++ * Xilinx AXI DMA Engine support ++ * ++ * Copyright (C) 2010 Xilinx, Inc. All rights reserved. ++ * ++ * Description: ++ * This driver supports Xilinx AXI DMA engine: ++ * . Axi DMA engine, it does transfers between memory and device. It can be ++ * configured to have one channel or two channels. If configured as two ++ * channels, one is for transmit to device and another is for receive from ++ * device. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "xilinx-dma-apf.h" ++ ++#include "xlnk-event-tracer-type.h" ++#include "xlnk.h" ++ ++static DEFINE_MUTEX(dma_list_mutex); ++static LIST_HEAD(dma_device_list); ++/* IO accessors */ ++#define DMA_OUT(addr, val) (iowrite32(val, addr)) ++#define DMA_IN(addr) (ioread32(addr)) ++ ++static int unpin_user_pages(struct scatterlist *sglist, unsigned int cnt); ++/* Driver functions */ ++static void xdma_clean_bd(struct xdma_desc_hw *bd) ++{ ++ bd->src_addr = 0x0; ++ bd->control = 0x0; ++ bd->status = 0x0; ++ bd->app[0] = 0x0; ++ bd->app[1] = 0x0; ++ bd->app[2] = 0x0; ++ bd->app[3] = 0x0; ++ bd->app[4] = 0x0; ++ bd->dmahead = 0x0; ++ bd->sw_flag = 0x0; ++} ++ ++static int dma_is_running(struct xdma_chan *chan) ++{ ++ return !(DMA_IN(&chan->regs->sr) & XDMA_SR_HALTED_MASK) && ++ (DMA_IN(&chan->regs->cr) & XDMA_CR_RUNSTOP_MASK); ++} ++ ++static int dma_is_idle(struct xdma_chan *chan) ++{ ++ return DMA_IN(&chan->regs->sr) & XDMA_SR_IDLE_MASK; ++} ++ ++static void dma_halt(struct xdma_chan *chan) ++{ ++ DMA_OUT(&chan->regs->cr, ++ (DMA_IN(&chan->regs->cr) & ~XDMA_CR_RUNSTOP_MASK)); ++} ++ ++static void dma_start(struct xdma_chan *chan) ++{ ++ DMA_OUT(&chan->regs->cr, ++ (DMA_IN(&chan->regs->cr) | XDMA_CR_RUNSTOP_MASK)); ++} ++ ++static int dma_init(struct xdma_chan *chan) ++{ ++ int loop = XDMA_RESET_LOOP; ++ ++ DMA_OUT(&chan->regs->cr, ++ (DMA_IN(&chan->regs->cr) | XDMA_CR_RESET_MASK)); ++ ++ /* Wait for the hardware to finish reset ++ */ ++ while (loop) { ++ if (!(DMA_IN(&chan->regs->cr) & XDMA_CR_RESET_MASK)) ++ break; ++ ++ loop -= 1; ++ } ++ ++ if (!loop) ++ return 1; ++ ++ return 0; ++} ++ ++static int xdma_alloc_chan_descriptors(struct xdma_chan *chan) ++{ ++ int i; ++ u8 *ptr; ++ ++ /* ++ * We need the descriptor to be aligned to 64bytes ++ * for meeting Xilinx DMA specification requirement. ++ */ ++ ptr = (u8 *)dma_alloc_coherent(chan->dev, ++ (sizeof(struct xdma_desc_hw) * XDMA_MAX_BD_CNT), ++ &chan->bd_phys_addr, ++ GFP_KERNEL); ++ ++ if (!ptr) { ++ dev_err(chan->dev, ++ "unable to allocate channel %d descriptor pool\n", ++ chan->id); ++ return -ENOMEM; ++ } ++ ++ memset(ptr, 0, (sizeof(struct xdma_desc_hw) * XDMA_MAX_BD_CNT)); ++ chan->bd_cur = 0; ++ chan->bd_tail = 0; ++ chan->bd_used = 0; ++ chan->bd_chain_size = sizeof(struct xdma_desc_hw) * XDMA_MAX_BD_CNT; ++ ++ /* ++ * Pre allocate all the channels. ++ */ ++ for (i = 0; i < XDMA_MAX_BD_CNT; i++) { ++ chan->bds[i] = (struct xdma_desc_hw *) ++ (ptr + (sizeof(struct xdma_desc_hw) * i)); ++ chan->bds[i]->next_desc = chan->bd_phys_addr + ++ (sizeof(struct xdma_desc_hw) * ++ ((i + 1) % XDMA_MAX_BD_CNT)); ++ } ++ ++ /* there is at least one descriptor free to be allocated */ ++ return 0; ++} ++ ++static void xdma_free_chan_resources(struct xdma_chan *chan) ++{ ++ dev_dbg(chan->dev, "Free all channel resources.\n"); ++ dma_free_coherent(chan->dev, (sizeof(struct xdma_desc_hw) * ++ XDMA_MAX_BD_CNT), chan->bds[0], chan->bd_phys_addr); ++} ++ ++static void xilinx_chan_desc_reinit(struct xdma_chan *chan) ++{ ++ struct xdma_desc_hw *desc; ++ unsigned int start, end; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&chan->lock, flags); ++ start = 0; ++ end = XDMA_MAX_BD_CNT; ++ ++ while (start < end) { ++ desc = chan->bds[start]; ++ xdma_clean_bd(desc); ++ start++; ++ } ++ /* Re-initialize bd_cur and bd_tail values */ ++ chan->bd_cur = 0; ++ chan->bd_tail = 0; ++ chan->bd_used = 0; ++ spin_unlock_irqrestore(&chan->lock, flags); ++} ++ ++static void xilinx_chan_desc_cleanup(struct xdma_chan *chan) ++{ ++ struct xdma_head *dmahead; ++ struct xdma_desc_hw *desc; ++ struct completion *cmp; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&chan->lock, flags); ++#define XDMA_BD_STS_RXEOF_MASK 0x04000000 ++ desc = chan->bds[chan->bd_cur]; ++ while ((desc->status & XDMA_BD_STS_ALL_MASK)) { ++ if ((desc->status & XDMA_BD_STS_RXEOF_MASK) && ++ !(desc->dmahead)) { ++ pr_info("ERROR: premature EOF on DMA\n"); ++ dma_init(chan); /* reset the dma HW */ ++ while (!(desc->dmahead)) { ++ xdma_clean_bd(desc); ++ chan->bd_used--; ++ chan->bd_cur++; ++ if (chan->bd_cur >= XDMA_MAX_BD_CNT) ++ chan->bd_cur = 0; ++ desc = chan->bds[chan->bd_cur]; ++ } ++ } ++ if (desc->dmahead) { ++ ++ if ((desc->sw_flag & XDMA_BD_SF_POLL_MODE_MASK)) ++ if (!(desc->sw_flag & XDMA_BD_SF_SW_DONE_MASK)) ++ break; ++ ++ dmahead = (struct xdma_head *)desc->dmahead; ++ cmp = (struct completion *)&dmahead->cmp; ++ if (dmahead->nappwords_o) ++ memcpy(dmahead->appwords_o, desc->app, ++ dmahead->nappwords_o * sizeof(u32)); ++ ++ if (chan->poll_mode) ++ cmp->done = 1; ++ else ++ complete(cmp); ++ } ++ xdma_clean_bd(desc); ++ chan->bd_used--; ++ chan->bd_cur++; ++ if (chan->bd_cur >= XDMA_MAX_BD_CNT) ++ chan->bd_cur = 0; ++ desc = chan->bds[chan->bd_cur]; ++ } ++ spin_unlock_irqrestore(&chan->lock, flags); ++} ++ ++static void xdma_err_tasklet(unsigned long data) ++{ ++ struct xdma_chan *chan = (struct xdma_chan *)data; ++ ++ if (chan->err) { ++ /* If reset failed, need to hard reset ++ * Channel is no longer functional ++ */ ++ if (!dma_init(chan)) ++ chan->err = 0; ++ else ++ dev_err(chan->dev, ++ "DMA channel reset failed, please reset system\n"); ++ } ++ ++ rmb(); ++ xilinx_chan_desc_cleanup(chan); ++ ++ xilinx_chan_desc_reinit(chan); ++} ++ ++static void xdma_tasklet(unsigned long data) ++{ ++ struct xdma_chan *chan = (struct xdma_chan *)data; ++ ++ rmb(); ++ xilinx_chan_desc_cleanup(chan); ++} ++ ++static void dump_cur_bd(struct xdma_chan *chan) ++{ ++ u32 index; ++ ++ index = (((u32)DMA_IN(&chan->regs->cdr)) - chan->bd_phys_addr) / ++ sizeof(struct xdma_desc_hw); ++ ++ dev_err(chan->dev, "cur bd @ %08x\n", (u32)DMA_IN(&chan->regs->cdr)); ++ dev_err(chan->dev, " buf = 0x%08x\n", chan->bds[index]->src_addr); ++ dev_err(chan->dev, " ctrl = 0x%08x\n", chan->bds[index]->control); ++ dev_err(chan->dev, " sts = 0x%08x\n", chan->bds[index]->status); ++ dev_err(chan->dev, " next = 0x%08x\n", chan->bds[index]->next_desc); ++} ++ ++static irqreturn_t xdma_rx_intr_handler(int irq, void *data) ++{ ++ struct xdma_chan *chan = data; ++ u32 stat; ++ ++ stat = DMA_IN(&chan->regs->sr); ++ ++ if (!(stat & XDMA_XR_IRQ_ALL_MASK)) { ++ return IRQ_NONE; ++ } ++ ++ /* Ack the interrupts */ ++ DMA_OUT(&chan->regs->sr, (stat & XDMA_XR_IRQ_ALL_MASK)); ++ ++ if (stat & XDMA_XR_IRQ_ERROR_MASK) { ++ dev_err(chan->dev, "Channel %s has errors %x, cdr %x tdr %x\n", ++ chan->name, (unsigned int)stat, ++ (unsigned int)DMA_IN(&chan->regs->cdr), ++ (unsigned int)DMA_IN(&chan->regs->tdr)); ++ ++ dump_cur_bd(chan); ++ ++ chan->err = 1; ++ tasklet_schedule(&chan->dma_err_tasklet); ++ } ++ ++ if (!(chan->poll_mode) && ((stat & XDMA_XR_IRQ_DELAY_MASK) || ++ (stat & XDMA_XR_IRQ_IOC_MASK))) ++ tasklet_schedule(&chan->tasklet); ++ ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t xdma_tx_intr_handler(int irq, void *data) ++{ ++ struct xdma_chan *chan = data; ++ u32 stat; ++ ++ stat = DMA_IN(&chan->regs->sr); ++ ++ if (!(stat & XDMA_XR_IRQ_ALL_MASK)) { ++ return IRQ_NONE; ++ } ++ ++ /* Ack the interrupts */ ++ DMA_OUT(&chan->regs->sr, (stat & XDMA_XR_IRQ_ALL_MASK)); ++ ++ if (stat & XDMA_XR_IRQ_ERROR_MASK) { ++ dev_err(chan->dev, "Channel %s has errors %x, cdr %x tdr %x\n", ++ chan->name, (unsigned int)stat, ++ (unsigned int)DMA_IN(&chan->regs->cdr), ++ (unsigned int)DMA_IN(&chan->regs->tdr)); ++ ++ dump_cur_bd(chan); ++ ++ chan->err = 1; ++ tasklet_schedule(&chan->dma_err_tasklet); ++ } ++ ++ if (!(chan->poll_mode) && ((stat & XDMA_XR_IRQ_DELAY_MASK) || ++ (stat & XDMA_XR_IRQ_IOC_MASK))) ++ tasklet_schedule(&chan->tasklet); ++ ++ return IRQ_HANDLED; ++} ++ ++static void xdma_chan_remove(struct xdma_chan *chan) ++{ ++ dma_halt(chan); ++ xdma_free_chan_resources(chan); ++ free_irq(chan->irq, chan); ++ kfree(chan); ++} ++ ++static void xdma_start_transfer(struct xdma_chan *chan, ++ int start_index, ++ int end_index) ++{ ++ dma_addr_t cur_phys; ++ dma_addr_t tail_phys; ++ u32 regval; ++ ++ if (chan->err) ++ return; ++ ++ cur_phys = chan->bd_phys_addr + (start_index * ++ sizeof(struct xdma_desc_hw)); ++ tail_phys = chan->bd_phys_addr + (end_index * ++ sizeof(struct xdma_desc_hw)); ++ /* If hardware is busy, move the tail & return */ ++ if (dma_is_running(chan) || dma_is_idle(chan)) { ++ /* Update tail ptr register and start the transfer */ ++ DMA_OUT(&chan->regs->tdr, tail_phys); ++ xlnk_record_event(XLNK_ET_KERNEL_AFTER_DMA_KICKOFF); ++ return; ++ } ++ ++ DMA_OUT(&chan->regs->cdr, cur_phys); ++ ++ dma_start(chan); ++ ++ /* Enable interrupts */ ++ regval = DMA_IN(&chan->regs->cr); ++ regval |= (chan->poll_mode ? XDMA_XR_IRQ_ERROR_MASK ++ : XDMA_XR_IRQ_ALL_MASK); ++ DMA_OUT(&chan->regs->cr, regval); ++ ++ /* Update tail ptr register and start the transfer */ ++ DMA_OUT(&chan->regs->tdr, tail_phys); ++ xlnk_record_event(XLNK_ET_KERNEL_AFTER_DMA_KICKOFF); ++} ++ ++static int xdma_setup_hw_desc(struct xdma_chan *chan, ++ struct xdma_head *dmahead, ++ struct scatterlist *sgl, ++ unsigned int sg_len, ++ enum dma_data_direction direction, ++ unsigned int nappwords_i, ++ u32 *appwords_i) ++{ ++ struct xdma_desc_hw *bd = NULL; ++ size_t copy; ++ struct scatterlist *sg; ++ size_t sg_used; ++ dma_addr_t dma_src; ++ int i, start_index = -1, end_index1 = 0, end_index2 = -1; ++ int status; ++ unsigned long flags; ++ unsigned int bd_used_saved; ++ ++ if (!chan) ++ return -ENODEV; ++ ++ /* if we almost run out of bd, try to recycle some */ ++ if ((chan->poll_mode) && (chan->bd_used >= XDMA_BD_CLEANUP_THRESHOLD)) ++ xilinx_chan_desc_cleanup(chan); ++ ++ spin_lock_irqsave(&chan->lock, flags); ++ ++ bd_used_saved = chan->bd_used; ++ /* ++ * Build transactions using information in the scatter gather list ++ */ ++ for_each_sg(sgl, sg, sg_len, i) { ++ sg_used = 0; ++ ++ /* Loop until the entire scatterlist entry is used */ ++ while (sg_used < sg_dma_len(sg)) { ++ /* Allocate the link descriptor from DMA pool */ ++ bd = chan->bds[chan->bd_tail]; ++ if ((bd->control) & (XDMA_BD_STS_ACTUAL_LEN_MASK)) { ++ end_index2 = chan->bd_tail; ++ status = -ENOMEM; ++ /* If first was not set, then we failed to ++ * allocate the very first descriptor, ++ * and we're done */ ++ if (start_index == -1) ++ goto out_unlock; ++ else ++ goto out_clean; ++ } ++ /* ++ * Calculate the maximum number of bytes to transfer, ++ * making sure it is less than the DMA controller limit ++ */ ++ copy = min((size_t)(sg_dma_len(sg) - sg_used), ++ (size_t)chan->max_len); ++ /* ++ * Only the src address for DMA ++ */ ++ dma_src = sg_dma_address(sg) + sg_used; ++ bd->src_addr = dma_src; ++ ++ /* Fill in the descriptor */ ++ bd->control = copy; ++ ++ /* ++ * If this is not the first descriptor, chain the ++ * current descriptor after the previous descriptor ++ * ++ * For the first DMA_TO_DEVICE transfer, set SOP ++ */ ++ if (start_index == -1) { ++ start_index = chan->bd_tail; ++ ++ if (nappwords_i) ++ memcpy(bd->app, appwords_i, ++ nappwords_i * sizeof(u32)); ++ ++ if (direction == DMA_TO_DEVICE) ++ bd->control |= XDMA_BD_SOP; ++ } ++ ++ sg_used += copy; ++ end_index2 = chan->bd_tail; ++ chan->bd_tail++; ++ chan->bd_used++; ++ if (chan->bd_tail >= XDMA_MAX_BD_CNT) { ++ end_index1 = XDMA_MAX_BD_CNT; ++ chan->bd_tail = 0; ++ } ++ } ++ } ++ ++ if (start_index == -1) { ++ status = -EINVAL; ++ goto out_unlock; ++ } ++ ++ bd->dmahead = (u32) dmahead; ++ bd->sw_flag = chan->poll_mode ? XDMA_BD_SF_POLL_MODE_MASK : 0; ++ dmahead->last_bd_index = end_index2; ++ ++ if (direction == DMA_TO_DEVICE) ++ bd->control |= XDMA_BD_EOP; ++ ++ wmb(); ++ ++ xdma_start_transfer(chan, start_index, end_index2); ++ ++ spin_unlock_irqrestore(&chan->lock, flags); ++ ++ return 0; ++ ++out_clean: ++ if (!end_index1) { ++ for (i = start_index; i < end_index2; i++) ++ xdma_clean_bd(chan->bds[i]); ++ } else { ++ /* clean till the end of bd list first, and then 2nd end */ ++ for (i = start_index; i < end_index1; i++) ++ xdma_clean_bd(chan->bds[i]); ++ ++ end_index1 = 0; ++ for (i = end_index1; i < end_index2; i++) ++ xdma_clean_bd(chan->bds[i]); ++ } ++ /* Move the bd_tail back */ ++ chan->bd_tail = start_index; ++ chan->bd_used = bd_used_saved; ++ ++out_unlock: ++ spin_unlock_irqrestore(&chan->lock, flags); ++ ++ return status; ++} ++ ++#define XDMA_SGL_MAX_LEN XDMA_MAX_BD_CNT ++static struct scatterlist sglist_array[XDMA_SGL_MAX_LEN]; ++ ++/* ++ * create minimal length scatter gather list for physically contiguous buffer ++ * that starts at phy_buf and has length phy_buf_len bytes ++ */ ++static unsigned int phy_buf_to_sgl(void *phy_buf, unsigned int phy_buf_len, ++ struct scatterlist **sgl) ++{ ++ unsigned int sgl_cnt = 0; ++ struct scatterlist *sgl_head; ++ unsigned int dma_len; ++ ++ if (!phy_buf || !phy_buf_len) { ++ pr_err("phy_buf is NULL or phy_buf_len = 0\n"); ++ return sgl_cnt; ++ } ++ ++ *sgl = sglist_array; ++ sgl_head = *sgl; ++ ++ while (phy_buf_len > 0) { ++ ++ sgl_cnt++; ++ if (sgl_cnt > XDMA_SGL_MAX_LEN) ++ return 0; ++ ++ dma_len = (phy_buf_len > XDMA_MAX_TRANS_LEN) ? ++ XDMA_MAX_TRANS_LEN : phy_buf_len; ++ ++ sg_dma_address(sgl_head) = (dma_addr_t)phy_buf; ++ sg_dma_len(sgl_head) = dma_len; ++ sgl_head = sg_next(sgl_head); ++ ++ phy_buf += dma_len; ++ phy_buf_len -= dma_len; ++ ++ } ++ return sgl_cnt; ++} ++ ++/* merge sg list, sgl, with length sgl_len, to sgl_merged, to save dma bds */ ++static unsigned int sgl_merge(struct scatterlist *sgl, unsigned int sgl_len, ++ struct scatterlist **sgl_merged) ++{ ++ struct scatterlist *sghead, *sgend, *sgnext, *sg_merged_head; ++ unsigned int sg_visited_cnt = 0, sg_merged_num = 0; ++ unsigned int dma_len = 0; ++ ++ *sgl_merged = sglist_array; ++ sg_merged_head = *sgl_merged; ++ sghead = sgl; ++ ++ while (sghead && (sg_visited_cnt < sgl_len)) { ++ ++ dma_len = sg_dma_len(sghead); ++ sgend = sghead; ++ sg_visited_cnt++; ++ sgnext = sg_next(sgend); ++ ++ while (sgnext && (sg_visited_cnt < sgl_len)) { ++ ++ if ((sg_dma_address(sgend) + sg_dma_len(sgend)) != ++ sg_dma_address(sgnext)) ++ break; ++ ++ if (dma_len + sg_dma_len(sgnext) >= XDMA_MAX_TRANS_LEN) ++ break; ++ ++ sgend = sgnext; ++ dma_len += sg_dma_len(sgend); ++ sg_visited_cnt++; ++ sgnext = sg_next(sgnext); ++ ++ } ++ ++ sg_merged_num++; ++ if (sg_merged_num > XDMA_SGL_MAX_LEN) ++ return 0; ++ ++ memcpy(sg_merged_head, sghead, sizeof(struct scatterlist)); ++ ++ sg_dma_len(sg_merged_head) = dma_len; ++ ++ sg_merged_head = sg_next(sg_merged_head); ++ sghead = sg_next(sgend); ++ } ++ ++ return sg_merged_num; ++} ++ ++static struct page *mapped_pages[XDMA_MAX_BD_CNT]; ++static int pin_user_pages(unsigned long uaddr, ++ unsigned int ulen, ++ int write, ++ struct scatterlist **scatterpp, ++ unsigned int *cntp, ++ unsigned int user_flags) ++{ ++ int status; ++ struct mm_struct *mm = current->mm; ++ struct task_struct *curr_task = current; ++ unsigned int first_page; ++ unsigned int last_page; ++ unsigned int num_pages; ++ struct scatterlist *sglist; ++ ++ unsigned int pgidx; ++ unsigned int pglen; ++ unsigned int pgoff; ++ unsigned int sublen; ++ ++ first_page = uaddr / PAGE_SIZE; ++ last_page = (uaddr + ulen - 1) / PAGE_SIZE; ++ num_pages = last_page - first_page + 1; ++ xlnk_record_event(XLNK_ET_KERNEL_BEFORE_GET_USER_PAGES); ++ down_read(&mm->mmap_sem); ++ status = get_user_pages(curr_task, mm, uaddr, num_pages, write, 1, ++ mapped_pages, NULL); ++ up_read(&mm->mmap_sem); ++ xlnk_record_event(XLNK_ET_KERNEL_AFTER_GET_USER_PAGES); ++ ++ if (status == num_pages) { ++ sglist = kcalloc(num_pages, ++ sizeof(struct scatterlist), ++ GFP_KERNEL); ++ if (sglist == NULL) { ++ pr_err("%s: kcalloc failed to create sg list\n", ++ __func__); ++ return -ENOMEM; ++ } ++ sg_init_table(sglist, num_pages); ++ sublen = 0; ++ for (pgidx = 0; pgidx < status; pgidx++) { ++ if (pgidx == 0 && num_pages != 1) { ++ pgoff = uaddr & (~PAGE_MASK); ++ pglen = PAGE_SIZE - pgoff; ++ } else if (pgidx == 0 && num_pages == 1) { ++ pgoff = uaddr & (~PAGE_MASK); ++ pglen = ulen; ++ } else if (pgidx == num_pages - 1) { ++ pgoff = 0; ++ pglen = ulen - sublen; ++ } else { ++ pgoff = 0; ++ pglen = PAGE_SIZE; ++ } ++ ++ sublen += pglen; ++ ++ sg_set_page(&sglist[pgidx], ++ mapped_pages[pgidx], ++ pglen, pgoff); ++ ++ sg_dma_len(&sglist[pgidx]) = pglen; ++ } ++ ++ *scatterpp = sglist; ++ *cntp = num_pages; ++ ++ return 0; ++ } else { ++ ++ for (pgidx = 0; pgidx < status; pgidx++) { ++ page_cache_release(mapped_pages[pgidx]); ++ } ++ return -ENOMEM; ++ } ++} ++ ++static int unpin_user_pages(struct scatterlist *sglist, unsigned int cnt) ++{ ++ struct page *pg; ++ unsigned int i; ++ ++ if (!sglist) ++ return 0; ++ ++ for (i = 0; i < cnt; i++) { ++ pg = sg_page(sglist + i); ++ if (pg) { ++ page_cache_release(pg); ++ } ++ } ++ ++ kfree(sglist); ++ return 0; ++} ++ ++struct xdma_chan *xdma_request_channel(char *name) ++{ ++ int i; ++ struct xdma_device *device, *tmp; ++ ++ mutex_lock(&dma_list_mutex); ++ list_for_each_entry_safe(device, tmp, &dma_device_list, node) { ++ for (i = 0; i < device->channel_count; i++) { ++ if (device->chan[i]->client_count) ++ continue; ++ if (!strcmp(device->chan[i]->name, name)) { ++ device->chan[i]->client_count++; ++ mutex_unlock(&dma_list_mutex); ++ return device->chan[i]; ++ } ++ } ++ } ++ mutex_unlock(&dma_list_mutex); ++ return NULL; ++} ++EXPORT_SYMBOL(xdma_request_channel); ++ ++void xdma_release_channel(struct xdma_chan *chan) ++{ ++ mutex_lock(&dma_list_mutex); ++ if (!chan->client_count) { ++ mutex_unlock(&dma_list_mutex); ++ return; ++ } ++ chan->client_count--; ++ dma_halt(chan); ++ xilinx_chan_desc_reinit(chan); ++ mutex_unlock(&dma_list_mutex); ++} ++EXPORT_SYMBOL(xdma_release_channel); ++ ++void xdma_release_all_channels(void) ++{ ++ int i; ++ struct xdma_device *device, *tmp; ++ ++ list_for_each_entry_safe(device, tmp, &dma_device_list, node) { ++ for (i = 0; i < device->channel_count; i++) { ++ if (device->chan[i]->client_count) { ++ dma_halt(device->chan[i]); ++ xilinx_chan_desc_reinit(device->chan[i]); ++ device->chan[i]->client_count = 0; ++ pr_info("%s: chan %s freed\n", ++ __func__, ++ device->chan[i]->name); ++ } ++ } ++ } ++} ++EXPORT_SYMBOL(xdma_release_all_channels); ++ ++int xdma_submit(struct xdma_chan *chan, ++ void *userbuf, ++ unsigned int size, ++ unsigned int nappwords_i, ++ u32 *appwords_i, ++ unsigned int nappwords_o, ++ unsigned int user_flags, ++ struct xdma_head **dmaheadpp) ++{ ++ struct xdma_head *dmahead; ++ struct scatterlist *sglist, *sglist_dma; ++ unsigned int sgcnt, sgcnt_dma; ++ enum dma_data_direction dmadir; ++ int status; ++ void *kaddr; ++ DEFINE_DMA_ATTRS(attrs); ++ ++ ++ xlnk_record_event(XLNK_ET_KERNEL_ENTER_DMA_SUBMIT); ++ dmahead = kmalloc(sizeof(struct xdma_head), GFP_KERNEL); ++ if (!dmahead) ++ return -ENOMEM; ++ ++ memset(dmahead, 0, sizeof(struct xdma_head)); ++ ++ dmahead->chan = chan; ++ dmahead->userbuf = userbuf; ++ dmahead->size = size; ++ dmahead->dmadir = chan->direction; ++ dmahead->userflag = user_flags; ++ dmadir = chan->direction; ++ if (user_flags & CF_FLAG_PHYSICALLY_CONTIGUOUS) { ++ /* ++ * convert physically contiguous buffer into ++ * minimal length sg list ++ */ ++ sgcnt = phy_buf_to_sgl(userbuf, size, &sglist); ++ if (!sgcnt) ++ return -ENOMEM; ++ ++ sglist_dma = sglist; ++ sgcnt_dma = sgcnt; ++ if (user_flags & CF_FLAG_CACHE_FLUSH_INVALIDATE) { ++ kaddr = phys_to_virt((phys_addr_t)userbuf); ++ dmac_map_area(kaddr, size, DMA_TO_DEVICE); ++ outer_clean_range((phys_addr_t)userbuf, ++ (u32)userbuf + size); ++ } ++ } else { ++ /* pin user pages is monitored separately */ ++ xlnk_record_event(XLNK_ET_KERNEL_BEFORE_PIN_USER_PAGE); ++ status = pin_user_pages((unsigned long)userbuf, size, ++ dmadir != DMA_TO_DEVICE, ++ &sglist, &sgcnt, user_flags); ++ if (status < 0) { ++ pr_err("pin_user_pages failed\n"); ++ return status; ++ } ++ xlnk_record_event(XLNK_ET_KERNEL_AFTER_PIN_USER_PAGE); ++ xlnk_record_event(XLNK_ET_KERNEL_BEFORE_DMA_MAP_SG); ++ if (!(user_flags & CF_FLAG_CACHE_FLUSH_INVALIDATE)) ++ dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs); ++ ++ status = get_dma_ops(chan->dev)->map_sg(chan->dev, sglist, ++ sgcnt, dmadir, &attrs); ++ if (!status) { ++ pr_err("dma_map_sg failed\n"); ++ unpin_user_pages(sglist, sgcnt); ++ return -ENOMEM; ++ } ++ xlnk_record_event(XLNK_ET_KERNEL_AFTER_DMA_MAP_SG); ++ ++ /* merge sg list to save dma bds */ ++ sgcnt_dma = sgl_merge(sglist, sgcnt, &sglist_dma); ++ if (!sgcnt_dma) { ++ get_dma_ops(chan->dev)->unmap_sg(chan->dev, sglist, ++ sgcnt, dmadir, &attrs); ++ unpin_user_pages(sglist, sgcnt); ++ return -ENOMEM; ++ } ++ } ++ dmahead->sglist = sglist; ++ dmahead->sgcnt = sgcnt; ++ ++ /* skipping config */ ++ init_completion(&dmahead->cmp); ++ ++ if (nappwords_i > XDMA_MAX_APPWORDS) ++ nappwords_i = XDMA_MAX_APPWORDS; ++ ++ if (nappwords_o > XDMA_MAX_APPWORDS) ++ nappwords_o = XDMA_MAX_APPWORDS; ++ ++ dmahead->nappwords_o = nappwords_o; ++ ++ xlnk_record_event(XLNK_ET_KERNEL_BEFORE_DMA_SETUP_BD); ++ status = xdma_setup_hw_desc(chan, dmahead, sglist_dma, sgcnt_dma, ++ dmadir, nappwords_i, appwords_i); ++ xlnk_record_event(XLNK_ET_KERNEL_AFTER_DMA_SETUP_BD); ++ if (status) { ++ pr_err("setup hw desc failed\n"); ++ if (!(user_flags & CF_FLAG_PHYSICALLY_CONTIGUOUS)) { ++ get_dma_ops(chan->dev)->unmap_sg(chan->dev, sglist, ++ sgcnt, dmadir, &attrs); ++ unpin_user_pages(sglist, sgcnt); ++ } ++ ++ return -ENOMEM; ++ } ++ ++ *dmaheadpp = dmahead; ++ ++ xlnk_record_event(XLNK_ET_KERNEL_LEAVE_DMA_SUBMIT); ++ return 0; ++} ++EXPORT_SYMBOL(xdma_submit); ++ ++int xdma_wait(struct xdma_head *dmahead, unsigned int user_flags) ++{ ++ struct xdma_chan *chan = dmahead->chan; ++ void *kaddr, *paddr; ++ int size; ++ DEFINE_DMA_ATTRS(attrs); ++ xlnk_record_event(XLNK_ET_KERNEL_ENTER_DMA_WAIT); ++ ++ if (chan->poll_mode) { ++ xilinx_chan_desc_cleanup(chan); ++ } else ++ wait_for_completion(&dmahead->cmp); ++ ++ if (!(user_flags & CF_FLAG_PHYSICALLY_CONTIGUOUS)) { ++ xlnk_record_event(XLNK_ET_KERNEL_BEFORE_DMA_UNMAP_SG); ++ if (!(user_flags & CF_FLAG_CACHE_FLUSH_INVALIDATE)) ++ dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs); ++ ++ get_dma_ops(chan->dev)->unmap_sg(chan->dev, dmahead->sglist, ++ dmahead->sgcnt, ++ dmahead->dmadir, &attrs); ++ xlnk_record_event(XLNK_ET_KERNEL_AFTER_DMA_UNMAP_SG); ++ ++ unpin_user_pages(dmahead->sglist, dmahead->sgcnt); ++ } else { ++ if (user_flags & CF_FLAG_CACHE_FLUSH_INVALIDATE) { ++ paddr = dmahead->userbuf; ++ size = dmahead->size; ++ kaddr = phys_to_virt((phys_addr_t)paddr); ++ outer_inv_range((phys_addr_t)paddr, (u32)paddr + size); ++ dmac_unmap_area(kaddr, size, DMA_FROM_DEVICE); ++ } ++ } ++ xlnk_record_event(XLNK_ET_KERNEL_LEAVE_DMA_WAIT); ++ return 0; ++} ++EXPORT_SYMBOL(xdma_wait); ++ ++int xdma_getconfig(struct xdma_chan *chan, ++ unsigned char *irq_thresh, ++ unsigned char *irq_delay) ++{ ++ *irq_thresh = (DMA_IN(&chan->regs->cr) >> XDMA_COALESCE_SHIFT) & 0xff; ++ *irq_delay = (DMA_IN(&chan->regs->cr) >> XDMA_DELAY_SHIFT) & 0xff; ++ return 0; ++} ++EXPORT_SYMBOL(xdma_getconfig); ++ ++int xdma_setconfig(struct xdma_chan *chan, ++ unsigned char irq_thresh, ++ unsigned char irq_delay) ++{ ++ unsigned long val; ++ ++ if (dma_is_running(chan)) ++ return -EBUSY; ++ ++ val = DMA_IN(&chan->regs->cr); ++ val &= ~((0xff << XDMA_COALESCE_SHIFT) | ++ (0xff << XDMA_DELAY_SHIFT)); ++ val |= ((irq_thresh << XDMA_COALESCE_SHIFT) | ++ (irq_delay << XDMA_DELAY_SHIFT)); ++ ++ DMA_OUT(&chan->regs->cr, val); ++ return 0; ++} ++EXPORT_SYMBOL(xdma_setconfig); ++ ++/* Brute-force probing for xilinx DMA ++ */ ++static int xdma_probe(struct platform_device *pdev) ++{ ++ struct xdma_device *xdev; ++ struct resource *res; ++ int err, i, j; ++ struct xdma_chan *chan; ++ struct dma_device_config *dma_config; ++ int dma_chan_dir; ++ int dma_chan_reg_offset; ++ ++ pr_info("%s: probe dma %x, nres %d, id %d\n", __func__, ++ (unsigned int)&pdev->dev, ++ pdev->num_resources, pdev->id); ++ ++ xdev = devm_kzalloc(&pdev->dev, sizeof(struct xdma_device), GFP_KERNEL); ++ if (!xdev) { ++ dev_err(&pdev->dev, "Not enough memory for device\n"); ++ return -ENOMEM; ++ } ++ xdev->dev = &(pdev->dev); ++ ++ dma_config = (struct dma_device_config *)xdev->dev->platform_data; ++ if (dma_config->channel_count < 1 || dma_config->channel_count > 2) ++ return -EFAULT; ++ ++ /* Get the memory resource */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(&pdev->dev, "invalid resource\n"); ++ return -EINVAL; ++ } ++ xdev->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); ++ if (!xdev->regs) { ++ dev_err(&pdev->dev, "unable to iomap registers\n"); ++ return -EFAULT; ++ } ++ ++ dev_info(&pdev->dev, "AXIDMA device %d physical base address=%pa\n", ++ pdev->id, &res->start); ++ dev_info(&pdev->dev, "AXIDMA device %d remapped to %pa\n", ++ pdev->id, &xdev->regs); ++ ++ /* Allocate the channels */ ++ ++ dev_info(&pdev->dev, "has %d channel(s)\n", dma_config->channel_count); ++ for (i = 0; i < dma_config->channel_count; i++) { ++ chan = devm_kzalloc(&pdev->dev, sizeof(*chan), GFP_KERNEL); ++ if (!chan) { ++ dev_err(&pdev->dev, "no free memory for DMA channel\n"); ++ return -ENOMEM; ++ } ++ ++ dma_chan_dir = strcmp(dma_config->channel_config[i].type, ++ "axi-dma-mm2s-channel") ? ++ DMA_FROM_DEVICE : DMA_TO_DEVICE; ++ dma_chan_reg_offset = dma_chan_dir == DMA_TO_DEVICE ? 0 : 0x30; ++ ++ /* Initialize channel parameters */ ++ chan->id = i; ++ chan->regs = xdev->regs + dma_chan_reg_offset; ++ /* chan->regs = xdev->regs; */ ++ chan->dev = xdev->dev; ++ chan->max_len = XDMA_MAX_TRANS_LEN; ++ chan->direction = dma_chan_dir; ++ sprintf(chan->name, "%schan%d", dev_name(&pdev->dev), chan->id); ++ pr_info(" chan%d name: %s\n", chan->id, chan->name); ++ pr_info(" chan%d direction: %s\n", chan->id, ++ dma_chan_dir == DMA_FROM_DEVICE ? ++ "FROM_DEVICE" : "TO_DEVICE"); ++ ++ spin_lock_init(&chan->lock); ++ tasklet_init(&chan->tasklet, xdma_tasklet, (unsigned long)chan); ++ tasklet_init(&chan->dma_err_tasklet, xdma_err_tasklet, ++ (unsigned long)chan); ++ ++ xdev->chan[chan->id] = chan; ++ ++ /* The IRQ resource */ ++ chan->irq = dma_config->channel_config[i].irq; ++ if (chan->irq <= 0) { ++ pr_err("get_resource for IRQ for dev %d failed\n", ++ pdev->id); ++ return -ENODEV; ++ } ++ ++ err = devm_request_irq(&pdev->dev, ++ chan->irq, ++ dma_chan_dir == DMA_TO_DEVICE ? ++ xdma_tx_intr_handler : xdma_rx_intr_handler, ++ IRQF_SHARED, ++ pdev->name, ++ chan); ++ if (err) { ++ dev_err(&pdev->dev, "unable to request IRQ\n"); ++ return err; ++ } ++ pr_info(" chan%d irq: %d\n", chan->id, chan->irq); ++ ++ chan->poll_mode = dma_config->channel_config[i].poll_mode; ++ pr_info(" chan%d poll mode: %s\n", chan->id, ++ chan->poll_mode ? "on" : "off"); ++ ++ /* Allocate channel BD's */ ++ err = xdma_alloc_chan_descriptors(xdev->chan[chan->id]); ++ if (err) { ++ dev_err(&pdev->dev, "unable to allocate BD's\n"); ++ return -ENOMEM; ++ } ++ pr_info(" chan%d bd ring @ 0x%08x (size: 0x%08x bytes)\n", ++ chan->id, chan->bd_phys_addr, ++ chan->bd_chain_size); ++ ++ err = dma_init(xdev->chan[chan->id]); ++ if (err) { ++ dev_err(&pdev->dev, "DMA init failed\n"); ++ /* FIXME Check this - unregister all chan resources */ ++ for (j = 0; j <= i; j++) ++ xdma_free_chan_resources(xdev->chan[j]); ++ return -EIO; ++ } ++ } ++ xdev->channel_count = dma_config->channel_count; ++ ++ /* Add the DMA device to the global list */ ++ mutex_lock(&dma_list_mutex); ++ list_add_tail(&xdev->node, &dma_device_list); ++ mutex_unlock(&dma_list_mutex); ++ ++ platform_set_drvdata(pdev, xdev); ++ ++ return 0; ++} ++ ++static int xdma_remove(struct platform_device *pdev) ++{ ++ int i; ++ struct xdma_device *xdev = platform_get_drvdata(pdev); ++ ++ /* Remove the DMA device from the global list */ ++ mutex_lock(&dma_list_mutex); ++ list_del(&xdev->node); ++ mutex_unlock(&dma_list_mutex); ++ ++ for (i = 0; i < XDMA_MAX_CHANS_PER_DEVICE; i++) { ++ if (xdev->chan[i]) ++ xdma_chan_remove(xdev->chan[i]); ++ } ++ ++ return 0; ++} ++ ++static struct platform_driver xdma_driver = { ++ .probe = xdma_probe, ++ .remove = xdma_remove, ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "xilinx-axidma", ++ }, ++}; ++ ++module_platform_driver(xdma_driver); ++ ++MODULE_DESCRIPTION("Xilinx DMA driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/staging/apf/xilinx-dma-apf.h b/drivers/staging/apf/xilinx-dma-apf.h +new file mode 100644 +index 0000000..39d3da6 +--- /dev/null ++++ b/drivers/staging/apf/xilinx-dma-apf.h +@@ -0,0 +1,210 @@ ++/* ++ * Xilinx AXI DMA Engine support ++ * ++ * Copyright (C) 2010 Xilinx, Inc. All rights reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ */ ++ ++#ifndef __XILINX_DMA_APF_H ++#define __XILINX_DMA_APF_H ++ ++/* ioctls */ ++#include ++ ++/* tasklet */ ++#include ++ ++/* dma stuff */ ++#include ++ ++#define XDMA_IOC_MAGIC 'X' ++#define XDMA_IOCRESET _IO(XDMA_IOC_MAGIC, 0) ++#define XDMA_IOCREQUEST _IOWR(XDMA_IOC_MAGIC, 1, unsigned long) ++#define XDMA_IOCRELEASE _IOWR(XDMA_IOC_MAGIC, 2, unsigned long) ++#define XDMA_IOCSUBMIT _IOWR(XDMA_IOC_MAGIC, 3, unsigned long) ++#define XDMA_IOCWAIT _IOWR(XDMA_IOC_MAGIC, 4, unsigned long) ++#define XDMA_IOCGETCONFIG _IOWR(XDMA_IOC_MAGIC, 5, unsigned long) ++#define XDMA_IOCSETCONFIG _IOWR(XDMA_IOC_MAGIC, 6, unsigned long) ++#define XDMA_IOC_MAXNR 6 ++ ++/* Specific hardware configuration-related constants ++ */ ++#define XDMA_RESET_LOOP 1000000 ++#define XDMA_HALT_LOOP 1000000 ++#define XDMA_NO_CHANGE 0xFFFF; ++ ++/* General register bits definitions ++ */ ++#define XDMA_CR_RESET_MASK 0x00000004 /* Reset DMA engine */ ++#define XDMA_CR_RUNSTOP_MASK 0x00000001 /* Start/stop DMA engine */ ++ ++#define XDMA_SR_HALTED_MASK 0x00000001 /* DMA channel halted */ ++#define XDMA_SR_IDLE_MASK 0x00000002 /* DMA channel idle */ ++ ++#define XDMA_SR_ERR_INTERNAL_MASK 0x00000010/* Datamover internal err */ ++#define XDMA_SR_ERR_SLAVE_MASK 0x00000020 /* Datamover slave err */ ++#define XDMA_SR_ERR_DECODE_MASK 0x00000040 /* Datamover decode err */ ++#define XDMA_SR_ERR_SG_INT_MASK 0x00000100 /* SG internal err */ ++#define XDMA_SR_ERR_SG_SLV_MASK 0x00000200 /* SG slave err */ ++#define XDMA_SR_ERR_SG_DEC_MASK 0x00000400 /* SG decode err */ ++#define XDMA_SR_ERR_ALL_MASK 0x00000770 /* All errors */ ++ ++#define XDMA_XR_IRQ_IOC_MASK 0x00001000 /* Completion interrupt */ ++#define XDMA_XR_IRQ_DELAY_MASK 0x00002000 /* Delay interrupt */ ++#define XDMA_XR_IRQ_ERROR_MASK 0x00004000 /* Error interrupt */ ++#define XDMA_XR_IRQ_ALL_MASK 0x00007000 /* All interrupts */ ++ ++#define XDMA_XR_DELAY_MASK 0xFF000000 /* Delay timeout counter */ ++#define XDMA_XR_COALESCE_MASK 0x00FF0000 /* Coalesce counter */ ++ ++#define XDMA_DELAY_SHIFT 24 ++#define XDMA_COALESCE_SHIFT 16 ++ ++#define XDMA_DELAY_MAX 0xFF /**< Maximum delay counter value */ ++#define XDMA_COALESCE_MAX 0xFF /**< Maximum coalescing counter value */ ++ ++/* BD definitions for Axi DMA ++ */ ++#define XDMA_BD_STS_ACTUAL_LEN_MASK 0x007FFFFF ++#define XDMA_BD_STS_COMPL_MASK 0x80000000 ++#define XDMA_BD_STS_ERR_MASK 0x70000000 ++#define XDMA_BD_STS_ALL_MASK 0xF0000000 ++ ++/* DMA BD special bits definitions ++ */ ++#define XDMA_BD_SOP 0x08000000 /* Start of packet bit */ ++#define XDMA_BD_EOP 0x04000000 /* End of packet bit */ ++ ++/* BD Software Flag definitions for Axi DMA ++ */ ++#define XDMA_BD_SF_POLL_MODE_MASK 0x00000002 ++#define XDMA_BD_SF_SW_DONE_MASK 0x00000001 ++ ++/* driver defines */ ++#define XDMA_MAX_BD_CNT 2048 ++#define XDMA_MAX_CHANS_PER_DEVICE 2 ++#define XDMA_MAX_TRANS_LEN 0x7FF000 ++#define XDMA_MAX_APPWORDS 5 ++#define XDMA_BD_CLEANUP_THRESHOLD ((XDMA_MAX_BD_CNT * 8) / 10) ++ ++/* Platform data definition until ARM supports device tree */ ++struct dma_channel_config { ++ char *type; ++ unsigned int include_dre; ++ unsigned int datawidth; ++ unsigned int max_burst_len; ++ unsigned int irq; ++ unsigned int poll_mode; ++ unsigned int lite_mode; ++}; ++struct dma_device_config { ++ char *type; ++ unsigned int include_sg; ++ unsigned int sg_include_stscntrl_strm; /* dma only */ ++ unsigned int channel_count; ++ struct dma_channel_config *channel_config; ++}; ++ ++struct xdma_desc_hw { ++ u32 next_desc; /* 0x00 */ ++ u32 pad1; /* 0x04 */ ++ u32 src_addr; /* 0x08 */ ++ u32 pad2; /* 0x0c */ ++ u32 addr_vsize; /* 0x10 */ ++ u32 hsize; /* 0x14 */ ++ u32 control; /* 0x18 */ ++ u32 status; /* 0x1c */ ++ u32 app[5]; /* 0x20 */ ++ u32 dmahead; ++ u32 sw_flag; /* 0x38 */ ++ u32 Reserved0; ++} __aligned(64); ++ ++/* shared by all Xilinx DMA engines */ ++struct xdma_regs { ++ u32 cr; /* 0x00 Control Register */ ++ u32 sr; /* 0x04 Status Register */ ++ u32 cdr; /* 0x08 Current Descriptor Register */ ++ u32 pad1; ++ u32 tdr; /* 0x10 Tail Descriptor Register */ ++ u32 pad2; ++ u32 src; /* 0x18 Source Address Register (cdma) */ ++ u32 pad3; ++ u32 dst; /* 0x20 Destination Address Register (cdma) */ ++ u32 pad4; ++ u32 btt_ref; /* 0x28 Bytes To Transfer (cdma) or ++ park_ref (vdma) */ ++ u32 version; /* 0x2c version (vdma) */ ++}; ++ ++/* Per DMA specific operations should be embedded in the channel structure */ ++struct xdma_chan { ++ char name[64]; ++ struct xdma_regs __iomem *regs; ++ struct device *dev; /* The dma device */ ++ struct xdma_desc_hw *bds[XDMA_MAX_BD_CNT]; ++ dma_addr_t bd_phys_addr; ++ u32 bd_chain_size; ++ int bd_cur; ++ int bd_tail; ++ unsigned int bd_used; /* # of BDs passed to hw chan */ ++ enum dma_data_direction direction; /* Transfer direction */ ++ int id; /* Channel ID */ ++ int irq; /* Channel IRQ */ ++ int poll_mode; /* Poll mode turned on? */ ++ spinlock_t lock; /* Descriptor operation lock */ ++ struct tasklet_struct tasklet; /* Cleanup work after irq */ ++ struct tasklet_struct dma_err_tasklet; /* Cleanup work after irq */ ++ int max_len; /* Maximum len per transfer */ ++ int err; /* Channel has errors */ ++ int client_count; ++}; ++ ++struct xdma_device { ++ void __iomem *regs; ++ struct device *dev; ++ struct list_head node; ++ struct xdma_chan *chan[XDMA_MAX_CHANS_PER_DEVICE]; ++ u8 channel_count; ++}; ++ ++struct xdma_head { ++ void *userbuf; ++ unsigned int size; ++ unsigned int dmaflag; ++ enum dma_data_direction dmadir; ++ void *sglist; ++ unsigned int sgcnt; ++ struct completion cmp; ++ struct xdma_chan *chan; ++ unsigned int nappwords_o; ++ u32 appwords_o[XDMA_MAX_APPWORDS]; ++ unsigned int userflag; ++ u32 last_bd_index; ++}; ++ ++struct xdma_chan *xdma_request_channel(char *name); ++void xdma_release_channel(struct xdma_chan *chan); ++void xdma_release_all_channels(void); ++int xdma_submit(struct xdma_chan *chan, ++ void *userbuf, ++ unsigned int size, ++ unsigned int nappwords_i, ++ u32 *appwords_i, ++ unsigned int nappwords_o, ++ unsigned int user_flags, ++ struct xdma_head **dmaheadpp); ++int xdma_wait(struct xdma_head *dmahead, unsigned int user_flags); ++int xdma_getconfig(struct xdma_chan *chan, ++ unsigned char *irq_thresh, ++ unsigned char *irq_delay); ++int xdma_setconfig(struct xdma_chan *chan, ++ unsigned char irq_thresh, ++ unsigned char irq_delay); ++ ++#endif +diff --git a/drivers/staging/apf/xlnk-eng.c b/drivers/staging/apf/xlnk-eng.c +new file mode 100644 +index 0000000..b38d5be +--- /dev/null ++++ b/drivers/staging/apf/xlnk-eng.c +@@ -0,0 +1,223 @@ ++/* ++ * Xilinx XLNK Engine Driver ++ * ++ * Copyright (C) 2010 Xilinx, Inc. All rights reserved. ++ * ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "xlnk-eng.h" ++ ++static DEFINE_MUTEX(xlnk_eng_list_mutex); ++static LIST_HEAD(xlnk_eng_list); ++ ++int xlnk_eng_register_device(struct xlnk_eng_device *xlnk_dev) ++{ ++ mutex_lock(&xlnk_eng_list_mutex); ++ /* todo: need to add more error checking */ ++ ++ list_add_tail(&xlnk_dev->global_node, &xlnk_eng_list); ++ ++ mutex_unlock(&xlnk_eng_list_mutex); ++ ++ return 0; ++} ++EXPORT_SYMBOL(xlnk_eng_register_device); ++ ++ ++void xlnk_eng_unregister_device(struct xlnk_eng_device *xlnk_dev) ++{ ++ mutex_lock(&xlnk_eng_list_mutex); ++ /* todo: need to add more error checking */ ++ ++ list_del(&xlnk_dev->global_node); ++ ++ mutex_unlock(&xlnk_eng_list_mutex); ++} ++EXPORT_SYMBOL(xlnk_eng_unregister_device); ++ ++struct xlnk_eng_device *xlnk_eng_request_by_name(char *name) ++{ ++ struct xlnk_eng_device *device, *_d; ++ int found = 0; ++ ++ mutex_lock(&xlnk_eng_list_mutex); ++ ++ list_for_each_entry_safe(device, _d, &xlnk_eng_list, global_node) { ++ if (!strcmp(dev_name(device->dev), name)) { ++ found = 1; ++ break; ++ } ++ } ++ if (found) ++ device = device->alloc(device); ++ else ++ device = NULL; ++ ++ mutex_unlock(&xlnk_eng_list_mutex); ++ ++ return device; ++} ++EXPORT_SYMBOL(xlnk_eng_request_by_name); ++ ++void xlnk_eng_release(struct xlnk_eng_device *xlnk_dev) ++{ ++ if (!xlnk_dev) ++ return; ++ ++ xlnk_dev->free(xlnk_dev); ++} ++EXPORT_SYMBOL(xlnk_eng_release); ++ ++#define DRIVER_NAME "xilinx-xlnk-eng" ++ ++struct xilinx_xlnk_eng_device { ++ struct xlnk_eng_device common; ++ void __iomem *base; ++ spinlock_t lock; ++ int cnt; ++}; ++ ++ ++#define to_xilinx_xlnk(dev) container_of(dev, \ ++ struct xilinx_xlnk_eng_device, common) ++ ++static struct xlnk_eng_device *xilinx_xlnk_alloc( ++ struct xlnk_eng_device *xlnkdev) ++{ ++ struct xilinx_xlnk_eng_device *xdev; ++ struct xlnk_eng_device *retdev; ++ ++ xdev = to_xilinx_xlnk(xlnkdev); ++ ++ if (xdev->cnt == 0) { ++ xdev->cnt++; ++ retdev = xlnkdev; ++ } else ++ retdev = NULL; ++ ++ return retdev; ++} ++ ++static void xilinx_xlnk_free(struct xlnk_eng_device *xlnkdev) ++{ ++ struct xilinx_xlnk_eng_device *xdev; ++ ++ xdev = to_xilinx_xlnk(xlnkdev); ++ ++ xdev->cnt = 0; ++} ++ ++static int xlnk_eng_probe(struct platform_device *pdev) ++{ ++ struct resource *res; ++ struct xilinx_xlnk_eng_device *xdev; ++ struct uio_info *info; ++ char *devname; ++ ++ pr_info("xlnk_eng_probe ...\n"); ++ xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL); ++ if (!xdev) { ++ dev_err(&pdev->dev, "Not enough memory for device\n"); ++ return -ENOMEM; ++ } ++ ++ /* more error handling */ ++ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); ++ if (!info) { ++ dev_err(&pdev->dev, "Not enough memory for device\n"); ++ return -ENOMEM; ++ } ++ ++ devname = devm_kzalloc(&pdev->dev, 64, GFP_KERNEL); ++ if (!devname) { ++ dev_err(&pdev->dev, "Not enough memory for device\n"); ++ return -ENOMEM; ++ } ++ sprintf(devname, "%s.%d", DRIVER_NAME, pdev->id); ++ pr_info("uio name %s\n", devname); ++ /* iomap registers */ ++ ++ /* Get the data from the platform device */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(&pdev->dev, "invalid resource\n"); ++ return -EINVAL; ++ } ++ xdev->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); ++ ++ /* %pa types should be used here */ ++ dev_info(&pdev->dev, "physical base : 0x%lx\n", ++ (unsigned long)res->start); ++ dev_info(&pdev->dev, "register range : 0x%lx\n", ++ (unsigned long)resource_size(res)); ++ dev_info(&pdev->dev, "base remapped to: 0x%lx\n", ++ (unsigned long)xdev->base); ++ if (!xdev->base) { ++ dev_err(&pdev->dev, "unable to iomap registers\n"); ++ return -ENOMEM; ++ } ++ ++ info->mem[0].addr = res->start; ++ info->mem[0].size = resource_size(res); ++ info->mem[0].memtype = UIO_MEM_PHYS; ++ info->mem[0].internal_addr = xdev->base; ++ ++ /* info->name = DRIVER_NAME; */ ++ info->name = devname; ++ info->version = "0.0.1"; ++ ++ info->irq = -1; ++ ++ xdev->common.dev = &pdev->dev; ++ ++ xdev->common.alloc = xilinx_xlnk_alloc; ++ xdev->common.free = xilinx_xlnk_free; ++ ++ dev_set_drvdata(&pdev->dev, xdev); ++ ++ spin_lock_init(&xdev->lock); ++ ++ xdev->cnt = 0; ++ ++ xlnk_eng_register_device(&xdev->common); ++ ++ if (uio_register_device(&pdev->dev, info)) { ++ dev_err(&pdev->dev, "uio_register_device failed\n"); ++ return -ENODEV; ++ } ++ dev_info(&pdev->dev, "xilinx-xlnk-eng uio registered\n"); ++ ++ return 0; ++} ++ ++static int xlnk_eng_remove(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++static struct platform_driver xlnk_eng_driver = { ++ .probe = xlnk_eng_probe, ++ .remove = xlnk_eng_remove, ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = DRIVER_NAME, ++ }, ++}; ++ ++module_platform_driver(xlnk_eng_driver); ++ ++MODULE_DESCRIPTION("Xilinx xlnk engine generic driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/staging/apf/xlnk-eng.h b/drivers/staging/apf/xlnk-eng.h +new file mode 100644 +index 0000000..842ce28 +--- /dev/null ++++ b/drivers/staging/apf/xlnk-eng.h +@@ -0,0 +1,34 @@ ++/* ++ * Xilinx XLNK Engine Driver ++ * ++ * Copyright (C) 2010 Xilinx, Inc. All rights reserved. ++ * ++ * ++ */ ++ ++#ifndef XLNK_ENG_H ++#define XLNK_ENG_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct xlnk_eng_device { ++ struct list_head global_node; ++ struct xlnk_eng_device * (*alloc)(struct xlnk_eng_device *xdev); ++ void (*free)(struct xlnk_eng_device *xdev); ++ struct device *dev; ++}; ++extern int xlnk_eng_register_device(struct xlnk_eng_device *xlnk_dev); ++extern void xlnk_eng_unregister_device(struct xlnk_eng_device *xlnk_dev); ++extern struct xlnk_eng_device *xlnk_eng_request_by_name(char *name); ++extern void xlnk_eng_release(struct xlnk_eng_device *xlnk_dev); ++ ++#endif ++ +diff --git a/drivers/staging/apf/xlnk-event-tracer-type.h b/drivers/staging/apf/xlnk-event-tracer-type.h +new file mode 100644 +index 0000000..6afef20 +--- /dev/null ++++ b/drivers/staging/apf/xlnk-event-tracer-type.h +@@ -0,0 +1,39 @@ ++#ifndef XLNK_EVENT_TRACER_TYPE_H ++#define XLNK_EVENT_TRACER_TYPE_H ++ ++#define XLNK_ET_USERSPACE_BEFORE_ACC_TRANSFER_CALL 50 ++#define XLNK_ET_USERSPACE_BEFORE_PORT_WAIT4COMPLETION 51 ++ ++#define XLNK_ET_USERSPACE_BEFORE_DMA_SUBMIT 100 ++#define XLNK_ET_USERSPACE_AFTER_DMA_SUBMIT 101 ++#define XLNK_ET_USERSPACE_BEFORE_DMA_WAIT4COMPLETION 102 ++#define XLNK_ET_USERSPACE_AFTER_DMA_WAIT4COMPLETION 103 ++ ++#define XLNK_ET_KERNEL_ENTER_IOCTL 5000 ++#define XLNK_ET_KERNEL_LEAVE_IOCTL 5001 ++#define XLNK_ET_KERNEL_ENTER_DMA_SUBMIT 5002 ++#define XLNK_ET_KERNEL_LEAVE_DMA_SUBMIT 5003 ++#define XLNK_ET_KERNEL_BEFORE_PIN_USER_PAGE 5004 ++#define XLNK_ET_KERNEL_BEFORE_GET_USER_PAGES 5005 ++#define XLNK_ET_KERNEL_AFTER_GET_USER_PAGES 5006 ++#define XLNK_ET_KERNEL_AFTER_PIN_USER_PAGE 5007 ++#define XLNK_ET_KERNEL_BEFORE_DMA_MAP_SG 5008 ++#define XLNK_ET_KERNEL_AFTER_DMA_MAP_SG 5009 ++#define XLNK_ET_KERNEL_BEFORE_DMA_SETUP_BD 5010 ++#define XLNK_ET_KERNEL_AFTER_DMA_KICKOFF 5011 ++#define XLNK_ET_KERNEL_AFTER_DMA_SETUP_BD 5012 ++#define XLNK_ET_KERNEL_ENTER_DMA_WAIT 5013 ++#define XLNK_ET_KERNEL_BEFORE_DMA_UNMAP_SG 5014 ++#define XLNK_ET_KERNEL_AFTER_DMA_UNMAP_SG 5015 ++#define XLNK_ET_KERNEL_LEAVE_DMA_WAIT 5016 ++ ++ ++#define XLNK_ET_KERNEL_DMA_MM2S_INTR 5100 ++#define XLNK_ET_KERNEL_DMA_MM2S_HALF_BOTTOM_START 5101 ++#define XLNK_ET_KERNEL_DMA_MM2S_HALF_BOTTOM_END 5102 ++#define XLNK_ET_KERNEL_DMA_S2MM_INTR 5110 ++#define XLNK_ET_KERNEL_DMA_S2MM_HALF_BOTTOM_START 5111 ++#define XLNK_ET_KERNEL_DMA_S2MM_HALF_BOTTOM_END 5112 ++ ++#endif ++ +diff --git a/drivers/staging/apf/xlnk-ioctl.h b/drivers/staging/apf/xlnk-ioctl.h +new file mode 100644 +index 0000000..665fc27 +--- /dev/null ++++ b/drivers/staging/apf/xlnk-ioctl.h +@@ -0,0 +1,39 @@ ++#ifndef _XLNK_IOCTL_H ++#define _XLNK_IOCTL_H ++ ++#include ++ ++#define XLNK_IOC_MAGIC 'X' ++ ++#define XLNK_IOCRESET _IO(XLNK_IOC_MAGIC, 0) ++ ++#define XLNK_IOCALLOCBUF _IOWR(XLNK_IOC_MAGIC, 2, unsigned long) ++#define XLNK_IOCFREEBUF _IOWR(XLNK_IOC_MAGIC, 3, unsigned long) ++ ++ ++ ++#define XLNK_IOCDMAREQUEST _IOWR(XLNK_IOC_MAGIC, 7, unsigned long) ++#define XLNK_IOCDMASUBMIT _IOWR(XLNK_IOC_MAGIC, 8, unsigned long) ++#define XLNK_IOCDMAWAIT _IOWR(XLNK_IOC_MAGIC, 9, unsigned long) ++#define XLNK_IOCDMARELEASE _IOWR(XLNK_IOC_MAGIC, 10, unsigned long) ++ ++ ++ ++ ++ ++#define XLNK_IOCDEVREGISTER _IOWR(XLNK_IOC_MAGIC, 16, unsigned long) ++#define XLNK_IOCDMAREGISTER _IOWR(XLNK_IOC_MAGIC, 17, unsigned long) ++#define XLNK_IOCDEVUNREGISTER _IOWR(XLNK_IOC_MAGIC, 18, unsigned long) ++#define XLNK_IOCCDMAREQUEST _IOWR(XLNK_IOC_MAGIC, 19, unsigned long) ++#define XLNK_IOCCDMASUBMIT _IOWR(XLNK_IOC_MAGIC, 20, unsigned long) ++#define XLNK_IOCGETEVENTSIZE _IOWR(XLNK_IOC_MAGIC, 21, unsigned long) ++#define XLNK_IOCDUMPEVENTS _IOWR(XLNK_IOC_MAGIC, 22, unsigned long) ++#define XLNK_IOCMCDMAREGISTER _IOWR(XLNK_IOC_MAGIC, 23, unsigned long) ++#define XLNK_IOCCACHECTRL _IOWR(XLNK_IOC_MAGIC, 24, unsigned long) ++ ++#define XLNK_IOCSHUTDOWN _IOWR(XLNK_IOC_MAGIC, 100, unsigned long) ++#define XLNK_IOCRECRES _IOWR(XLNK_IOC_MAGIC, 101, unsigned long) ++ ++#define XLNK_IOC_MAXNR 101 ++ ++#endif +diff --git a/drivers/staging/apf/xlnk.c b/drivers/staging/apf/xlnk.c +new file mode 100644 +index 0000000..df107d61 +--- /dev/null ++++ b/drivers/staging/apf/xlnk.c +@@ -0,0 +1,1261 @@ ++/* ++ * xlnk.c ++ * ++ * Xilinx Accelerator driver support. ++ * ++ * Copyright (C) 2010 Xilinx Inc. ++ * ++ * This package 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. ++ * ++ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ++ */ ++ ++/* ----------------------------------- Host OS */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include /* error codes */ ++#include /* dma */ ++ ++ ++#include "xlnk-ioctl.h" ++#include "xlnk-event-tracer-type.h" ++#include "xlnk.h" ++ ++#ifdef CONFIG_XILINX_DMA_APF ++#include "xilinx-dma-apf.h" ++#endif ++ ++#ifdef CONFIG_XILINX_MCDMA ++#include "xdma-if.h" ++#include "xdma.h" ++ ++static void xdma_if_device_release(struct device *op) ++{ ++} ++ ++#endif ++ ++#define DRIVER_NAME "xlnk" ++#define DRIVER_VERSION "0.2" ++ ++static struct platform_device *xlnk_pdev; ++static struct device *xlnk_dev; ++ ++static struct cdev xlnk_cdev; ++ ++static struct class *xlnk_class; ++ ++static s32 driver_major; ++ ++static char *driver_name = DRIVER_NAME; ++ ++static void *xlnk_dev_buf; ++static ssize_t xlnk_dev_size; ++static int xlnk_dev_vmas; ++ ++#define XLNK_BUF_POOL_SIZE 256 ++static void **xlnk_bufpool; ++static unsigned int xlnk_bufpool_size = XLNK_BUF_POOL_SIZE; ++static dma_addr_t xlnk_phyaddr[XLNK_BUF_POOL_SIZE]; ++static size_t xlnk_buflen[XLNK_BUF_POOL_SIZE]; ++static unsigned int xlnk_bufcacheable[XLNK_BUF_POOL_SIZE]; ++ ++ ++static int xlnk_open(struct inode *ip, struct file *filp); /* Open */ ++static int xlnk_release(struct inode *ip, struct file *filp); /* Release */ ++static long xlnk_ioctl(struct file *filp, unsigned int code, ++ unsigned long args); ++static ssize_t xlnk_read(struct file *filp, char __user *buf, ++ size_t count, loff_t *offp); ++static ssize_t xlnk_write(struct file *filp, const char __user *buf, ++ size_t count, loff_t *offp); ++static int xlnk_mmap(struct file *filp, struct vm_area_struct *vma); ++static void xlnk_vma_open(struct vm_area_struct *vma); ++static void xlnk_vma_close(struct vm_area_struct *vma); ++ ++static int xlnk_init_bufpool(void); ++ ++static void xlnk_start_benchmark_counter(void); ++static int xlnk_dump_events(unsigned long buf); ++static int xlnk_get_event_size(unsigned long buf); ++ ++static int xlnk_shutdown(unsigned long buf); ++static int xlnk_recover_resource(unsigned long buf); ++ ++static const struct file_operations xlnk_fops = { ++ .open = xlnk_open, ++ .release = xlnk_release, ++ .read = xlnk_read, ++ .write = xlnk_write, ++ .unlocked_ioctl = xlnk_ioctl, ++ .mmap = xlnk_mmap, ++}; ++ ++#define MAX_XLNK_DMAS 16 ++ ++struct xlnk_device_pack { ++ char name[64]; ++ struct platform_device pdev; ++ struct resource res[8]; ++ ++#ifdef CONFIG_XILINX_DMA_APF ++ struct dma_channel_config dma_chan_cfg[4]; /* for xidane dma only */ ++ struct dma_device_config dma_dev_cfg; /* for xidane dma only */ ++#endif ++ ++#ifdef CONFIG_XILINX_MCDMA ++ struct xdma_device_info mcdma_dev_cfg; /* for mcdma only */ ++#endif ++ ++}; ++ ++static struct xlnk_device_pack *xlnk_devpacks[16]; ++static void xlnk_devpacks_init(void) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < 16; i++) ++ xlnk_devpacks[0] = NULL; ++ ++} ++ ++static void xlnk_devpacks_delete(struct xlnk_device_pack *devpack) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < 16; i++) { ++ if (xlnk_devpacks[i] == devpack) ++ xlnk_devpacks[i] = NULL; ++ } ++} ++ ++static void xlnk_devpacks_add(struct xlnk_device_pack *devpack) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < 16; i++) { ++ if (xlnk_devpacks[i] == NULL) { ++ xlnk_devpacks[i] = devpack; ++ break; ++ } ++ } ++} ++ ++static struct xlnk_device_pack *xlnk_devpacks_find(unsigned long base) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < 16; i++) { ++ if (xlnk_devpacks[i] ++ && xlnk_devpacks[i]->res[0].start == base) ++ return xlnk_devpacks[i]; ++ } ++ return NULL; ++} ++ ++static void xlnk_devpacks_free(unsigned long base) ++{ ++ struct xlnk_device_pack *devpack; ++ ++ devpack = xlnk_devpacks_find(base); ++ if (devpack) { ++ platform_device_unregister(&devpack->pdev); ++ kfree(devpack); ++ xlnk_devpacks_delete(devpack); ++ } ++} ++ ++static void xlnk_devpacks_free_all(void) ++{ ++ struct xlnk_device_pack *devpack; ++ unsigned int i; ++ ++ for (i = 0; i < 16; i++) { ++ devpack = xlnk_devpacks[i]; ++ if (devpack) { ++ platform_device_unregister(&devpack->pdev); ++ kfree(devpack); ++ xlnk_devpacks_delete(devpack); ++ } ++ } ++} ++ ++static int xlnk_probe(struct platform_device *pdev) ++{ ++ int err; ++ dev_t dev = 0; ++ ++ /* use 2.6 device model */ ++ err = alloc_chrdev_region(&dev, 0, 1, driver_name); ++ if (err) { ++ pr_err("%s: Can't get major %d\n", __func__, driver_major); ++ goto err1; ++ } ++ ++ cdev_init(&xlnk_cdev, &xlnk_fops); ++ ++ xlnk_cdev.owner = THIS_MODULE; ++ ++ err = cdev_add(&xlnk_cdev, dev, 1); ++ ++ if (err) { ++ pr_err("%s: Failed to add XLNK device\n", __func__); ++ goto err3; ++ } ++ ++ /* udev support */ ++ xlnk_class = class_create(THIS_MODULE, "xlnk"); ++ if (IS_ERR(xlnk_class)) { ++ pr_err("%s: Error creating xlnk class\n", __func__); ++ goto err3; ++ } ++ ++ driver_major = MAJOR(dev); ++ ++ pr_info("xlnk major %d\n", driver_major); ++ ++ device_create(xlnk_class, NULL, MKDEV(driver_major, 0), ++ NULL, "xlnk"); ++ ++ xlnk_init_bufpool(); ++ ++ pr_info("%s driver loaded\n", DRIVER_NAME); ++ ++ xlnk_pdev = pdev; ++ xlnk_dev = &pdev->dev; ++ ++ if (xlnk_pdev) ++ pr_info("xlnk_pdev is not null\n"); ++ else ++ pr_info("xlnk_pdev is null\n"); ++ ++ xlnk_devpacks_init(); ++ ++#ifdef CONFIG_ARCH_ZYNQ ++ xlnk_start_benchmark_counter(); ++#endif ++ ++ return 0; ++ ++err3: ++ cdev_del(&xlnk_cdev); ++ unregister_chrdev_region(dev, 1); ++err1: ++ return err; ++} ++ ++static int xlnk_buf_findnull(void) ++{ ++ int i; ++ ++ for (i = 1; i < xlnk_bufpool_size; i++) { ++ if (!xlnk_bufpool[i]) ++ return i; ++ } ++ ++ return 0; ++} ++ ++/** ++ * allocate and return an id ++ * id must be a positve number ++ */ ++static int xlnk_allocbuf(unsigned int len, unsigned int cacheable) ++{ ++ int id; ++ ++ id = xlnk_buf_findnull(); ++ ++ if (id <= 0) ++ return -ENOMEM; ++ ++ xlnk_bufpool[id] = dma_alloc_coherent(xlnk_dev, len, ++ &xlnk_phyaddr[id], ++ GFP_KERNEL | GFP_DMA); ++ xlnk_buflen[id] = len; ++ xlnk_bufcacheable[id] = cacheable; ++ ++ if (!xlnk_bufpool[id]) { ++ pr_err("%s: dma_alloc_coherent of %d byte buffer failed\n", ++ __func__, len); ++ return -ENOMEM; ++ } ++ ++ return id; ++} ++ ++static int xlnk_init_bufpool(void) ++{ ++ unsigned int i; ++ ++ xlnk_dev_buf = kmalloc(8192, GFP_KERNEL | __GFP_DMA); ++ *((char *)xlnk_dev_buf) = '\0'; ++ ++ if (!xlnk_dev_buf) { ++ pr_err("%s: malloc failed\n", __func__); ++ return -ENOMEM; ++ } ++ ++ xlnk_bufpool = kmalloc(sizeof(void *) * xlnk_bufpool_size, ++ GFP_KERNEL); ++ ++ xlnk_bufpool[0] = xlnk_dev_buf; ++ for (i = 1; i < xlnk_bufpool_size; i++) ++ xlnk_bufpool[i] = NULL; ++ ++ return 0; ++} ++ ++#define XLNK_SUSPEND NULL ++#define XLNK_RESUME NULL ++ ++static int xlnk_remove(struct platform_device *pdev) ++{ ++ dev_t devno; ++ ++ kfree(xlnk_dev_buf); ++ xlnk_dev_buf = NULL; ++ ++ kfree(xlnk_bufpool); ++ xlnk_bufpool = NULL; ++ ++ devno = MKDEV(driver_major, 0); ++ cdev_del(&xlnk_cdev); ++ unregister_chrdev_region(devno, 1); ++ if (xlnk_class) { ++ /* remove the device from sysfs */ ++ device_destroy(xlnk_class, MKDEV(driver_major, 0)); ++ class_destroy(xlnk_class); ++ } ++ ++ xlnk_devpacks_free_all(); ++ ++ return 0; ++} ++ ++ ++static struct platform_driver xlnk_driver = { ++ .driver = { ++ .name = DRIVER_NAME, ++ }, ++ .probe = xlnk_probe, ++ .remove = xlnk_remove, ++ .suspend = XLNK_SUSPEND, ++ .resume = XLNK_RESUME, ++}; ++ ++static u64 dma_mask = 0xFFFFFFFFUL; ++ ++static struct platform_device xlnk_device = { ++ .name = "xlnk", ++ .id = 0, ++ .dev = { ++ .platform_data = NULL, ++ .dma_mask = &dma_mask, ++ .coherent_dma_mask = 0xFFFFFFFF, ++ }, ++ .resource = NULL, ++ .num_resources = 0, ++}; ++ ++/* ++ * This function is called when an application opens handle to the ++ * bridge driver. ++ */ ++static int xlnk_open(struct inode *ip, struct file *filp) ++{ ++ int status = 0; ++ ++ if ((filp->f_flags & O_ACCMODE) == O_WRONLY) ++ xlnk_dev_size = 0; ++ ++ return status; ++} ++ ++static ssize_t xlnk_read(struct file *filp, char __user *buf, ++ size_t count, loff_t *offp) ++{ ++ ssize_t retval = 0; ++ ++ /* todo: need semi for critical section */ ++ ++ if (*offp >= xlnk_dev_size) ++ goto out; ++ ++ if (*offp + count > xlnk_dev_size) ++ count = xlnk_dev_size - *offp; ++ ++ if (copy_to_user(buf, xlnk_dev_buf + *offp, count)) { ++ retval = -EFAULT; ++ goto out; ++ } ++ *offp += count; ++ retval = count; ++ ++ out: ++ return retval; ++} ++ ++static ssize_t xlnk_write(struct file *filp, const char __user *buf, ++ size_t count, loff_t *offp) ++{ ++ ssize_t retval = 0; ++ ++ /* todo: need to setup semi for critical section */ ++ ++ if (copy_from_user(xlnk_dev_buf + *offp, buf, count)) { ++ retval = -EFAULT; ++ goto out; ++ } ++ *offp += count; ++ retval = count; ++ ++ if (xlnk_dev_size < *offp) ++ xlnk_dev_size = *offp; ++ ++ out: ++ return retval; ++} ++ ++/* ++ * This function is called when an application closes handle to the bridge ++ * driver. ++ */ ++static int xlnk_release(struct inode *ip, struct file *filp) ++{ ++ int status = 0; ++ return status; ++} ++ ++ ++static int xlnk_devregister(char *name, unsigned int id, ++ unsigned long base, unsigned int size, ++ unsigned int *irqs, ++ u32 *handle) ++{ ++ unsigned int nres; ++ unsigned int nirq; ++ unsigned int *irqptr; ++ struct xlnk_device_pack *devpack; ++ unsigned int i; ++ int status; ++ ++ devpack = xlnk_devpacks_find(base); ++ if (devpack) { ++ *handle = (u32)devpack; ++ return 0; ++ } ++ nirq = 0; ++ irqptr = irqs; ++ ++ while (*irqptr) { ++ nirq++; ++ irqptr++; ++ } ++ ++ if (nirq > 7) ++ return -ENOMEM; ++ ++ nres = nirq + 1; ++ ++ devpack = kzalloc(sizeof(struct xlnk_device_pack), ++ GFP_KERNEL); ++ strcpy(devpack->name, name); ++ devpack->pdev.name = devpack->name; ++ ++ devpack->pdev.id = id; ++ ++ devpack->pdev.dev.dma_mask = &dma_mask; ++ devpack->pdev.dev.coherent_dma_mask = 0xFFFFFFFF; ++ ++ devpack->res[0].start = base; ++ devpack->res[0].end = base + size - 1; ++ devpack->res[0].flags = IORESOURCE_MEM; ++ ++ for (i = 0; i < nirq; i++) { ++ devpack->res[i+1].start = irqs[i]; ++ devpack->res[i+1].end = irqs[i]; ++ devpack->res[i+1].flags = IORESOURCE_IRQ; ++ } ++ ++ devpack->pdev.resource = devpack->res; ++ devpack->pdev.num_resources = nres; ++ ++ status = platform_device_register(&devpack->pdev); ++ if (status) { ++ kfree(devpack); ++ *handle = 0; ++ } else { ++ xlnk_devpacks_add(devpack); ++ *handle = (u32)devpack; ++ } ++ return status; ++} ++ ++static int xlnk_dmaregister(char *name, unsigned int id, ++ unsigned long base, unsigned int size, ++ unsigned int chan_num, ++ unsigned int chan0_dir, ++ unsigned int chan0_irq, ++ unsigned int chan0_poll_mode, ++ unsigned int chan0_include_dre, ++ unsigned int chan0_data_width, ++ unsigned int chan1_dir, ++ unsigned int chan1_irq, ++ unsigned int chan1_poll_mode, ++ unsigned int chan1_include_dre, ++ unsigned int chan1_data_width, ++ u32 *handle) ++{ ++ int status = -1; ++ ++#ifdef CONFIG_XILINX_DMA_APF ++ ++ struct xlnk_device_pack *devpack; ++ ++ if (strcmp(name, "xilinx-axidma")) ++ return -EINVAL; ++ ++ if (chan_num < 1 || chan_num > 2) ++ return -EINVAL; ++ ++ devpack = xlnk_devpacks_find(base); ++ if (devpack) { ++ *handle = (u32)devpack; ++ return 0; ++ } ++ ++ devpack = kzalloc(sizeof(struct xlnk_device_pack), ++ GFP_KERNEL); ++ if (!devpack) ++ return -ENOMEM; ++ ++ strcpy(devpack->name, name); ++ devpack->pdev.name = devpack->name; ++ ++ devpack->pdev.id = id; ++ ++ devpack->dma_chan_cfg[0].include_dre = chan0_include_dre; ++ devpack->dma_chan_cfg[0].datawidth = chan0_data_width; ++ devpack->dma_chan_cfg[0].irq = chan0_irq; ++ devpack->dma_chan_cfg[0].poll_mode = chan0_poll_mode; ++ devpack->dma_chan_cfg[0].type = chan0_dir ? ++ "axi-dma-s2mm-channel" : ++ "axi-dma-mm2s-channel"; ++ ++ if (chan_num > 1) { ++ devpack->dma_chan_cfg[1].include_dre = chan1_include_dre; ++ devpack->dma_chan_cfg[1].datawidth = chan1_data_width; ++ devpack->dma_chan_cfg[1].irq = chan1_irq; ++ devpack->dma_chan_cfg[1].poll_mode = chan1_poll_mode; ++ devpack->dma_chan_cfg[1].type = chan1_dir ? ++ "axi-dma-s2mm-channel" : ++ "axi-dma-mm2s-channel"; ++ } ++ ++ devpack->dma_dev_cfg.type = "axi-dma"; ++ devpack->dma_dev_cfg.include_sg = 1; ++ devpack->dma_dev_cfg.sg_include_stscntrl_strm = 1; ++ devpack->dma_dev_cfg.channel_count = chan_num; ++ devpack->dma_dev_cfg.channel_config = &devpack->dma_chan_cfg[0]; ++ ++ devpack->pdev.dev.platform_data = &devpack->dma_dev_cfg; ++ ++ devpack->pdev.dev.dma_mask = &dma_mask; ++ devpack->pdev.dev.coherent_dma_mask = 0xFFFFFFFF; ++ ++ devpack->res[0].start = base; ++ devpack->res[0].end = base + size - 1; ++ devpack->res[0].flags = IORESOURCE_MEM; ++ ++ devpack->pdev.resource = devpack->res; ++ devpack->pdev.num_resources = 1; ++ ++ status = platform_device_register(&devpack->pdev); ++ if (status) { ++ kfree(devpack); ++ *handle = 0; ++ } else { ++ xlnk_devpacks_add(devpack); ++ *handle = (u32)devpack; ++ } ++ ++#endif ++ return status; ++} ++ ++static int xlnk_mcdmaregister(char *name, unsigned int id, ++ unsigned long base, unsigned int size, ++ unsigned int mm2s_chan_num, ++ unsigned int mm2s_chan_irq, ++ unsigned int s2mm_chan_num, ++ unsigned int s2mm_chan_irq, ++ u32 *handle) ++{ ++ int status = -1; ++ ++#ifdef CONFIG_XILINX_MCDMA ++ struct xlnk_device_pack *devpack; ++ ++ if (strcmp(name, "xdma")) ++ return -EINVAL; ++ ++ ++ devpack = xlnk_devpacks_find(base); ++ if (devpack) { ++ *handle = (u32)devpack; ++ return 0; ++ } ++ ++ devpack = kzalloc(sizeof(struct xlnk_device_pack), ++ GFP_KERNEL); ++ if (!devpack) ++ return -ENOMEM; ++ ++ strcpy(devpack->name, name); ++ devpack->pdev.name = devpack->name; ++ devpack->pdev.id = id; ++ ++ devpack->mcdma_dev_cfg.tx_chans = mm2s_chan_num; ++ devpack->mcdma_dev_cfg.rx_chans = s2mm_chan_num; ++ devpack->mcdma_dev_cfg.legacy_mode = XDMA_MCHAN_MODE; ++ devpack->mcdma_dev_cfg.device_id = id; ++ ++ devpack->pdev.dev.platform_data = &devpack->mcdma_dev_cfg; ++ devpack->pdev.dev.dma_mask = &dma_mask; ++ devpack->pdev.dev.coherent_dma_mask = 0xFFFFFFFF; ++ devpack->pdev.dev.release = xdma_if_device_release, ++ ++ devpack->res[0].start = base; ++ devpack->res[0].end = base + size - 1; ++ devpack->res[0].flags = IORESOURCE_MEM; ++ ++ devpack->res[1].start = mm2s_chan_irq; ++ devpack->res[1].end = s2mm_chan_irq; ++ devpack->res[1].flags = IORESOURCE_IRQ; ++ ++ devpack->pdev.resource = devpack->res; ++ devpack->pdev.num_resources = 2; ++ ++ status = platform_device_register(&devpack->pdev); ++ if (status) { ++ kfree(devpack); ++ *handle = 0; ++ } else { ++ xlnk_devpacks_add(devpack); ++ *handle = (u32)devpack; ++ } ++ ++#endif ++ ++ return status; ++} ++ ++static int xlnk_allocbuf_ioctl(struct file *filp, unsigned int code, ++ unsigned long args) ++{ ++ ++ union xlnk_args temp_args; ++ int status; ++ int id; ++ ++ status = copy_from_user(&temp_args, (void __user *)args, ++ sizeof(union xlnk_args)); ++ ++ if (status) ++ return -ENOMEM; ++ ++ id = xlnk_allocbuf(temp_args.allocbuf.len, ++ temp_args.allocbuf.cacheable); ++ ++ if (id <= 0) ++ return -ENOMEM; ++ ++ put_user(id, temp_args.allocbuf.idptr); ++ put_user((u32)(xlnk_phyaddr[id]), temp_args.allocbuf.phyaddrptr); ++ ++ return 0; ++} ++ ++static int xlnk_freebuf(int id) ++{ ++ ++ if (id <= 0 || id >= xlnk_bufpool_size) ++ return -ENOMEM; ++ ++ if (!xlnk_bufpool[id]) ++ return -ENOMEM; ++ ++ dma_free_coherent(xlnk_dev, xlnk_buflen[id], xlnk_bufpool[id], ++ xlnk_phyaddr[id]); ++ ++ xlnk_bufpool[id] = NULL; ++ xlnk_phyaddr[id] = (dma_addr_t)NULL; ++ xlnk_buflen[id] = 0; ++ ++ return 0; ++} ++ ++static void xlnk_free_all_buf(void) ++{ ++ int i; ++ ++ for (i = 1; i < xlnk_bufpool_size; i++) ++ xlnk_freebuf(i); ++} ++ ++static int xlnk_freebuf_ioctl(struct file *filp, unsigned int code, ++ unsigned long args) ++{ ++ ++ union xlnk_args temp_args; ++ int status; ++ int id; ++ ++ status = copy_from_user(&temp_args, (void __user *)args, ++ sizeof(union xlnk_args)); ++ ++ if (status) ++ return -ENOMEM; ++ ++ id = temp_args.freebuf.id; ++ return xlnk_freebuf(id); ++} ++ ++static int xlnk_dmarequest_ioctl(struct file *filp, unsigned int code, ++ unsigned long args) ++{ ++ ++#ifdef CONFIG_XILINX_DMA_APF ++ ++ union xlnk_args temp_args; ++ int status; ++ struct xdma_chan *chan; ++ ++ status = copy_from_user(&temp_args, (void __user *)args, ++ sizeof(union xlnk_args)); ++ ++ if (status) ++ return -ENOMEM; ++ ++ if (!temp_args.dmarequest.name[0]) ++ return 0; ++ ++ chan = xdma_request_channel(temp_args.dmarequest.name); ++ ++ if (!chan) { ++ return -ENOMEM; ++ } ++ ++ temp_args.dmarequest.dmachan = (u32)chan; ++ temp_args.dmarequest.bd_space_phys_addr = chan->bd_phys_addr; ++ temp_args.dmarequest.bd_space_size = chan->bd_chain_size; ++ ++ copy_to_user((void __user *)args, &temp_args, sizeof(union xlnk_args)); ++ ++ return 0; ++ ++#else ++ ++ return -1; ++ ++#endif ++ ++} ++ ++static int xlnk_dmasubmit_ioctl(struct file *filp, unsigned int code, ++ unsigned long args) ++{ ++ ++#ifdef CONFIG_XILINX_DMA_APF ++ union xlnk_args temp_args; ++ struct xdma_head *dmahead; ++ int status = -1; ++ ++ status = copy_from_user(&temp_args, (void __user *)args, ++ sizeof(union xlnk_args)); ++ ++ if (status) ++ return -ENOMEM; ++ ++ if (!temp_args.dmasubmit.dmachan) ++ return -ENODEV; ++ ++ status = xdma_submit((struct xdma_chan *)temp_args.dmasubmit.dmachan, ++ temp_args.dmasubmit.buf, ++ temp_args.dmasubmit.len, ++ temp_args.dmasubmit.nappwords_i, ++ temp_args.dmasubmit.appwords_i, ++ temp_args.dmasubmit.nappwords_o, ++ temp_args.dmasubmit.flag, ++ &dmahead); ++ ++ if (!status) { ++ temp_args.dmasubmit.dmahandle = (u32)dmahead; ++ temp_args.dmasubmit.last_bd_index = ++ (u32)dmahead->last_bd_index; ++ copy_to_user((void __user *)args, &temp_args, ++ sizeof(union xlnk_args)); ++ return 0; ++ } ++#endif ++ return -ENOMEM; ++} ++ ++ ++static int xlnk_dmawait_ioctl(struct file *filp, unsigned int code, ++ unsigned long args) ++{ ++ int status = -1; ++ ++#ifdef CONFIG_XILINX_DMA_APF ++ union xlnk_args temp_args; ++ struct xdma_head *dmahead; ++ ++ status = copy_from_user(&temp_args, (void __user *)args, ++ sizeof(union xlnk_args)); ++ ++ if (status) ++ return -ENOMEM; ++ ++ dmahead = (struct xdma_head *)temp_args.dmawait.dmahandle; ++ status = xdma_wait(dmahead, dmahead->userflag); ++ ++ if (temp_args.dmawait.nappwords) { ++ memcpy(temp_args.dmawait.appwords, dmahead->appwords_o, ++ dmahead->nappwords_o * sizeof(u32)); ++ ++ copy_to_user((void __user *)args, &temp_args, ++ sizeof(union xlnk_args)); ++ } ++ kfree(dmahead); ++ ++#endif ++ ++ return status; ++} ++ ++static int xlnk_dmarelease_ioctl(struct file *filp, unsigned int code, ++ unsigned long args) ++{ ++ int status = -1; ++ ++#ifdef CONFIG_XILINX_DMA_APF ++ ++ union xlnk_args temp_args; ++ status = copy_from_user(&temp_args, (void __user *)args, ++ sizeof(union xlnk_args)); ++ ++ if (status) ++ return -ENOMEM; ++ ++ xdma_release_channel((struct xdma_chan *)temp_args.dmarelease.dmachan); ++#endif ++ ++ return status; ++} ++ ++ ++static int xlnk_devregister_ioctl(struct file *filp, unsigned int code, ++ unsigned long args) ++{ ++ union xlnk_args temp_args; ++ int status; ++ u32 handle; ++ ++ status = copy_from_user(&temp_args, (void __user *)args, ++ sizeof(union xlnk_args)); ++ ++ if (status) ++ return -ENOMEM; ++ ++ status = xlnk_devregister(temp_args.devregister.name, ++ temp_args.devregister.id, ++ temp_args.devregister.base, ++ temp_args.devregister.size, ++ temp_args.devregister.irqs, ++ &handle); ++ ++ return status; ++} ++ ++static int xlnk_dmaregister_ioctl(struct file *filp, unsigned int code, ++ unsigned long args) ++{ ++ union xlnk_args temp_args; ++ int status; ++ u32 handle; ++ ++ status = copy_from_user(&temp_args, (void __user *)args, ++ sizeof(union xlnk_args)); ++ ++ if (status) ++ return -ENOMEM; ++ ++ status = xlnk_dmaregister(temp_args.dmaregister.name, ++ temp_args.dmaregister.id, ++ temp_args.dmaregister.base, ++ temp_args.dmaregister.size, ++ temp_args.dmaregister.chan_num, ++ temp_args.dmaregister.chan0_dir, ++ temp_args.dmaregister.chan0_irq, ++ temp_args.dmaregister.chan0_poll_mode, ++ temp_args.dmaregister.chan0_include_dre, ++ temp_args.dmaregister.chan0_data_width, ++ temp_args.dmaregister.chan1_dir, ++ temp_args.dmaregister.chan1_irq, ++ temp_args.dmaregister.chan1_poll_mode, ++ temp_args.dmaregister.chan1_include_dre, ++ temp_args.dmaregister.chan1_data_width, ++ &handle); ++ ++ return status; ++} ++ ++static int xlnk_mcdmaregister_ioctl(struct file *filp, unsigned int code, ++ unsigned long args) ++{ ++ union xlnk_args temp_args; ++ int status; ++ u32 handle; ++ ++ status = copy_from_user(&temp_args, (void __user *)args, ++ sizeof(union xlnk_args)); ++ ++ if (status) ++ return -ENOMEM; ++ ++ status = xlnk_mcdmaregister(temp_args.mcdmaregister.name, ++ temp_args.mcdmaregister.id, ++ temp_args.mcdmaregister.base, ++ temp_args.mcdmaregister.size, ++ temp_args.mcdmaregister.mm2s_chan_num, ++ temp_args.mcdmaregister.mm2s_chan_irq, ++ temp_args.mcdmaregister.s2mm_chan_num, ++ temp_args.mcdmaregister.s2mm_chan_irq, ++ &handle); ++ ++ return status; ++} ++ ++static int xlnk_devunregister_ioctl(struct file *filp, unsigned int code, ++ unsigned long args) ++{ ++ union xlnk_args temp_args; ++ int status; ++ ++ status = copy_from_user(&temp_args, (void __user *)args, ++ sizeof(union xlnk_args)); ++ ++ if (status) ++ return -ENOMEM; ++ ++ xlnk_devpacks_free(temp_args.devunregister.base); ++ ++ return 0; ++} ++ ++static int xlnk_cachecontrol_ioctl(struct file *filp, unsigned int code, ++ unsigned long args) ++{ ++ union xlnk_args temp_args; ++ int status, size; ++ void *paddr, *kaddr; ++ ++ status = copy_from_user(&temp_args, (void __user *)args, ++ sizeof(union xlnk_args)); ++ ++ if (status) { ++ pr_err("Error in copy_from_user. status = %d\n", status); ++ return -ENOMEM; ++ } ++ ++ if (!(temp_args.cachecontrol.action == 0 || ++ temp_args.cachecontrol.action == 1)) { ++ pr_err("Illegal action specified to cachecontrol_ioctl: %d\n", ++ temp_args.cachecontrol.action); ++ return -EINVAL; ++ } ++ ++ size = temp_args.cachecontrol.size; ++ paddr = temp_args.cachecontrol.phys_addr; ++ kaddr = phys_to_virt((unsigned int)paddr); ++ ++ if (temp_args.cachecontrol.action == 0) { ++ /* flush cache */ ++ dmac_map_area(kaddr, size, DMA_TO_DEVICE); ++ outer_clean_range((unsigned int)paddr, ++ (unsigned int)(paddr + size)); ++ } else { ++ /* invalidate cache */ ++ outer_inv_range((unsigned int)paddr, ++ (unsigned int)(paddr + size)); ++ dmac_unmap_area(kaddr, size, DMA_FROM_DEVICE); ++ } ++ ++ return 0; ++} ++ ++/* This function provides IO interface to the bridge driver. */ ++static long xlnk_ioctl(struct file *filp, unsigned int code, ++ unsigned long args) ++{ ++ int status = 0; ++ ++ xlnk_record_event(XLNK_ET_KERNEL_ENTER_IOCTL); ++ ++ if (_IOC_TYPE(code) != XLNK_IOC_MAGIC) ++ return -ENOTTY; ++ if (_IOC_NR(code) > XLNK_IOC_MAXNR) ++ return -ENOTTY; ++ ++ /* some sanity check */ ++ switch (code) { ++ case XLNK_IOCALLOCBUF: ++ status = xlnk_allocbuf_ioctl(filp, code, args); ++ break; ++ case XLNK_IOCFREEBUF: ++ status = xlnk_freebuf_ioctl(filp, code, args); ++ break; ++ case XLNK_IOCDMAREQUEST: ++ status = xlnk_dmarequest_ioctl(filp, code, args); ++ break; ++ case XLNK_IOCDMASUBMIT: ++ status = xlnk_dmasubmit_ioctl(filp, code, args); ++ break; ++ case XLNK_IOCDMAWAIT: ++ status = xlnk_dmawait_ioctl(filp, code, args); ++ break; ++ case XLNK_IOCDMARELEASE: ++ status = xlnk_dmarelease_ioctl(filp, code, args); ++ break; ++ case XLNK_IOCDEVREGISTER: ++ status = xlnk_devregister_ioctl(filp, code, args); ++ break; ++ case XLNK_IOCDMAREGISTER: ++ status = xlnk_dmaregister_ioctl(filp, code, args); ++ break; ++ case XLNK_IOCMCDMAREGISTER: ++ status = xlnk_mcdmaregister_ioctl(filp, code, args); ++ break; ++ case XLNK_IOCDEVUNREGISTER: ++ status = xlnk_devunregister_ioctl(filp, code, args); ++ break; ++ case XLNK_IOCGETEVENTSIZE: ++ status = xlnk_get_event_size(args); ++ break; ++ case XLNK_IOCCACHECTRL: ++ status = xlnk_cachecontrol_ioctl(filp, code, args); ++ break; ++ case XLNK_IOCDUMPEVENTS: ++ status = xlnk_dump_events(args); ++ break; ++ case XLNK_IOCSHUTDOWN: ++ status = xlnk_shutdown(args); ++ break; ++ case XLNK_IOCRECRES: /* recover resource */ ++ status = xlnk_recover_resource(args); ++ break; ++ } ++ ++ xlnk_record_event(XLNK_ET_KERNEL_LEAVE_IOCTL); ++ return status; ++} ++ ++static struct vm_operations_struct xlnk_vm_ops = { ++ .open = xlnk_vma_open, ++ .close = xlnk_vma_close, ++}; ++ ++/* This function maps kernel space memory to user space memory. */ ++static int xlnk_mmap(struct file *filp, struct vm_area_struct *vma) ++{ ++ ++ int bufid; ++ int status; ++ ++ bufid = vma->vm_pgoff >> (24 - PAGE_SHIFT); ++ ++ if (bufid == 0) ++ status = remap_pfn_range(vma, vma->vm_start, ++ virt_to_phys(xlnk_dev_buf) >> PAGE_SHIFT, ++ vma->vm_end - vma->vm_start, ++ vma->vm_page_prot); ++ else { ++ if (xlnk_bufcacheable[bufid] == 0) ++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); ++ ++ status = remap_pfn_range(vma, vma->vm_start, ++ xlnk_phyaddr[bufid] >> PAGE_SHIFT, ++ vma->vm_end - vma->vm_start, ++ vma->vm_page_prot); ++ } ++ if (status) ++ return -EAGAIN; ++ ++ xlnk_vma_open(vma); ++ vma->vm_ops = &xlnk_vm_ops; ++ vma->vm_private_data = xlnk_bufpool[bufid]; ++ ++ return 0; ++} ++ ++static void xlnk_vma_open(struct vm_area_struct *vma) ++{ ++ xlnk_dev_vmas++; ++} ++ ++static void xlnk_vma_close(struct vm_area_struct *vma) ++{ ++ xlnk_dev_vmas--; ++} ++ ++ ++#ifdef CONFIG_ARCH_ZYNQ ++ ++/* ++ * Xidane XLNK benchmark counter support ++ */ ++static u32 __iomem *bc_virt; ++ ++ ++/* Zynq global counter */ ++static const unsigned long bc_phyaddr = 0xF8F00200; ++static const unsigned long bc_to_cpu_shift = 1; ++static const unsigned long bc_csr_size = 16; ++static const unsigned long bc_ctr_offset = 2; ++static const unsigned long bc_ctr_start = 1; ++static const unsigned long bc_data_offset; ++ ++ ++static void xlnk_start_benchmark_counter(void) ++{ ++ bc_virt = ioremap(bc_phyaddr, bc_csr_size); ++ if (bc_virt) { ++ iowrite32(bc_ctr_start, bc_virt + bc_ctr_offset); ++ pr_info("xlnk: benchmark counter started\n"); ++ /* iounmap(bc_virt); */ ++ } ++} ++ ++#define XLNK_EVENT_TRACER_ENTRY_NUM 60000 ++static struct event_tracer { ++ u32 event_id; ++ u32 event_time; ++} xlnk_et[XLNK_EVENT_TRACER_ENTRY_NUM]; ++ ++static unsigned long xlnk_et_index; ++static unsigned long xlnk_et_numbers_to_dump; ++ ++void xlnk_record_event(u32 event_id) ++{ ++ if (xlnk_et_index >= XLNK_EVENT_TRACER_ENTRY_NUM) ++ return; ++ ++ xlnk_et[xlnk_et_index].event_id = event_id; ++ xlnk_et[xlnk_et_index].event_time = ioread32(bc_virt + ++ bc_data_offset) << ++ bc_to_cpu_shift; ++ xlnk_et_index++; ++} ++EXPORT_SYMBOL(xlnk_record_event); ++ ++static int xlnk_get_event_size(unsigned long args) ++{ ++ unsigned long __user *datap = (unsigned long __user *)args; ++ ++ /* take a snapshot of current index and only copy this ++ * size to user space thru xlnk_dump_events(), as the snapshot ++ * value determine the dynamically created user space event ++ * trace buffer size but the xlnk_et_index could keep going up ++ * with any xlnk_record_event() calls after this function ++ */ ++ xlnk_et_numbers_to_dump = xlnk_et_index; ++ put_user(xlnk_et_numbers_to_dump, datap); ++ return 0; ++} ++ ++static int xlnk_dump_events(unsigned long buf) ++{ ++ /* only dump the number of event traces reported thru ++ * xlnk_get_event_size() and ignore the rest to avoid ++ * buffer overflow issue ++ */ ++ copy_to_user((void __user *)buf, xlnk_et, ++ xlnk_et_numbers_to_dump * sizeof(struct event_tracer)); ++ ++ /* clear up event pool so it's ready to use again */ ++ xlnk_et_index = 0; ++ xlnk_et_numbers_to_dump = 0; ++ ++ return 0; ++} ++#endif ++ ++ ++static int xlnk_shutdown(unsigned long buf) ++{ ++ return 0; ++} ++ ++static int xlnk_recover_resource(unsigned long buf) ++{ ++ xlnk_free_all_buf(); ++#ifdef CONFIG_XILINX_DMA_APF ++ xdma_release_all_channels(); ++#endif ++ return 0; ++} ++ ++static int __init xlnk_init(void) ++{ ++ pr_info("%s driver initializing\n", DRIVER_NAME); ++ ++ xlnk_dev_buf = NULL; ++ xlnk_dev_size = 0; ++ xlnk_dev_vmas = 0; ++ xlnk_bufpool = NULL; ++ ++ platform_device_register(&xlnk_device); ++ ++ return platform_driver_register(&xlnk_driver); ++} ++ ++static void __exit xlnk_exit(void) ++{ ++ platform_driver_unregister(&xlnk_driver); ++} ++ ++/* APF driver initialization and de-initialization functions */ ++module_init(xlnk_init); ++module_exit(xlnk_exit); ++ ++MODULE_DESCRIPTION("Xilinx APF driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/staging/apf/xlnk.h b/drivers/staging/apf/xlnk.h +new file mode 100644 +index 0000000..e44fad7 +--- /dev/null ++++ b/drivers/staging/apf/xlnk.h +@@ -0,0 +1,116 @@ ++#ifndef _XLNK_OS_H ++#define _XLNK_OS_H ++ ++#include ++ ++#define XLNK_FLAG_COHERENT 0x00000001 ++#define XLNK_FLAG_KERNEL_BUFFER 0x00000002 ++#define XLNK_FLAG_DMAPOLLING 0x00000004 ++#define XLNK_FLAG_PHYSICAL_ADDR 0x00000100 ++#define XLNK_FLAG_VIRTUAL_ADDR 0x00000200 ++ ++#define CF_FLAG_CACHE_FLUSH_INVALIDATE 0x00000001 ++#define CF_FLAG_PHYSICALLY_CONTIGUOUS 0x00000002 ++#define CF_FLAG_DMAPOLLING 0x00000004 ++ ++extern void xlnk_record_event(u32 event_id); ++ ++ ++enum xlnk_dma_direction { ++ XLNK_DMA_BI = 0, ++ XLNK_DMA_TO_DEVICE = 1, ++ XLNK_DMA_FROM_DEVICE = 2, ++ XLNK_DMA_NONE = 3, ++}; ++ ++union xlnk_args { ++ struct { ++ unsigned int len; ++ unsigned int __user *idptr; ++ unsigned int __user *phyaddrptr; ++ unsigned int cacheable; ++ } allocbuf; ++ struct { ++ unsigned int id; ++ void *buf; ++ } freebuf; ++ struct { ++ char name[64]; /* max length of 64 */ ++ u32 dmachan; /* return value */ ++ unsigned int bd_space_phys_addr;/*for bd chain used by dmachan*/ ++ unsigned int bd_space_size; /* bd chain size in bytes */ ++ } dmarequest; ++#define XLNK_MAX_APPWORDS 5 ++ struct { ++ u32 dmachan; ++ void *buf; /* buffer base address */ ++ void *buf2; /* used to point src_buf in cdma case */ ++ unsigned int buf_offset; /* used on kernel allocated buffers */ ++ unsigned int len; ++ unsigned int bufflag; /* zero all the time so far */ ++ u32 sglist; /* ignored */ ++ unsigned int sgcnt; /* ignored */ ++ enum xlnk_dma_direction dmadir; ++ unsigned int nappwords_i; /* n appwords passed to BD */ ++ unsigned int appwords_i[XLNK_MAX_APPWORDS]; ++ unsigned int nappwords_o; /* n appwords passed from BD */ ++ /* appwords array we only accept 5 max */ ++ unsigned int flag; ++ u32 dmahandle; /* return value */ ++ unsigned int last_bd_index; /*index of last bd used by request*/ ++ } dmasubmit; ++ struct { ++ u32 dmahandle; ++ unsigned int nappwords; /* n appwords read from BD */ ++ unsigned int appwords[XLNK_MAX_APPWORDS]; ++ /* appwords array we only accept 5 max */ ++ } dmawait; ++ struct { ++ u32 dmachan; ++ } dmarelease; ++ struct { ++ unsigned long base; ++ unsigned int size; ++ unsigned int irqs[8]; ++ char name[32]; ++ unsigned int id; ++ } devregister; ++ struct { ++ unsigned int base; ++ } devunregister; ++ struct { ++ char name[32]; ++ unsigned int id; ++ unsigned long base; ++ unsigned int size; ++ unsigned int chan_num; ++ unsigned int chan0_dir; ++ unsigned int chan0_irq; ++ unsigned int chan0_poll_mode; ++ unsigned int chan0_include_dre; ++ unsigned int chan0_data_width; ++ unsigned int chan1_dir; ++ unsigned int chan1_irq; ++ unsigned int chan1_poll_mode; ++ unsigned int chan1_include_dre; ++ unsigned int chan1_data_width; ++ } dmaregister; ++ struct { ++ char name[32]; ++ unsigned int id; ++ unsigned long base; ++ unsigned int size; ++ unsigned int mm2s_chan_num; ++ unsigned int mm2s_chan_irq; ++ unsigned int s2mm_chan_num; ++ unsigned int s2mm_chan_irq; ++ } mcdmaregister; ++ struct { ++ void *phys_addr; ++ int size; ++ int action; ++ } cachecontrol; ++}; ++ ++ ++#endif +diff --git a/drivers/staging/video/axivdma/Kconfig b/drivers/staging/video/axivdma/Kconfig +new file mode 100644 +index 0000000..f3b401b +--- /dev/null ++++ b/drivers/staging/video/axivdma/Kconfig +@@ -0,0 +1,16 @@ ++menuconfig XILINX_VIDEO_IP ++ tristate "Xilinx Video IP components" ++ ---help--- ++ This adds support to include Xilinx Video IP components. ++ Xilinx video IP need few additional drivers which are not currently in Xilinx ++ main-stream kernel are added in this section. ++ Example includes : AXI VDMA client driver. ++ ++config XILINX_VDMA_WRAPPER ++ tristate "Video DMA Wrapper" ++ depends on XILINX_VIDEO_IP && XILINX_DMA_ENGINES ++ ---help--- ++ Enables Video DMA IP component.Uses Slave-DMA API of the DMA engine. ++ Provides user space application an interface to configure/control ++ Xilinx VDMA IP. ++ VDMA wrapper can be extened to supports other features exported by VDMA engine. +diff --git a/drivers/staging/video/axivdma/Makefile b/drivers/staging/video/axivdma/Makefile +new file mode 100644 +index 0000000..feee773 +--- /dev/null ++++ b/drivers/staging/video/axivdma/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_XILINX_VDMA_WRAPPER) += xvdma.o +diff --git a/drivers/staging/video/axivdma/xvdma.c b/drivers/staging/video/axivdma/xvdma.c +new file mode 100644 +index 0000000..e37a4ee +--- /dev/null ++++ b/drivers/staging/video/axivdma/xvdma.c +@@ -0,0 +1,440 @@ ++/* ++ * xvdma.c ++ * ++ * Xilinx Video DMA Driver ++ * ++ * Author: Xilinx Inc. ++ * ++ * 2002-2006 (c)Xilinx Inc. This file is licensed under ++ * the terms of the GNU General Public License version 2. This program ++ * is licensed "as is" without any warranty of any kind, whether express ++ * or implied. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "xvdma.h" ++ ++#define XVDMA_IOCTL_BASE 'W' ++#define XVDMA_GET_NUM_DEVICES _IO(XVDMA_IOCTL_BASE, 0) ++#define XVDMA_GET_DEV_INFO _IO(XVDMA_IOCTL_BASE, 1) ++#define XVDMA_DEVICE_CONTROL _IO(XVDMA_IOCTL_BASE, 2) ++#define XVDMA_PREP_BUF _IO(XVDMA_IOCTL_BASE, 3) ++#define XVDMA_START_TRANSFER _IO(XVDMA_IOCTL_BASE, 4) ++#define XVDMA_STOP_TRANSFER _IO(XVDMA_IOCTL_BASE, 5) ++ ++#define XVDMA_DEVICE_ID_SHIFT 28 ++ ++ ++struct xvdma_dev *xvdma_dev_info[MAX_DEVICES + 1]; ++static u64 dma_mask = 0xFFFFFFFFUL; ++struct chan_buf chan_buf[MAX_FRAMES]; ++u32 num_devices; ++struct completion cmp; ++ ++void xvdma_get_dev_info(u32 device_id, struct xvdma_dev *dev) ++{ ++ int i; ++ ++ for (i = 0; i < MAX_DEVICES; i++) { ++ if (xvdma_dev_info[i]->device_id == device_id) ++ break; ++ } ++ memcpy(dev, xvdma_dev_info[i], sizeof(struct xvdma_dev)); ++} ++ ++/* ++ * This function is called when an application opens handle to the ++ * bridge driver. ++ */ ++static int xvdma_open(struct inode *ip, struct file *filp) ++{ ++ return 0; ++} ++ ++static int xvdma_release(struct inode *ip, struct file *filp) ++{ ++ return 0; ++} ++ ++ ++static long xvdma_ioctl(struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ struct xvdma_dev xvdma_dev; ++ struct xvdma_chan_cfg chan_cfg; ++ struct xvdma_buf_info buf_info; ++ struct xvdma_transfer tx_info; ++ u32 devices, chan; ++ ++ switch (cmd) { ++ case XVDMA_GET_NUM_DEVICES: ++ { ++ if (copy_from_user((void *)&devices, ++ (const void __user *)arg, ++ sizeof(u32))) ++ return -EFAULT; ++ ++ devices = num_devices; ++ if (copy_to_user((u32 *)arg, ++ &devices, sizeof(u32))) ++ return -EFAULT; ++ break; ++ } ++ case XVDMA_GET_DEV_INFO: ++ { ++ if (copy_from_user((void *)&xvdma_dev, ++ (const void __user *)arg, ++ sizeof(struct xvdma_dev))) ++ return -EFAULT; ++ ++ xvdma_get_dev_info(xvdma_dev.device_id, &xvdma_dev); ++ ++ if (copy_to_user((struct xvdma_dev *)arg, ++ &xvdma_dev, sizeof(struct xvdma_dev))) ++ return -EFAULT; ++ break; ++ } ++ case XVDMA_DEVICE_CONTROL: ++ { ++ if (copy_from_user((void *)&chan_cfg, ++ (const void __user *)arg, ++ sizeof(struct xvdma_chan_cfg))) ++ return -EFAULT; ++ ++ xvdma_device_control(&chan_cfg); ++ break; ++ } ++ case XVDMA_PREP_BUF: ++ { ++ if (copy_from_user((void *)&buf_info, ++ (const void __user *)arg, ++ sizeof(struct xvdma_buf_info))) ++ return -EFAULT; ++ xvdma_prep_slave_sg(&buf_info); ++ break; ++ } ++ case XVDMA_START_TRANSFER: ++ { ++ if (copy_from_user((void *)&tx_info, ++ (const void __user *)arg, ++ sizeof(struct xvdma_transfer))) ++ return -EFAULT; ++ ++ xvdma_start_transfer(&tx_info); ++ break; ++ } ++ case XVDMA_STOP_TRANSFER: ++ { ++ if (copy_from_user((void *)&chan, ++ (const void __user *)arg, ++ sizeof(u32))) ++ return -EFAULT; ++ ++ xvdma_stop_transfer((struct dma_chan *)chan); ++ break; ++ } ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static bool xvdma_filter(struct dma_chan *chan, void *param) ++{ ++ if (*((int *)chan->private) == *(int *)param) ++ return true; ++ ++ ++ return false; ++} ++ ++void vdma_sync_callback(void *completion) ++{ ++ complete(completion); ++} ++ ++void xvdma_stop_transfer(struct dma_chan *chan) ++{ ++ struct dma_device *chan_dev; ++ ++ if (chan) { ++ chan_dev = chan->device; ++ chan_dev->device_control(chan, DMA_TERMINATE_ALL, ++ (unsigned long)NULL); ++ } ++} ++ ++void xvdma_start_transfer(struct xvdma_transfer *tx_info) ++{ ++ unsigned long tmo = msecs_to_jiffies(3000); ++ ++ init_completion(&cmp); ++ if (tx_info->chan) ++ dma_async_issue_pending((struct dma_chan *)tx_info->chan); ++ ++ if (tx_info->wait) { ++ tmo = wait_for_completion_timeout(&cmp, tmo); ++ if (0 == tmo) ++ pr_err("Timeout has occured...\n"); ++ } ++} ++ ++void xvdma_prep_slave_sg(struct xvdma_buf_info *buf_info) ++{ ++ struct dma_chan *chan; ++ struct dma_device *chan_dev; ++ struct dma_async_tx_descriptor *chan_desc; ++ struct scatterlist chansg[MAX_FRAMES]; ++ dma_addr_t dma_srcs[MAX_FRAMES]; ++ u8 **buf = NULL; ++ int buf_size; ++ u32 flags = 0; ++ int i; ++ u32 device_id; ++ u32 frm_cnt = buf_info->frm_cnt; ++ ++ buf_size = buf_info->buf_size; ++ chan = (struct dma_chan *) buf_info->chan; ++ device_id = buf_info->device_id; ++ ++ if (chan) { ++ flags = DMA_CTRL_ACK | DMA_COMPL_SKIP_DEST_UNMAP ++ | DMA_PREP_INTERRUPT; ++ ++ if (buf_info->fixed_buffer) { ++ chan_dev = chan->device; ++ sg_init_table(chansg, frm_cnt); ++ for (i = 0; i < frm_cnt; i++) { ++ if (!buf_info->shared_buffer) { ++ dma_srcs[i] = ++ buf_info->addr_base + i * buf_size; ++ chan_buf[device_id].dma_addr[i] = ++ dma_srcs[i]; ++ } ++ sg_dma_address(&chansg[i]) = ++ chan_buf[device_id].dma_addr[i]; ++ sg_dma_len(&chansg[i]) = buf_size; ++ } ++ } else { ++ if (!buf_info->shared_buffer) { ++ buf = kcalloc(frm_cnt + 1, sizeof(u8 *), ++ GFP_KERNEL); ++ if (!buf) ++ pr_err("Buf failed\n"); ++ ++ for (i = 0; i < frm_cnt; i++) { ++ buf[i] = kmalloc(buf_size, GFP_KERNEL); ++ if (!buf[i]) ++ pr_err("Buf[%d] failed\n", i); ++ } ++ buf[i] = NULL; ++ } ++ ++ chan_dev = chan->device; ++ sg_init_table(chansg, frm_cnt); ++ for (i = 0; i < frm_cnt; i++) { ++ if (!buf_info->shared_buffer) { ++ dma_srcs[i] = dma_map_single( ++ chan_dev->dev, buf[i], buf_size, ++ buf_info->mem_type); ++ chan_buf[device_id].dma_addr[i] = ++ dma_srcs[i]; ++ } ++ sg_dma_address(&chansg[i]) = ++ chan_buf[device_id].dma_addr[i]; ++ sg_dma_len(&chansg[i]) = buf_size; ++ } ++ } ++ chan_desc = chan_dev->device_prep_slave_sg(chan, chansg, ++ frm_cnt, buf_info->direction, flags, NULL); ++ if (buf_info->callback) { ++ chan_desc->callback = vdma_sync_callback; ++ chan_desc->callback_param = &cmp; ++ } ++ chan_desc->tx_submit(chan_desc); ++ } ++} ++ ++void xvdma_device_control(struct xvdma_chan_cfg *chan_cfg) ++{ ++ struct dma_chan *chan; ++ struct dma_device *chan_dev; ++ ++ chan = (struct dma_chan *) chan_cfg->chan; ++ ++ if (chan) { ++ chan_dev = chan->device; ++ chan_dev->device_control(chan, DMA_SLAVE_CONFIG, ++ (unsigned long)&chan_cfg->config); ++ } ++} ++ ++void xvdma_add_dev_info(struct dma_chan *tx_chan, ++ struct dma_chan *rx_chan) ++{ ++ static u32 i ; ++ ++ xvdma_dev_info[i] = (struct xvdma_dev *) ++ kzalloc(sizeof(struct xvdma_dev), GFP_KERNEL); ++ ++ xvdma_dev_info[i]->tx_chan = (u32) tx_chan; ++ xvdma_dev_info[i]->rx_chan = (u32) rx_chan; ++ xvdma_dev_info[i]->device_id = i; ++ num_devices++; ++ i++; ++} ++ ++void xvdma_scan_channels(void) ++{ ++ dma_cap_mask_t mask; ++ u32 match_tx, match_rx; ++ struct dma_chan *tx_chan, *rx_chan; ++ u32 device_id = 0; ++ ++ dma_cap_zero(mask); ++ dma_cap_set(DMA_SLAVE | DMA_PRIVATE, mask); ++ ++ for (;;) { ++ match_tx = (DMA_TO_DEVICE & 0xFF) | XILINX_DMA_IP_VDMA | ++ (device_id << XVDMA_DEVICE_ID_SHIFT); ++ tx_chan = dma_request_channel(mask, xvdma_filter, ++ (void *)&match_tx); ++ match_rx = (DMA_FROM_DEVICE & 0xFF) | XILINX_DMA_IP_VDMA | ++ (device_id << XVDMA_DEVICE_ID_SHIFT); ++ rx_chan = dma_request_channel(mask, xvdma_filter, ++ (void *)&match_rx); ++ ++ if (!tx_chan && !rx_chan) ++ break; ++ else ++ xvdma_add_dev_info(tx_chan, rx_chan); ++ ++ device_id++; ++ } ++} ++ ++void xvdma_release_channels(void) ++{ ++ int i; ++ ++ for (i = 0; i < MAX_DEVICES; i++) { ++ if (xvdma_dev_info[i]->tx_chan) ++ dma_release_channel((struct dma_chan *) ++ xvdma_dev_info[i]->tx_chan); ++ if (xvdma_dev_info[i]->rx_chan) ++ dma_release_channel((struct dma_chan *) ++ xvdma_dev_info[i]->rx_chan); ++ } ++} ++ ++static const struct file_operations xvdma_fops = { ++ .owner = THIS_MODULE, ++ .open = xvdma_open, ++ .unlocked_ioctl = xvdma_ioctl, ++ .release = xvdma_release, ++}; ++ ++static int xvdma_probe(struct platform_device *pdev) ++{ ++ dev_t devt; ++ struct xvdma_drvdata *drvdata = NULL; ++ struct device *dev = &pdev->dev; ++ int retval; ++ ++ devt = MKDEV(XVDMA_MAJOR, XVDMA_MINOR); ++ ++ drvdata = kzalloc(sizeof(struct xvdma_drvdata), GFP_KERNEL); ++ if (!drvdata) { ++ dev_err(dev, "Couldn't allocate device private record\n"); ++ retval = -ENOMEM; ++ goto failed0; ++ } ++ dev_set_drvdata(dev, (void *)drvdata); ++ ++ drvdata->dev = dev; ++ drvdata->devt = devt; ++ ++ cdev_init(&drvdata->cdev, &xvdma_fops); ++ drvdata->cdev.owner = THIS_MODULE; ++ retval = cdev_add(&drvdata->cdev, devt, 1); ++ if (retval) { ++ dev_err(dev, "cdev_add() failed\n"); ++ goto failed1; ++ } ++ ++ xvdma_scan_channels(); ++ dev_info(dev, "Xilinx VDMA probe successful\n"); ++ dev_info(dev, "Devices Scanned %d\n", num_devices); ++ return 0; ++ ++failed1: ++ kfree(drvdata); ++failed0: ++ return retval; ++} ++ ++static int xvdma_remove(struct platform_device *op) ++{ ++ struct xvdma_drvdata *drvdata; ++ struct device *dev = &op->dev; ++ ++ drvdata = (struct xvdma_drvdata *)dev_get_drvdata(dev); ++ if (!drvdata) ++ return 0; ++ ++ xvdma_release_channels(); ++ cdev_del(&drvdata->cdev); ++ kfree(drvdata); ++ dev_set_drvdata(dev, NULL); ++ return 0; ++} ++ ++static struct platform_driver xvdma_driver = { ++ .driver = { ++ .name = DRIVER_NAME, ++ }, ++ .probe = xvdma_probe, ++ .remove = xvdma_remove, ++ .suspend = XVDMA_SUSPEND, ++ .resume = XVDMA_RESUME, ++}; ++ ++static struct platform_device xvdma_device = { ++ .name = "xvdma", ++ .id = 0, ++ .dev = { ++ .platform_data = NULL, ++ .dma_mask = &dma_mask, ++ .coherent_dma_mask = 0xFFFFFFFF, ++ }, ++ .resource = NULL, ++ .num_resources = 0, ++}; ++ ++static int __init xvdma_init(void) ++{ ++ platform_device_register(&xvdma_device); ++ ++ return platform_driver_register(&xvdma_driver); ++} ++ ++static void __exit xvdma_exit(void) ++{ ++ platform_driver_unregister(&xvdma_driver); ++} ++ ++late_initcall(xvdma_init); ++module_exit(xvdma_exit); +diff --git a/drivers/staging/video/axivdma/xvdma.h b/drivers/staging/video/axivdma/xvdma.h +new file mode 100644 +index 0000000..c4ed882 +--- /dev/null ++++ b/drivers/staging/video/axivdma/xvdma.h +@@ -0,0 +1,71 @@ ++/* ++xvdma.h ++Wrapper client driver for xilinx VDMA Engine. ++ ++*/ ++#ifndef __XVDMA_H ++#define __XVDMA_H ++ ++#include ++ ++#define DRIVER_NAME "xvdma" ++#define XVDMA_SUSPEND NULL ++#define XVDMA_RESUME NULL ++ ++#define XVDMA_MAJOR 10 ++#define XVDMA_MINOR 224 ++ ++#define MAX_DEVICES 4 ++#define MAX_FRAMES 5 ++#define DMA_CHAN_RESET 10 ++ ++ ++ ++ ++struct xvdma_drvdata { ++ struct device *dev; ++ struct cdev cdev; /* Char device structure */ ++ dev_t devt; ++}; ++ ++struct xvdma_dev { ++ ++ u32 tx_chan; ++ u32 rx_chan; ++ u32 device_id; ++}; ++ ++struct xvdma_chan_cfg { ++ struct xilinx_vdma_config config; ++ u32 chan; ++}; ++ ++struct xvdma_buf_info { ++ u32 chan; ++ u32 device_id; ++ u32 direction; ++ u32 shared_buffer; ++ u32 mem_type; ++ u32 fixed_buffer; ++ u32 buf_size; ++ u32 addr_base; ++ u32 frm_cnt; ++ u32 callback; ++}; ++ ++struct xvdma_transfer { ++ u32 chan; ++ u32 wait; ++}; ++ ++struct chan_buf { ++ u32 device_id; ++ dma_addr_t dma_addr[MAX_FRAMES]; ++}; ++ ++void xvdma_device_control(struct xvdma_chan_cfg *); ++void xvdma_prep_slave_sg(struct xvdma_buf_info *); ++void xvdma_start_transfer(struct xvdma_transfer *); ++void xvdma_stop_transfer(struct dma_chan *); ++ ++#endif +diff --git a/drivers/staging/video/imageon/Kconfig b/drivers/staging/video/imageon/Kconfig +new file mode 100644 +index 0000000..6bafe68 +--- /dev/null ++++ b/drivers/staging/video/imageon/Kconfig +@@ -0,0 +1,11 @@ ++config VIDEO_IMAGEON ++ tristate "Imageon card RX support" ++ depends on MEDIA_SUPPORT && VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API ++ select I2C_ALGOBIT ++ select VIDEO_ADV7604 ++ ---help--- ++ To compile this driver as a module, choose M here: the ++ module will be called imageon-rx. ++ Imageon driver initializes/configures ADV7611 (v4l2 sub device) ++ Configured as a loadable module. ++ It requests EDID using mdev (user-space helper app). +diff --git a/drivers/staging/video/imageon/Makefile b/drivers/staging/video/imageon/Makefile +new file mode 100644 +index 0000000..81ae78b +--- /dev/null ++++ b/drivers/staging/video/imageon/Makefile +@@ -0,0 +1,3 @@ ++imageon-rx-objs := imageon-rx-driver.o ++ ++obj-$(CONFIG_VIDEO_IMAGEON) += imageon-rx.o +diff --git a/drivers/staging/video/imageon/imageon-rx-driver.c b/drivers/staging/video/imageon/imageon-rx-driver.c +new file mode 100644 +index 0000000..63d9d18 +--- /dev/null ++++ b/drivers/staging/video/imageon/imageon-rx-driver.c +@@ -0,0 +1,251 @@ ++/* ++ * Driver for the IMAGEON-FMC board ++ * ++ * Copyright 2012-2013 Analog Devices Inc. ++ * Author: Lars-Peter Clausen ++ * ++ * based on cobalt-driver.c ++ * ++ * Licensed under the GPL-2. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "imageon-rx-driver.h" ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++/* EDID for ADV7611 HDMI receiver */ ++#define EDID_SIZE 256 ++static u8 edid_data[EDID_SIZE] = { ++ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, ++ 0x06, 0xD4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x16, 0x01, 0x03, 0x81, 0x46, 0x27, 0x78, ++ 0x0A, 0x32, 0x30, 0xA1, 0x54, 0x52, 0x9E, 0x26, ++ 0x0A, 0x49, 0x4B, 0xA3, 0x08, 0x00, 0x81, 0xC0, ++ 0x81, 0x00, 0x81, 0x0F, 0x81, 0x40, 0x81, 0x80, ++ 0x95, 0x00, 0xB3, 0x00, 0x01, 0x01, 0x02, 0x3A, ++ 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, 0x2C, ++ 0x45, 0x00, 0xC4, 0x8E, 0x21, 0x00, 0x00, 0x1E, ++ 0xA9, 0x1A, 0x00, 0xA0, 0x50, 0x00, 0x16, 0x30, ++ 0x30, 0x20, 0x37, 0x00, 0xC4, 0x8E, 0x21, 0x00, ++ 0x00, 0x1A, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x46, ++ 0x4D, 0x43, 0x2D, 0x49, 0x4D, 0x41, 0x47, 0x45, ++ 0x4F, 0x4E, 0x0A, 0x20, 0x00, 0x00, 0x00, 0xFD, ++ 0x00, 0x38, 0x4B, 0x20, 0x44, 0x11, 0x00, 0x0A, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0x54, ++ 0x02, 0x03, 0x1F, 0x71, 0x4B, 0x90, 0x03, 0x04, ++ 0x05, 0x12, 0x13, 0x14, 0x1F, 0x20, 0x07, 0x16, ++ 0x26, 0x15, 0x07, 0x50, 0x09, 0x07, 0x01, 0x67, ++ 0x03, 0x0C, 0x00, 0x10, 0x00, 0x00, 0x1E, 0x01, ++ 0x1D, 0x00, 0x72, 0x51, 0xD0, 0x1E, 0x20, 0x6E, ++ 0x28, 0x55, 0x00, 0xC4, 0x8E, 0x21, 0x00, 0x00, ++ 0x1E, 0x01, 0x1D, 0x80, 0x18, 0x71, 0x1C, 0x16, ++ 0x20, 0x58, 0x2C, 0x25, 0x00, 0xC4, 0x8E, 0x21, ++ 0x00, 0x00, 0x9E, 0x8C, 0x0A, 0xD0, 0x8A, 0x20, ++ 0xE0, 0x2D, 0x10, 0x10, 0x3E, 0x96, 0x00, 0xC4, ++ 0x8E, 0x21, 0x00, 0x00, 0x18, 0x01, 0x1D, 0x80, ++ 0x3E, 0x73, 0x38, 0x2D, 0x40, 0x7E, 0x2C, 0x45, ++ 0x80, 0xC4, 0x8E, 0x21, 0x00, 0x00, 0x1E, 0x1A, ++ 0x36, 0x80, 0xA0, 0x70, 0x38, 0x1F, 0x40, 0x30, ++ 0x20, 0x25, 0x00, 0xC4, 0x8E, 0x21, 0x00, 0x00, ++ 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ++}; ++ ++static void imageon_rx_notify(struct v4l2_subdev *sd, unsigned int notification, ++ void *arg) ++{ ++ /* pr_err("%s\n",__func__); */ ++ ++ struct imageon_rx *imageon_rx = to_imageon_rx(sd->v4l2_dev); ++ long hotplug = (long)arg; ++ ++ switch (notification) { ++ case ADV7604_HOTPLUG: ++ gpio_set_value_cansleep(imageon_rx->hotplug_gpio, hotplug); ++ break; ++ default: ++ break; ++ } ++} ++ ++static int imageon_rx_subdevs_init(struct imageon_rx *imageon_rx) ++{ ++ static struct adv7604_platform_data adv7611_pdata = { ++ .disable_pwrdnb = 1, ++ .op_ch_sel = ADV7604_OP_CH_SEL_RGB, ++ .blank_data = 1, ++ .op_656_range = 1, ++ .rgb_out = 0, ++ .alt_data_sat = 1, ++ .op_format_sel = ADV7604_OP_FORMAT_SEL_SDR_ITU656_16, ++ .int1_config = ADV7604_INT1_CONFIG_OPEN_DRAIN, ++ .connector_hdmi = 1, ++ .insert_av_codes = 1, ++ .i2c_cec = 0x40, ++ .i2c_infoframe = 0x3e, ++ .i2c_afe = 0x26, ++ .i2c_repeater = 0x32, ++ .i2c_edid = 0x36, ++ .i2c_hdmi = 0x34, ++ .i2c_cp = 0x22, ++ }; ++ static struct i2c_board_info adv7611_info = { ++ .type = "adv7611", ++ .addr = 0x4c, ++ .platform_data = &adv7611_pdata, ++ }; ++ struct v4l2_subdev_edid edid = { ++ .pad = 0, ++ .start_block = 0, ++ .blocks = 2, ++ .edid = imageon_rx->edid_data, ++ }; ++ ++ struct imageon_rx_stream *s = &imageon_rx->stream; ++ ++ s->sd_adv7611 = v4l2_i2c_new_subdev_board(&imageon_rx->v4l2_dev, ++ s->i2c_adap, &adv7611_info, NULL); ++ if (!s->sd_adv7611) ++ return -ENODEV; ++ ++ v4l2_subdev_call(s->sd_adv7611, pad, set_edid, &edid); ++ return v4l2_subdev_call(s->sd_adv7611, video, ++ s_routing, ADV7604_MODE_HDMI, 0, 0); ++} ++ ++static int imageon_rx_load_edid(struct platform_device *pdev, ++ struct imageon_rx *imageon_rx) ++{ ++ const struct firmware *fw; ++ int ret; ++ ++ ret = request_firmware(&fw, "adv7611_edid.bin", &pdev->dev); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "Failed to load firmware: %d\n", ret); ++ /*Using default EDID setting in case of failure */ ++ dev_err(&pdev->dev, "Loading default EDID setting\n"); ++ /*Copy EDID data */ ++ memcpy(imageon_rx->edid_data, edid_data, EDID_SIZE); ++ } else { ++ ++ if (fw->size > 256) { ++ dev_err(&pdev->dev, "EDID firmware data too large.\n"); ++ release_firmware(fw); ++ return -EINVAL; ++ } ++ ++ memcpy(imageon_rx->edid_data, fw->data, fw->size); ++ ++ release_firmware(fw); ++ } ++ ++ return 0; ++} ++ ++static int imageon_rx_probe(struct platform_device *pdev) ++{ ++ struct device_node *of_node; ++ struct i2c_adapter *adap; ++ struct imageon_rx *imageon_rx; ++ int ret; ++ ++ of_node = of_parse_phandle(pdev->dev.of_node, "slave_adapter", 0); ++ if (!of_node) ++ return -ENXIO; ++ ++ adap = of_find_i2c_adapter_by_node(of_node); ++ of_node_put(of_node); ++ if (!adap) ++ return -EPROBE_DEFER; ++ ++ imageon_rx = ++ devm_kzalloc(&pdev->dev, sizeof(struct imageon_rx), GFP_KERNEL); ++ if (imageon_rx == NULL) { ++ dev_err(&pdev->dev, "Failed to allocate device\n"); ++ ret = -ENOMEM; ++ goto err_i2c_put_adapter; ++ } ++ ++ imageon_rx->hotplug_gpio = ++ of_get_named_gpio(pdev->dev.of_node, "hpd-gpio", 0); ++ if (!gpio_is_valid(imageon_rx->hotplug_gpio)) ++ return imageon_rx->hotplug_gpio; ++ ++ ++ ret = devm_gpio_request_one(&pdev->dev, ++ imageon_rx->hotplug_gpio, GPIOF_OUT_INIT_LOW, "HPD"); ++ if (ret < 0) ++ return ret; ++ imageon_rx->stream.i2c_adap = adap; ++ ++ ++ ret = imageon_rx_load_edid(pdev, imageon_rx); ++ if (ret) ++ goto err_i2c_put_adapter; ++ ++ ret = v4l2_device_register(&pdev->dev, &imageon_rx->v4l2_dev); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to register card: %d\n", ret); ++ goto err_device_unregister; ++ } ++ snprintf(imageon_rx->v4l2_dev.name, sizeof(imageon_rx->v4l2_dev.name), ++ "imageon_rx"); ++ ++ imageon_rx->v4l2_dev.notify = imageon_rx_notify; ++ ++ ret = imageon_rx_subdevs_init(imageon_rx); ++ if (ret) ++ goto err_device_unregister; ++ ++ ret = v4l2_device_register_subdev_nodes(&imageon_rx->v4l2_dev); ++ if (ret) ++ goto err_device_unregister; ++ ++ video_set_drvdata(&imageon_rx->stream.vdev, imageon_rx); ++ ++ return 0; ++ ++err_device_unregister: ++ v4l2_device_unregister(&imageon_rx->v4l2_dev); ++err_i2c_put_adapter: ++ i2c_put_adapter(adap); ++ return ret; ++} ++ ++static int imageon_rx_remove(struct platform_device *pdev) ++{ ++ struct imageon_rx *imageon_rx = platform_get_drvdata(pdev); ++ ++ v4l2_device_unregister(&imageon_rx->v4l2_dev); ++ i2c_put_adapter(imageon_rx->stream.i2c_adap); ++ ++ return 0; ++} ++ ++static const struct of_device_id imageon_rx_of_match[] = { ++ { .compatible = "xlnx,imageon-rx", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, imageon_rx_of_match); ++ ++static struct platform_driver imageon_rx_driver = { ++ .driver = { ++ .name = "imageon-rx", ++ .owner = THIS_MODULE, ++ .of_match_table = imageon_rx_of_match, ++ }, ++ .probe = imageon_rx_probe, ++ .remove = imageon_rx_remove, ++}; ++module_platform_driver(imageon_rx_driver); +diff --git a/drivers/staging/video/imageon/imageon-rx-driver.h b/drivers/staging/video/imageon/imageon-rx-driver.h +new file mode 100644 +index 0000000..7c40a06 +--- /dev/null ++++ b/drivers/staging/video/imageon/imageon-rx-driver.h +@@ -0,0 +1,109 @@ ++/* ++ * imageon_rx driver internal defines and structures ++ * ++ * Derived from cx18-driver.h ++ * ++ * Copyright 2011 Tandberg Telecom AS. All rights reserved. ++ * ++ * This program is free software; you may redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS ++ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ++ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. ++ */ ++ ++#ifndef IMAGEON_RX_DRIVER_H ++#define IMAGEON_RX_DRIVER_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++struct imageon_rx_stream { ++ struct video_device vdev; ++ struct media_pad pad; ++ struct vb2_queue q; ++ struct i2c_adapter *i2c_adap; ++ struct v4l2_subdev *sd_adv7611; ++ struct mutex lock; ++ spinlock_t spinlock; ++ u32 input; ++ u32 width, height, bpp, pack_fmt; ++ u32 stride; ++ ++ struct dma_chan *chan; ++ struct xilinx_vdma_config dma_config; ++ ++ struct list_head queued_buffers; ++}; ++ ++/* Struct to hold info about imageon_rx cards */ ++struct imageon_rx { ++ struct v4l2_device v4l2_dev; ++ struct vb2_alloc_ctx *alloc_ctx; ++ ++ /* device nodes */ ++ struct media_device mdev; ++ struct imageon_rx_stream stream; ++ ++ int hotplug_gpio; ++ ++ void __iomem *base; ++ ++ u8 edid_data[256]; ++}; ++ ++static inline struct imageon_rx *to_imageon_rx(struct v4l2_device *v4l2_dev) ++{ ++ return container_of(v4l2_dev, struct imageon_rx, v4l2_dev); ++} ++ ++static inline struct imageon_rx_stream ++ *imageon_rx_file_to_stream(struct file *file) ++{ ++ struct imageon_rx *imageon_rx = video_drvdata(file); ++ return &imageon_rx->stream; ++} ++ ++static inline struct imageon_rx *imageon_rx_stream_to_imageon_rx( ++ struct imageon_rx_stream *s) ++{ ++ return container_of(s, struct imageon_rx, stream); ++} ++ ++int imageon_rx_nodes_register(struct imageon_rx *imageon_rx); ++ ++#define IMAGEON_RX_BYTES_PER_PIXEL_YUYV 4 ++#define IMAGEON_RX_BYTES_PER_PIXEL_RGB32 4 ++ ++enum { ++ IMAGEON_RX_VID_PACK_FMT_RGB32, ++/* ++ IMAGEON_RX_VID_PACK_FMT_YUYV,*/ ++}; ++ ++#endif +diff --git a/drivers/staging/zsmalloc/Kconfig b/drivers/staging/zsmalloc/Kconfig +index 7fab032..9084565 100644 +--- a/drivers/staging/zsmalloc/Kconfig ++++ b/drivers/staging/zsmalloc/Kconfig +@@ -1,5 +1,5 @@ + config ZSMALLOC +- bool "Memory allocator for compressed pages" ++ tristate "Memory allocator for compressed pages" + default n + help + zsmalloc is a slab-based memory allocator designed to store +diff --git a/drivers/staging/zsmalloc/zsmalloc-main.c b/drivers/staging/zsmalloc/zsmalloc-main.c +index 851a2ff..223c736 100644 +--- a/drivers/staging/zsmalloc/zsmalloc-main.c ++++ b/drivers/staging/zsmalloc/zsmalloc-main.c +@@ -657,8 +657,11 @@ static inline void __zs_unmap_object(struct mapping_area *area, + struct page *pages[2], int off, int size) + { + unsigned long addr = (unsigned long)area->vm_addr; ++ unsigned long end = addr + (PAGE_SIZE * 2); + +- unmap_kernel_range(addr, PAGE_SIZE * 2); ++ flush_cache_vunmap(addr, end); ++ unmap_kernel_range_noflush(addr, PAGE_SIZE * 2); ++ flush_tlb_kernel_range(addr, end); + } + + #else /* USE_PGTABLE_MAPPING */ +diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c +index c830b60..ac35c90 100644 +--- a/drivers/tty/pty.c ++++ b/drivers/tty/pty.c +@@ -675,9 +675,6 @@ static int ptmx_open(struct inode *inode, struct file *filp) + + nonseekable_open(inode, filp); + +- /* We refuse fsnotify events on ptmx, since it's a shared resource */ +- filp->f_mode |= FMODE_NONOTIFY; +- + retval = tty_alloc_file(filp); + if (retval) + return retval; +diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c +index a9e4be7..8318925 100644 +--- a/drivers/tty/serial/pch_uart.c ++++ b/drivers/tty/serial/pch_uart.c +@@ -214,7 +214,6 @@ enum { + #define FRI2_64_UARTCLK 64000000 /* 64.0000 MHz */ + #define FRI2_48_UARTCLK 48000000 /* 48.0000 MHz */ + #define NTC1_UARTCLK 64000000 /* 64.0000 MHz */ +-#define MINNOW_UARTCLK 50000000 /* 50.0000 MHz */ + + struct pch_uart_buffer { + unsigned char *buf; +@@ -396,10 +395,6 @@ static int pch_uart_get_uartclk(void) + strstr(cmp, "nanoETXexpress-TT"))) + return NTC1_UARTCLK; + +- cmp = dmi_get_system_info(DMI_BOARD_NAME); +- if (cmp && strstr(cmp, "MinnowBoard")) +- return MINNOW_UARTCLK; +- + return DEFAULT_UARTCLK; + } + +diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c +index 4293a3e..2c7230a 100644 +--- a/drivers/tty/serial/serial_core.c ++++ b/drivers/tty/serial/serial_core.c +@@ -1940,8 +1940,6 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport) + mutex_unlock(&port->mutex); + return 0; + } +- put_device(tty_dev); +- + if (console_suspend_enabled || !uart_console(uport)) + uport->suspended = 1; + +@@ -2007,11 +2005,9 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) + disable_irq_wake(uport->irq); + uport->irq_wake = 0; + } +- put_device(tty_dev); + mutex_unlock(&port->mutex); + return 0; + } +- put_device(tty_dev); + uport->suspended = 0; + + /* +diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c +index 7d06a53..2ee1dba 100644 +--- a/drivers/tty/serial/xilinx_uartps.c ++++ b/drivers/tty/serial/xilinx_uartps.c +@@ -220,7 +220,7 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id) + + /* drop byte with parity error if IGNPAR specified */ + if (isrstatus & port->ignore_status_mask & XUARTPS_IXR_PARITY) +- isrstatus &= ~(XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT); ++ isrstatus &= ~XUARTPS_IXR_TOUT; + + isrstatus &= port->read_status_mask; + isrstatus &= ~port->ignore_status_mask; +@@ -430,11 +430,16 @@ static unsigned int xuartps_set_baud_rate(struct uart_port *port, + static int xuartps_clk_notifier_cb(struct notifier_block *nb, + unsigned long event, void *data) + { +- struct clk_notifier_data *ndata = data; ++ u32 ctrl_reg; + struct uart_port *port; ++ int locked = 0; ++ struct clk_notifier_data *ndata = data; ++ unsigned long flags = 0; + struct xuartps *xuartps = to_xuartps(nb); + + port = xuartps->port; ++ if (port->suspended) ++ return NOTIFY_OK; + + switch (event) { + case PRE_RATE_CHANGE: +@@ -448,41 +453,49 @@ static int xuartps_clk_notifier_cb(struct notifier_block *nb, + if (!xuartps_calc_baud_divs(ndata->new_rate, xuartps->baud, + &bdiv, &cd, &div8)) + return NOTIFY_BAD; ++ ++ spin_lock_irqsave(&xuartps->port->lock, flags); ++ ++ /* Disable the TX and RX to set baud rate */ ++ xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) | ++ (XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS), ++ XUARTPS_CR_OFFSET); ++ ++ spin_unlock_irqrestore(&xuartps->port->lock, flags); ++ + return NOTIFY_OK; + } + case POST_RATE_CHANGE: + /* Set clk dividers to generate correct baud with new clock + * frequency. */ +- { +- u32 ctrl_reg; +- unsigned long flags = 0; + + spin_lock_irqsave(&xuartps->port->lock, flags); + ++ locked = 1; + port->uartclk = ndata->new_rate; +- /* Empty the receive FIFO 1st before making changes */ +- while ((xuartps_readl(XUARTPS_SR_OFFSET) & +- XUARTPS_SR_RXEMPTY) != XUARTPS_SR_RXEMPTY) +- xuartps_readl(XUARTPS_FIFO_OFFSET); +- +- /* Disable the TX and RX to set baud rate */ +- xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) | +- (XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS), +- XUARTPS_CR_OFFSET); + + xuartps->baud = xuartps_set_baud_rate(xuartps->port, + xuartps->baud); ++ /* fall through */ ++ case ABORT_RATE_CHANGE: ++ if (!locked) ++ spin_lock_irqsave(&xuartps->port->lock, flags); + + /* Set TX/RX Reset */ + xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) | + (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST), + XUARTPS_CR_OFFSET); + ++ while (xuartps_readl(XUARTPS_CR_OFFSET) & ++ (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST)) ++ cpu_relax(); ++ + /* + * Clear the RX disable and TX disable bits and then set the TX + * enable bit and RX enable bit to enable the transmitter and + * receiver. + */ ++ xuartps_writel(rx_timeout, XUARTPS_RXTOUT_OFFSET); + ctrl_reg = xuartps_readl(XUARTPS_CR_OFFSET); + xuartps_writel( + (ctrl_reg & ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS)) | +@@ -490,9 +503,7 @@ static int xuartps_clk_notifier_cb(struct notifier_block *nb, + XUARTPS_CR_OFFSET); + + spin_unlock_irqrestore(&xuartps->port->lock, flags); +- return NOTIFY_OK; +- } +- case ABORT_RATE_CHANGE: ++ + return NOTIFY_OK; + default: + return NOTIFY_DONE; +@@ -1261,21 +1272,15 @@ static int xuartps_probe(struct platform_device *pdev) + else + xuartps->uartnum = 1; + +- if (xuartps->uartnum) +- xuartps->aperclk = clk_get_sys("UART1_APER", NULL); +- else +- xuartps->aperclk = clk_get_sys("UART0_APER", NULL); ++ xuartps->aperclk = clk_get(&pdev->dev, "aper_clk"); + if (IS_ERR(xuartps->aperclk)) { +- dev_err(&pdev->dev, "APER clock not found.\n"); ++ dev_err(&pdev->dev, "aper_clk clock not found.\n"); + ret = PTR_ERR(xuartps->aperclk); + goto err_out_free; + } +- if (xuartps->uartnum) +- xuartps->devclk = clk_get_sys("UART1", NULL); +- else +- xuartps->devclk = clk_get_sys("UART0", NULL); ++ xuartps->devclk = clk_get(&pdev->dev, "ref_clk"); + if (IS_ERR(xuartps->devclk)) { +- dev_err(&pdev->dev, "Device clock not found.\n"); ++ dev_err(&pdev->dev, "ref_clk clock not found.\n"); + ret = PTR_ERR(xuartps->devclk); + goto err_out_clk_put_aper; + } +@@ -1405,6 +1410,19 @@ static int xuartps_suspend(struct device *device) + + clk_disable(xuartps->devclk); + clk_disable(xuartps->aperclk); ++ } else { ++ unsigned long flags = 0; ++ ++ spin_lock_irqsave(&port->lock, flags); ++ /* Empty the receive FIFO 1st before making changes */ ++ while (!(xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_RXEMPTY)) ++ xuartps_readl(XUARTPS_FIFO_OFFSET); ++ dmb(); ++ /* set RX trigger level to 1 */ ++ xuartps_writel(1, XUARTPS_RXWM_OFFSET); ++ /* disable RX timeout interrups */ ++ xuartps_writel(XUARTPS_IXR_TOUT, XUARTPS_IDR_OFFSET); ++ spin_unlock_irqrestore(&port->lock, flags); + } + + return 0; +@@ -1445,7 +1463,12 @@ static int xuartps_resume(struct device *device) + xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) | + (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST), + XUARTPS_CR_OFFSET); ++ while (xuartps_readl(XUARTPS_CR_OFFSET) & ++ (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST)) ++ cpu_relax(); + ++ /* restore rx timeout value */ ++ xuartps_writel(rx_timeout, XUARTPS_RXTOUT_OFFSET); + /* Enable Tx/Rx */ + ctrl_reg = xuartps_readl(XUARTPS_CR_OFFSET); + xuartps_writel( +@@ -1454,6 +1477,13 @@ static int xuartps_resume(struct device *device) + XUARTPS_CR_OFFSET); + + spin_unlock_irqrestore(&port->lock, flags); ++ } else { ++ spin_lock_irqsave(&port->lock, flags); ++ /* restore original rx trigger level */ ++ xuartps_writel(rx_trigger_level, XUARTPS_RXWM_OFFSET); ++ /* enable RX timeout interrupt */ ++ xuartps_writel(XUARTPS_IXR_TOUT, XUARTPS_IER_OFFSET); ++ spin_unlock_irqrestore(&port->lock, flags); + } + + return uart_resume_port(&xuartps_uart_driver, port); +diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c +index f34f98d..892ecda 100644 +--- a/drivers/tty/tty_io.c ++++ b/drivers/tty/tty_io.c +@@ -941,10 +941,10 @@ void start_tty(struct tty_struct *tty) + + EXPORT_SYMBOL(start_tty); + +-/* We limit tty time update visibility to every 8 seconds or so. */ + static void tty_update_time(struct timespec *time) + { +- unsigned long sec = get_seconds() & ~7; ++ unsigned long sec = get_seconds(); ++ sec -= sec % 60; + if ((long)(sec - time->tv_sec) > 0) + time->tv_sec = sec; + } +diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c +index c0f4066..2f45bba 100644 +--- a/drivers/usb/chipidea/udc.c ++++ b/drivers/usb/chipidea/udc.c +@@ -461,8 +461,6 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) + mReq->ptr->page[i] = + (mReq->req.dma + i * CI13XXX_PAGE_SIZE) & ~TD_RESERVED_MASK; + +- wmb(); +- + if (!list_empty(&mEp->qh.queue)) { + struct ci13xxx_req *mReqPrev; + int n = hw_ep_bit(mEp->num, mEp->dir); +@@ -563,12 +561,6 @@ __acquires(mEp->lock) + struct ci13xxx_req *mReq = \ + list_entry(mEp->qh.queue.next, + struct ci13xxx_req, queue); +- +- if (mReq->zptr) { +- dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma); +- mReq->zptr = NULL; +- } +- + list_del_init(&mReq->queue); + mReq->req.status = -ESHUTDOWN; + +diff --git a/drivers/usb/chipidea/udc.h b/drivers/usb/chipidea/udc.h +index d12e8b5..4ff2384d 100644 +--- a/drivers/usb/chipidea/udc.h ++++ b/drivers/usb/chipidea/udc.h +@@ -40,7 +40,7 @@ struct ci13xxx_td { + #define TD_CURR_OFFSET (0x0FFFUL << 0) + #define TD_FRAME_NUM (0x07FFUL << 0) + #define TD_RESERVED_MASK (0x0FFFUL << 0) +-} __attribute__ ((packed, aligned(4))); ++} __attribute__ ((packed)); + + /* DMA layout of queue heads */ + struct ci13xxx_qh { +@@ -57,7 +57,7 @@ struct ci13xxx_qh { + /* 9 */ + u32 RESERVED; + struct usb_ctrlrequest setup; +-} __attribute__ ((packed, aligned(4))); ++} __attribute__ ((packed)); + + /** + * struct ci13xxx_req - usb request representation +diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c +index ea0a9a1..b78fbe2 100644 +--- a/drivers/usb/core/devio.c ++++ b/drivers/usb/core/devio.c +@@ -738,8 +738,6 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, + index &= 0xff; + switch (requesttype & USB_RECIP_MASK) { + case USB_RECIP_ENDPOINT: +- if ((index & ~USB_DIR_IN) == 0) +- return 0; + ret = findintfep(ps->dev, index); + if (ret >= 0) + ret = checkintf(ps, ret); +diff --git a/drivers/usb/gadget/xilinx_usbps_udc.c b/drivers/usb/gadget/xilinx_usbps_udc.c +index f127fbb..f4600d8 100644 +--- a/drivers/usb/gadget/xilinx_usbps_udc.c ++++ b/drivers/usb/gadget/xilinx_usbps_udc.c +@@ -396,12 +396,9 @@ static int xusbps_udc_clk_init(struct platform_device *pdev) + struct xusbps_usb2_platform_data *pdata = pdev->dev.platform_data; + int rc; + +- if (pdata->irq == 53) +- pdata->clk = clk_get_sys("USB0_APER", NULL); +- else +- pdata->clk = clk_get_sys("USB1_APER", NULL); ++ pdata->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(pdata->clk)) { +- dev_err(&pdev->dev, "APER clock not found.\n"); ++ dev_err(&pdev->dev, "input clock not found.\n"); + return PTR_ERR(pdata->clk); + } + +@@ -806,14 +803,10 @@ static void ep0_setup(struct xusbps_udc *udc) + { + /* the intialization of an ep includes: fields in QH, Regs, + * xusbps_ep struct */ +- /* +- * For control OUT endpoint, don't need to wait for zlp from host +- * (see usb 2.0 spec, section 5.5.3) +- */ + struct_ep_qh_setup(udc, 0, USB_RECV, USB_ENDPOINT_XFER_CONTROL, + USB_MAX_CTRL_PAYLOAD, 1, 0); + struct_ep_qh_setup(udc, 0, USB_SEND, USB_ENDPOINT_XFER_CONTROL, +- USB_MAX_CTRL_PAYLOAD, 0, 0); ++ USB_MAX_CTRL_PAYLOAD, 1, 0); + dr_ep_setup(0, USB_RECV, USB_ENDPOINT_XFER_CONTROL); + dr_ep_setup(0, USB_SEND, USB_ENDPOINT_XFER_CONTROL); + +@@ -1103,15 +1096,7 @@ static struct ep_td_struct *xusbps_build_dtd(struct xusbps_req *req, unsigned + + /* zlp is needed if req->req.zero is set */ + if (req->req.zero) { +- /* +- * There is no need for a separate zlp dtd for control IN +- * endpoint. The ZLT bit in dQH takes care. +- */ +- if ((ep_index(req->ep) == 0) && +- (req->req.length == req->req.actual) && +- !(req->req.length % req->ep->ep.maxpacket)) +- *is_last = 1; +- else if (*length == 0 || (*length % req->ep->ep.maxpacket) != 0) ++ if (*length == 0 || (*length % req->ep->ep.maxpacket) != 0) + *is_last = 1; + else + *is_last = 0; +diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig +index fb9b28d..81597e0 100644 +--- a/drivers/usb/host/Kconfig ++++ b/drivers/usb/host/Kconfig +@@ -140,6 +140,7 @@ config USB_XUSBPS_DR_OF + tristate + select USB_ULPI + select USB_ULPI_VIEWPORT ++ select GPIO_XILINX_PS + + config USB_EHCI_XUSBPS + bool "Support for Xilinx PS EHCI USB controller" +diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c +index a4e550d..fc6dc2a 100644 +--- a/drivers/usb/host/ehci-hcd.c ++++ b/drivers/usb/host/ehci-hcd.c +@@ -692,6 +692,9 @@ int ehci_setup(struct usb_hcd *hcd) + if (retval) + return retval; + ++ if (ehci_is_TDI(ehci)) ++ tdi_reset(ehci); ++ + ehci_reset(ehci); + + return 0; +diff --git a/drivers/usb/host/ehci-xilinx-usbps.c b/drivers/usb/host/ehci-xilinx-usbps.c +index d3efaad..547f7e1 100644 +--- a/drivers/usb/host/ehci-xilinx-usbps.c ++++ b/drivers/usb/host/ehci-xilinx-usbps.c +@@ -168,12 +168,9 @@ static int usb_hcd_xusbps_probe(const struct hc_driver *driver, + goto err2; + } + +- if (pdata->irq == 53) +- pdata->clk = clk_get_sys("USB0_APER", NULL); +- else +- pdata->clk = clk_get_sys("USB1_APER", NULL); ++ pdata->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(pdata->clk)) { +- dev_err(&pdev->dev, "APER clock not found.\n"); ++ dev_err(&pdev->dev, "input clock not found.\n"); + retval = PTR_ERR(pdata->clk); + goto err2; + } +diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c +index b3e1f19..4c338ec 100644 +--- a/drivers/usb/host/pci-quirks.c ++++ b/drivers/usb/host/pci-quirks.c +@@ -359,9 +359,6 @@ EXPORT_SYMBOL_GPL(usb_amd_dev_put); + */ + void uhci_reset_hc(struct pci_dev *pdev, unsigned long base) + { +-#ifdef CONFIG_MIPS_MALTA +- int timeout = 10; +-#endif + /* Turn off PIRQ enable and SMI enable. (This also turns off the + * BIOS's USB Legacy Support.) Turn off all the R/WC bits too. + */ +@@ -375,16 +372,9 @@ void uhci_reset_hc(struct pci_dev *pdev, unsigned long base) + outw(UHCI_USBCMD_HCRESET, base + UHCI_USBCMD); + mb(); + udelay(5); ++ if (inw(base + UHCI_USBCMD) & UHCI_USBCMD_HCRESET) ++ dev_warn(&pdev->dev, "HCRESET not completed yet!\n"); + +-#ifdef CONFIG_MIPS_MALTA +- while (inw(base + UHCI_USBCMD) & UHCI_USBCMD_HCRESET) { +- if (--timeout < 0) { +- dev_warn(&pdev->dev, "HCRESET timed out!\n"); +- break; +- } +- udelay(5); +- } +-#endif + /* Just to be safe, disable interrupt requests and + * make sure the controller is stopped. + */ +diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c +index 6ac4f2b..15921fd 100644 +--- a/drivers/usb/host/uhci-q.c ++++ b/drivers/usb/host/uhci-q.c +@@ -71,9 +71,7 @@ static void uhci_fsbr_off(struct uhci_hcd *uhci) + static void uhci_add_fsbr(struct uhci_hcd *uhci, struct urb *urb) + { + struct urb_priv *urbp = urb->hcpriv; +-#ifdef CONFIG_MIPS_MALTA +- return; +-#endif ++ + if (!(urb->transfer_flags & URB_NO_FSBR)) + urbp->fsbr = 1; + } +diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c +index 2573cf4..f2845f1 100644 +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -2461,21 +2461,14 @@ static int handle_tx_event(struct xhci_hcd *xhci, + * TD list. + */ + if (list_empty(&ep_ring->td_list)) { +- /* +- * A stopped endpoint may generate an extra completion +- * event if the device was suspended. Don't print +- * warnings. +- */ +- if (!(trb_comp_code == COMP_STOP || +- trb_comp_code == COMP_STOP_INVAL)) { +- xhci_warn(xhci, "WARN Event TRB for slot %d ep %d with no TDs queued?\n", +- TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), +- ep_index); +- xhci_dbg(xhci, "Event TRB with TRB type ID %u\n", +- (le32_to_cpu(event->flags) & +- TRB_TYPE_BITMASK)>>10); +- xhci_print_trb_offsets(xhci, (union xhci_trb *) event); +- } ++ xhci_warn(xhci, "WARN Event TRB for slot %d ep %d " ++ "with no TDs queued?\n", ++ TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), ++ ep_index); ++ xhci_dbg(xhci, "Event TRB with TRB type ID %u\n", ++ (le32_to_cpu(event->flags) & ++ TRB_TYPE_BITMASK)>>10); ++ xhci_print_trb_offsets(xhci, (union xhci_trb *) event); + if (ep->skip) { + ep->skip = false; + xhci_dbg(xhci, "td_list is empty while skip " +diff --git a/drivers/usb/host/xusbps-dr-of.c b/drivers/usb/host/xusbps-dr-of.c +index c75e23e..08d420b 100644 +--- a/drivers/usb/host/xusbps-dr-of.c ++++ b/drivers/usb/host/xusbps-dr-of.c +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + + #include "ehci-xilinx-usbps.h" + +@@ -155,7 +156,7 @@ static int xusbps_dr_of_probe(struct platform_device *ofdev) + const unsigned char *prop; + static unsigned int idx; + struct resource *res; +- int i, phy_init; ++ int i, phy_init, reset_gpio; + int ret; + + pdata = &data; +@@ -189,6 +190,19 @@ static int xusbps_dr_of_probe(struct platform_device *ofdev) + return -EFAULT; + } + ++ /* Find out reset gpio and reset usb phy */ ++ reset_gpio = of_get_named_gpio(ofdev->dev.of_node, "usb-reset", 0); ++ if (reset_gpio >= 0) { ++ ret = devm_gpio_request_one(&ofdev->dev, reset_gpio, ++ GPIOF_OUT_INIT_HIGH, "usb_reset"); ++ if (ret) { ++ dev_err(&ofdev->dev, "Please specify usb reset pin\n"); ++ return ret; ++ } ++ gpio_set_value(reset_gpio, 0); ++ gpio_set_value(reset_gpio, 1); ++ } ++ + dev_data = get_dr_mode_data(np); + pdata->operating_mode = dev_data->op_mode; + +@@ -202,12 +216,9 @@ static int xusbps_dr_of_probe(struct platform_device *ofdev) + } + platform_set_drvdata(ofdev, hdata); + +- if (pdata->irq == 53) +- hdata->clk = clk_get_sys("USB0_APER", NULL); +- else +- hdata->clk = clk_get_sys("USB1_APER", NULL); ++ hdata->clk = clk_get(&ofdev->dev, NULL); + if (IS_ERR(hdata->clk)) { +- dev_err(&ofdev->dev, "APER clock not found.\n"); ++ dev_err(&ofdev->dev, "input clock not found.\n"); + ret = PTR_ERR(hdata->clk); + goto err_free; + } +diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c +index ba6a5d6..0fc6e5f 100644 +--- a/drivers/usb/misc/appledisplay.c ++++ b/drivers/usb/misc/appledisplay.c +@@ -63,7 +63,6 @@ static const struct usb_device_id appledisplay_table[] = { + { APPLEDISPLAY_DEVICE(0x9219) }, + { APPLEDISPLAY_DEVICE(0x921c) }, + { APPLEDISPLAY_DEVICE(0x921d) }, +- { APPLEDISPLAY_DEVICE(0x9236) }, + + /* Terminating entry */ + { } +diff --git a/drivers/usb/otg/xilinx_usbps_otg.c b/drivers/usb/otg/xilinx_usbps_otg.c +index 14c297e..fa6f995 100644 +--- a/drivers/usb/otg/xilinx_usbps_otg.c ++++ b/drivers/usb/otg/xilinx_usbps_otg.c +@@ -1996,12 +1996,9 @@ static int xusbps_otg_probe(struct platform_device *pdev) + } + INIT_WORK(&xotg->work, xusbps_otg_work); + +- if (xotg->irq == 53) +- xotg->clk = clk_get_sys("USB0_APER", NULL); +- else +- xotg->clk = clk_get_sys("USB1_APER", NULL); ++ xotg->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(xotg->clk)) { +- dev_err(&pdev->dev, "APER clock not found.\n"); ++ dev_err(&pdev->dev, "input clock not found.\n"); + retval = PTR_ERR(xotg->clk); + goto err; + } +diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c +index 77f78ad..8e4f40b 100644 +--- a/drivers/usb/serial/ftdi_sio.c ++++ b/drivers/usb/serial/ftdi_sio.c +@@ -189,7 +189,6 @@ static struct usb_device_id id_table_combined [] = { + { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_THROTTLE_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GATEWAY_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GBM_PID) }, +- { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GBM_BOOST_PID) }, + { USB_DEVICE(NEWPORT_VID, NEWPORT_AGILIS_PID) }, + { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) }, + { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) }, +@@ -871,9 +870,7 @@ static struct usb_device_id id_table_combined [] = { + { USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) }, + { USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, +- { USB_DEVICE(ST_VID, ST_STMCLT_2232_PID), +- .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, +- { USB_DEVICE(ST_VID, ST_STMCLT_4232_PID), ++ { USB_DEVICE(ST_VID, ST_STMCLT1030_PID), + .driver_info = (kernel_ulong_t)&ftdi_stmclite_quirk }, + { USB_DEVICE(FTDI_VID, FTDI_RF_R106) }, + { USB_DEVICE(FTDI_VID, FTDI_DISTORTEC_JTAG_LOCK_PICK_PID), +@@ -1795,24 +1792,20 @@ static int ftdi_8u2232c_probe(struct usb_serial *serial) + } + + /* +- * First two ports on JTAG adaptors using an FT4232 such as STMicroelectronics's +- * ST Micro Connect Lite are reserved for JTAG or other non-UART interfaces and +- * can be accessed from userspace. +- * The next two ports are enabled as UARTs by default, where port 2 is +- * a conventional RS-232 UART. ++ * First and second port on STMCLiteadaptors is reserved for JTAG interface ++ * and the forth port for pio + */ + static int ftdi_stmclite_probe(struct usb_serial *serial) + { + struct usb_device *udev = serial->dev; + struct usb_interface *interface = serial->interface; + +- if (interface == udev->actconfig->interface[0] || +- interface == udev->actconfig->interface[1]) { +- dev_info(&udev->dev, "Ignoring serial port reserved for JTAG\n"); +- return -ENODEV; +- } ++ if (interface == udev->actconfig->interface[2]) ++ return 0; + +- return 0; ++ dev_info(&udev->dev, "Ignoring serial port reserved for JTAG\n"); ++ ++ return -ENODEV; + } + + /* +diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h +index 9852827..e79861e 100644 +--- a/drivers/usb/serial/ftdi_sio_ids.h ++++ b/drivers/usb/serial/ftdi_sio_ids.h +@@ -74,7 +74,6 @@ + #define FTDI_OPENDCC_THROTTLE_PID 0xBFDA + #define FTDI_OPENDCC_GATEWAY_PID 0xBFDB + #define FTDI_OPENDCC_GBM_PID 0xBFDC +-#define FTDI_OPENDCC_GBM_BOOST_PID 0xBFDD + + /* NZR SEM 16+ USB (http://www.nzr.de) */ + #define FTDI_NZR_SEM_USB_PID 0xC1E0 /* NZR SEM-LOG16+ */ +@@ -1151,8 +1150,7 @@ + * STMicroelectonics + */ + #define ST_VID 0x0483 +-#define ST_STMCLT_2232_PID 0x3746 +-#define ST_STMCLT_4232_PID 0x3747 ++#define ST_STMCLT1030_PID 0x3747 /* ST Micro Connect Lite STMCLT1030 */ + + /* + * Papouch products (http://www.papouch.com/) +diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c +index bff059a..558adfc 100644 +--- a/drivers/usb/serial/option.c ++++ b/drivers/usb/serial/option.c +@@ -347,7 +347,6 @@ static void option_instat_callback(struct urb *urb); + /* Olivetti products */ + #define OLIVETTI_VENDOR_ID 0x0b3c + #define OLIVETTI_PRODUCT_OLICARD100 0xc000 +-#define OLIVETTI_PRODUCT_OLICARD145 0xc003 + + /* Celot products */ + #define CELOT_VENDOR_ID 0x211f +@@ -1274,7 +1273,6 @@ static const struct usb_device_id option_ids[] = { + { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) }, + + { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) }, +- { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD145) }, + { USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */ + { USB_DEVICE(ONDA_VENDOR_ID, ONDA_MT825UP) }, /* ONDA MT825UP modem */ + { USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_GT_B3730, USB_CLASS_CDC_DATA, 0x00, 0x00) }, /* Samsung GT-B3730 LTE USB modem.*/ +@@ -1352,12 +1350,6 @@ static const struct usb_device_id option_ids[] = { + { USB_DEVICE(TPLINK_VENDOR_ID, TPLINK_PRODUCT_MA180), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE(CHANGHONG_VENDOR_ID, CHANGHONG_PRODUCT_CH690) }, +- { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d01, 0xff, 0x02, 0x01) }, /* D-Link DWM-156 (variant) */ +- { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d01, 0xff, 0x00, 0x00) }, /* D-Link DWM-156 (variant) */ +- { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d02, 0xff, 0x02, 0x01) }, +- { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d02, 0xff, 0x00, 0x00) }, +- { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x02, 0x01) }, +- { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x00, 0x00) }, + { } /* Terminating entry */ + }; + MODULE_DEVICE_TABLE(usb, option_ids); +diff --git a/drivers/usb/storage/cypress_atacb.c b/drivers/usb/storage/cypress_atacb.c +index d944088..070b5c0 100644 +--- a/drivers/usb/storage/cypress_atacb.c ++++ b/drivers/usb/storage/cypress_atacb.c +@@ -248,26 +248,14 @@ static int cypress_probe(struct usb_interface *intf, + { + struct us_data *us; + int result; +- struct usb_device *device; + + result = usb_stor_probe1(&us, intf, id, + (id - cypress_usb_ids) + cypress_unusual_dev_list); + if (result) + return result; + +- /* Among CY7C68300 chips, the A revision does not support Cypress ATACB +- * Filter out this revision from EEPROM default descriptor values +- */ +- device = interface_to_usbdev(intf); +- if (device->descriptor.iManufacturer != 0x38 || +- device->descriptor.iProduct != 0x4e || +- device->descriptor.iSerialNumber != 0x64) { +- us->protocol_name = "Transparent SCSI with Cypress ATACB"; +- us->proto_handler = cypress_atacb_passthrough; +- } else { +- us->protocol_name = "Transparent SCSI"; +- us->proto_handler = usb_stor_transparent_scsi_command; +- } ++ us->protocol_name = "Transparent SCSI with Cypress ATACB"; ++ us->proto_handler = cypress_atacb_passthrough; + + result = usb_stor_probe2(us); + return result; +diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c +index 6e696e6..501c599 100644 +--- a/drivers/video/console/fbcon.c ++++ b/drivers/video/console/fbcon.c +@@ -1228,8 +1228,6 @@ static void fbcon_deinit(struct vc_data *vc) + finished: + + fbcon_free_font(p, free_font); +- if (free_font) +- vc->vc_font.data = NULL; + + if (!con_is_bound(&fb_con)) + fbcon_exit(); +diff --git a/drivers/video/xylon/xylonfb/core/xylonfb-pixclk.c b/drivers/video/xylon/xylonfb/core/xylonfb-pixclk.c +index 357a3f7..e5dfcfd 100644 +--- a/drivers/video/xylon/xylonfb/core/xylonfb-pixclk.c ++++ b/drivers/video/xylon/xylonfb/core/xylonfb-pixclk.c +@@ -17,9 +17,17 @@ + * generation on various HW platforms. + */ + +- ++#include ++#include + #include ++#include + ++#ifdef CONFIG_OF ++/* For open firmware. */ ++#include ++#include ++#include ++#endif + + #define XYLONFB_PIXCLK_GEN_DEVS 8 + +@@ -30,9 +38,6 @@ static bool xylonfb_hw_pixclk_init; + + #define XYLONFB_PIXCLK_ZYNQ_PS 1 + +-#include +-#include +- + int xylonfb_hw_pixclk_set_zynq_ps(unsigned long pixclk_khz) + { + unsigned long pllclk, sysclk; +@@ -116,15 +121,6 @@ int xylonfb_hw_pixclk_set_zynq_ps(unsigned long pixclk_khz) + + #define XYLONFB_PIXCLK_LOGICLK 2 + +-#include +-#include +-#include +-#ifdef CONFIG_OF +-/* For open firmware. */ +-#include +-#include +-#include +-#endif + #include "logiclk.h" + + int xylonfb_hw_pixclk_set_logiclk(unsigned long pixclk_khz) +diff --git a/drivers/video/xylon/xylonfb/core/xylonfb.c b/drivers/video/xylon/xylonfb/core/xylonfb.c +index bf7c758..b26dbb2 100644 +--- a/drivers/video/xylon/xylonfb/core/xylonfb.c ++++ b/drivers/video/xylon/xylonfb/core/xylonfb.c +@@ -12,14 +12,6 @@ + * kind, whether express or implied. + */ + +-/* +- Usefull driver information: +- - driver does not support multiple instances of logiCVC-ML +- - logiCVC-ML background layer is recomended +- - platform driver default resolution is set with defines +- in xylonfb-vmode.h +- */ +- + + #include + #include +@@ -257,13 +249,16 @@ static int xylonfb_check_var(struct fb_var_screeninfo *var, + + static int xylonfb_set_par(struct fb_info *fbi) + { ++ struct fb_info **afbi = NULL; + struct xylonfb_layer_data *ld = fbi->par; + struct xylonfb_common_data *cd = ld->xylonfb_cd; + int rc = 0; +- struct fb_info **afbi = NULL; + int i; + char vmode_opt[20+1]; +- char vmode_cvt[2+1]; ++ char vmode_ct[] = ""; ++ char vmode_cvt[] = "M"; ++ char vmode_cvtrb[] = "MR"; ++ char *vmode_tim; + bool resolution_change, layer_on[LOGICVC_MAX_LAYERS]; + + driver_devel("%s\n", __func__); +@@ -281,6 +276,15 @@ static int xylonfb_set_par(struct fb_info *fbi) + resolution_change = true; + } + ++ if (cd->xylonfb_flags & XYLONFB_FLAG_VMODE_INIT) { ++ vmode_tim = vmode_cvt; ++ } else { ++ if (cd->xylonfb_flags & XYLONFB_FLAG_EDID_VMODE) ++ vmode_tim = vmode_ct; ++ else ++ vmode_tim = vmode_cvtrb; ++ } ++ + if (resolution_change || + (cd->xylonfb_flags & XYLONFB_FLAG_VMODE_INIT)) { + +@@ -301,13 +305,9 @@ static int xylonfb_set_par(struct fb_info *fbi) + xylonfb_logicvc_disp_ctrl(fbi, false); + + if (!(cd->xylonfb_flags & XYLONFB_FLAG_VMODE_INIT)) { +- if (cd->xylonfb_flags & XYLONFB_FLAG_EDID_VMODE) +- strcpy(vmode_cvt, "-"); +- else +- strcpy(vmode_cvt, "M-"); +- sprintf(vmode_opt, "%dx%d%s%d@%d", ++ sprintf(vmode_opt, "%dx%d%s-%d@%d", + fbi->var.xres, fbi->var.yres, +- vmode_cvt, ++ vmode_tim, + fbi->var.bits_per_pixel, + cd->vmode_data_current.fb_vmode.refresh); + if (!strcmp(cd->vmode_data.fb_vmode_name, vmode_opt)) { +@@ -328,9 +328,9 @@ static int xylonfb_set_par(struct fb_info *fbi) + pr_err("Error xylonfb changing pixel clock\n"); + } + xylonfb_fbi_update(fbi); +- pr_info("xylonfb video mode: %dx%d-%d@%d\n", +- fbi->var.xres, +- fbi->var.yres, ++ pr_info("xylonfb video mode: %dx%d%s-%d@%d\n", ++ fbi->var.xres, fbi->var.yres, ++ vmode_tim, + fbi->var.bits_per_pixel, + cd->vmode_data_current.fb_vmode.refresh); + } +@@ -1257,7 +1257,7 @@ static int xylonfb_set_timings(struct fb_info *fbi, int bpp) + switch (rc) { + case 0: + pr_err("Error xylonfb video mode\n" +- "using driver default mode %dx%d-%d@%d\n", ++ "using driver default mode %dx%dM-%d@%d\n", + xylonfb_vmode.fb_vmode.xres, + xylonfb_vmode.fb_vmode.yres, + bpp, +@@ -1271,10 +1271,11 @@ static int xylonfb_set_timings(struct fb_info *fbi, int bpp) + xylonfb_mode_option); + break; + case 3: +- pr_notice("xylonfb default video mode %dx%d-%d@%d\n", ++ pr_notice("xylonfb default video mode %dx%dM-%d@%d\n", + xylonfb_vmode.fb_vmode.xres, + xylonfb_vmode.fb_vmode.yres, +- bpp, xylonfb_vmode.fb_vmode.refresh); ++ bpp, ++ xylonfb_vmode.fb_vmode.refresh); + break; + case 4: + pr_notice("xylonfb video mode fallback\n"); +@@ -1297,14 +1298,17 @@ static int xylonfb_set_timings(struct fb_info *fbi, int bpp) + cd->vmode_data_current.fb_vmode.sync = fb_var.sync; + cd->vmode_data_current.fb_vmode.vmode = fb_var.vmode; + cd->vmode_data_current.fb_vmode.refresh = +- (PICOS2KHZ(fb_var.pixclock) * 1000) / +- ((fb_var.xres + fb_var.left_margin + fb_var.right_margin + +- fb_var.hsync_len) * +- (fb_var.yres + fb_var.upper_margin + fb_var.lower_margin + +- fb_var.vsync_len)); ++ DIV_ROUND_CLOSEST( ++ (PICOS2KHZ(fb_var.pixclock) * 1000), ++ ((fb_var.xres + fb_var.left_margin + ++ fb_var.right_margin + fb_var.hsync_len) ++ * ++ (fb_var.yres + fb_var.upper_margin + ++ fb_var.lower_margin + fb_var.vsync_len))); + sprintf(cd->vmode_data_current.fb_vmode_name, + "%dx%dM-%d@%d", +- fb_var.xres, fb_var.yres, fb_var.bits_per_pixel, ++ fb_var.xres, fb_var.yres, ++ fb_var.bits_per_pixel, + cd->vmode_data_current.fb_vmode.refresh); + + if ((cd->xylonfb_flags & XYLONFB_FLAG_EDID_RDY) || +diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig +index 2d12d62..2acbe8d 100644 +--- a/drivers/watchdog/Kconfig ++++ b/drivers/watchdog/Kconfig +@@ -959,13 +959,10 @@ config M54xx_WATCHDOG + + config XILINX_WATCHDOG + tristate "Xilinx Watchdog timer" +- depends on MICROBLAZE ++ depends on MICROBLAZE || ARCH_ZYNQ + ---help--- + Watchdog driver for the xps_timebase_wdt ip core. + +- IMPORTANT: The xps_timebase_wdt parent must have the property +- "clock-frequency" at device tree. +- + To compile this driver as a module, choose M here: the + module will be called of_xilinx_wdt. + +diff --git a/drivers/watchdog/xilinx_wdtps.c b/drivers/watchdog/xilinx_wdtps.c +index 525082f..5d4950e 100644 +--- a/drivers/watchdog/xilinx_wdtps.c ++++ b/drivers/watchdog/xilinx_wdtps.c +@@ -349,7 +349,7 @@ static int xwdtps_probe(struct platform_device *pdev) + watchdog_set_nowayout(&xwdtps_device, nowayout); + watchdog_set_drvdata(&xwdtps_device, &wdt); + +- wdt->clk = clk_get_sys("CPU_1X_CLK", NULL); ++ wdt->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(wdt->clk)) { + dev_err(&pdev->dev, "input clock not found\n"); + res = PTR_ERR(wdt->clk); +diff --git a/fs/Kconfig b/fs/Kconfig +index da05819..780725a 100644 +--- a/fs/Kconfig ++++ b/fs/Kconfig +@@ -193,7 +193,6 @@ source "fs/hfsplus/Kconfig" + source "fs/befs/Kconfig" + source "fs/bfs/Kconfig" + source "fs/efs/Kconfig" +-source "fs/yaffs2/Kconfig" + source "fs/jffs2/Kconfig" + # UBIFS File system configuration + source "fs/ubifs/Kconfig" +@@ -212,7 +211,6 @@ source "fs/sysv/Kconfig" + source "fs/ufs/Kconfig" + source "fs/exofs/Kconfig" + source "fs/f2fs/Kconfig" +-source "fs/aufs/Kconfig" + + endif # MISC_FILESYSTEMS + +diff --git a/fs/Makefile b/fs/Makefile +index d91e380..9d53192 100644 +--- a/fs/Makefile ++++ b/fs/Makefile +@@ -127,5 +127,3 @@ obj-$(CONFIG_F2FS_FS) += f2fs/ + obj-y += exofs/ # Multiple modules + obj-$(CONFIG_CEPH_FS) += ceph/ + obj-$(CONFIG_PSTORE) += pstore/ +-obj-$(CONFIG_YAFFS_FS) += yaffs2/ +-obj-$(CONFIG_AUFS_FS) += aufs/ +diff --git a/fs/aufs/Kconfig b/fs/aufs/Kconfig +deleted file mode 100644 +index 7a96cb5..0000000 +--- a/fs/aufs/Kconfig ++++ /dev/null +@@ -1,203 +0,0 @@ +-config AUFS_FS +- tristate "Aufs (Advanced multi layered unification filesystem) support" +- depends on EXPERIMENTAL +- help +- Aufs is a stackable unification filesystem such as Unionfs, +- which unifies several directories and provides a merged single +- directory. +- In the early days, aufs was entirely re-designed and +- re-implemented Unionfs Version 1.x series. Introducing many +- original ideas, approaches and improvements, it becomes totally +- different from Unionfs while keeping the basic features. +- +-if AUFS_FS +-choice +- prompt "Maximum number of branches" +- default AUFS_BRANCH_MAX_127 +- help +- Specifies the maximum number of branches (or member directories) +- in a single aufs. The larger value consumes more system +- resources and has a minor impact to performance. +-config AUFS_BRANCH_MAX_127 +- bool "127" +- help +- Specifies the maximum number of branches (or member directories) +- in a single aufs. The larger value consumes more system +- resources and has a minor impact to performance. +-config AUFS_BRANCH_MAX_511 +- bool "511" +- help +- Specifies the maximum number of branches (or member directories) +- in a single aufs. The larger value consumes more system +- resources and has a minor impact to performance. +-config AUFS_BRANCH_MAX_1023 +- bool "1023" +- help +- Specifies the maximum number of branches (or member directories) +- in a single aufs. The larger value consumes more system +- resources and has a minor impact to performance. +-config AUFS_BRANCH_MAX_32767 +- bool "32767" +- help +- Specifies the maximum number of branches (or member directories) +- in a single aufs. The larger value consumes more system +- resources and has a minor impact to performance. +-endchoice +- +-config AUFS_SBILIST +- bool +- depends on AUFS_MAGIC_SYSRQ || PROC_FS +- default y +- help +- Automatic configuration for internal use. +- When aufs supports Magic SysRq or /proc, enabled automatically. +- +-config AUFS_HNOTIFY +- bool "Detect direct branch access (bypassing aufs)" +- help +- If you want to modify files on branches directly, eg. bypassing aufs, +- and want aufs to detect the changes of them fully, then enable this +- option and use 'udba=notify' mount option. +- Currently there is only one available configuration, "fsnotify". +- It will have a negative impact to the performance. +- See detail in aufs.5. +- +-choice +- prompt "method" if AUFS_HNOTIFY +- default AUFS_HFSNOTIFY +-config AUFS_HFSNOTIFY +- bool "fsnotify" +- select FSNOTIFY +-endchoice +- +-config AUFS_EXPORT +- bool "NFS-exportable aufs" +- depends on EXPORTFS +- help +- If you want to export your mounted aufs via NFS, then enable this +- option. There are several requirements for this configuration. +- See detail in aufs.5. +- +-config AUFS_INO_T_64 +- bool +- depends on AUFS_EXPORT +- depends on 64BIT && !(ALPHA || S390) +- default y +- help +- Automatic configuration for internal use. +- /* typedef unsigned long/int __kernel_ino_t */ +- /* alpha and s390x are int */ +- +-config AUFS_RDU +- bool "Readdir in userspace" +- help +- Aufs has two methods to provide a merged view for a directory, +- by a user-space library and by kernel-space natively. The latter +- is always enabled but sometimes large and slow. +- If you enable this option, install the library in aufs2-util +- package, and set some environment variables for your readdir(3), +- then the work will be handled in user-space which generally +- shows better performance in most cases. +- See detail in aufs.5. +- +-config AUFS_PROC_MAP +- bool "support for /proc/maps and lsof(1)" +- depends on PROC_FS +- help +- When you issue mmap(2) in aufs, it is actually a direct mmap(2) +- call to the file on the branch fs since the file in aufs is +- purely virtual. And the file path printed in /proc/maps (and +- others) will be the path on the branch fs. In most cases, it +- does no harm. But some utilities like lsof(1) may confuse since +- the utility or user may expect the file path in aufs to be +- printed. +- To address this issue, aufs provides a patch which introduces a +- new member called vm_prfile into struct vm_are_struct. The patch +- is meaningless without enabling this configuration since nobody +- sets the new vm_prfile member. +- If you don't apply the patch, then enabling this configuration +- will cause a compile error. +- This approach is fragile since if someone else make some changes +- around vm_file, then vm_prfile may not work anymore. As a +- workaround such case, aufs provides this configuration. If you +- disable it, then lsof(1) may produce incorrect result but the +- problem will be gone even if the aufs patch is applied (I hope). +- +-config AUFS_SP_IATTR +- bool "Respect the attributes (mtime/ctime mainly) of special files" +- help +- When you write something to a special file, some attributes of it +- (mtime/ctime mainly) may be updated. Generally such updates are +- less important (actually some device drivers and NFS ignore +- it). But some applications (such like test program) requires +- such updates. If you need these updates, then enable this +- configuration which introduces some overhead. +- Currently this configuration handles FIFO only. +- +-config AUFS_SHWH +- bool "Show whiteouts" +- help +- If you want to make the whiteouts in aufs visible, then enable +- this option and specify 'shwh' mount option. Although it may +- sounds like philosophy or something, but in technically it +- simply shows the name of whiteout with keeping its behaviour. +- +-config AUFS_BR_RAMFS +- bool "Ramfs (initramfs/rootfs) as an aufs branch" +- help +- If you want to use ramfs as an aufs branch fs, then enable this +- option. Generally tmpfs is recommended. +- Aufs prohibited them to be a branch fs by default, because +- initramfs becomes unusable after switch_root or something +- generally. If you sets initramfs as an aufs branch and boot your +- system by switch_root, you will meet a problem easily since the +- files in initramfs may be inaccessible. +- Unless you are going to use ramfs as an aufs branch fs without +- switch_root or something, leave it N. +- +-config AUFS_BR_FUSE +- bool "Fuse fs as an aufs branch" +- depends on FUSE_FS +- select AUFS_POLL +- help +- If you want to use fuse-based userspace filesystem as an aufs +- branch fs, then enable this option. +- It implements the internal poll(2) operation which is +- implemented by fuse only (curretnly). +- +-config AUFS_POLL +- bool +- help +- Automatic configuration for internal use. +- +-config AUFS_BR_HFSPLUS +- bool "Hfsplus as an aufs branch" +- depends on HFSPLUS_FS +- default y +- help +- If you want to use hfsplus fs as an aufs branch fs, then enable +- this option. This option introduces a small overhead at +- copying-up a file on hfsplus. +- +-config AUFS_BDEV_LOOP +- bool +- depends on BLK_DEV_LOOP +- default y +- help +- Automatic configuration for internal use. +- Convert =[ym] into =y. +- +-config AUFS_DEBUG +- bool "Debug aufs" +- help +- Enable this to compile aufs internal debug code. +- It will have a negative impact to the performance. +- +-config AUFS_MAGIC_SYSRQ +- bool +- depends on AUFS_DEBUG && MAGIC_SYSRQ +- default y +- help +- Automatic configuration for internal use. +- When aufs supports Magic SysRq, enabled automatically. +-endif +diff --git a/fs/aufs/Makefile b/fs/aufs/Makefile +deleted file mode 100644 +index 9b25bc8..0000000 +--- a/fs/aufs/Makefile ++++ /dev/null +@@ -1,42 +0,0 @@ +- +-include ${src}/magic.mk +-ifeq (${CONFIG_AUFS_FS},m) +-include ${src}/conf.mk +-endif +--include ${src}/priv_def.mk +- +-# cf. include/linux/kernel.h +-# enable pr_debug +-ccflags-y += -DDEBUG +-# sparse requires the full pathname +-ifdef M +-ccflags-y += -include ${M}/../../include/linux/aufs_type.h +-else +-ccflags-y += -include ${srctree}/include/linux/aufs_type.h +-endif +- +-obj-$(CONFIG_AUFS_FS) += aufs.o +-aufs-y := module.o sbinfo.o super.o branch.o xino.o sysaufs.o opts.o \ +- wkq.o vfsub.o dcsub.o \ +- cpup.o whout.o wbr_policy.o \ +- dinfo.o dentry.o \ +- dynop.o \ +- finfo.o file.o f_op.o \ +- dir.o vdir.o \ +- iinfo.o inode.o i_op.o i_op_add.o i_op_del.o i_op_ren.o \ +- ioctl.o +- +-# all are boolean +-aufs-$(CONFIG_PROC_FS) += procfs.o plink.o +-aufs-$(CONFIG_SYSFS) += sysfs.o +-aufs-$(CONFIG_DEBUG_FS) += dbgaufs.o +-aufs-$(CONFIG_AUFS_BDEV_LOOP) += loop.o +-aufs-$(CONFIG_AUFS_HNOTIFY) += hnotify.o +-aufs-$(CONFIG_AUFS_HFSNOTIFY) += hfsnotify.o +-aufs-$(CONFIG_AUFS_EXPORT) += export.o +-aufs-$(CONFIG_AUFS_POLL) += poll.o +-aufs-$(CONFIG_AUFS_RDU) += rdu.o +-aufs-$(CONFIG_AUFS_SP_IATTR) += f_op_sp.o +-aufs-$(CONFIG_AUFS_BR_HFSPLUS) += hfsplus.o +-aufs-$(CONFIG_AUFS_DEBUG) += debug.o +-aufs-$(CONFIG_AUFS_MAGIC_SYSRQ) += sysrq.o +diff --git a/fs/aufs/aufs.h b/fs/aufs/aufs.h +deleted file mode 100644 +index 8adb4f2..0000000 +--- a/fs/aufs/aufs.h ++++ /dev/null +@@ -1,60 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * all header files +- */ +- +-#ifndef __AUFS_H__ +-#define __AUFS_H__ +- +-#ifdef __KERNEL__ +- +-#define AuStub(type, name, body, ...) \ +- static inline type name(__VA_ARGS__) { body; } +- +-#define AuStubVoid(name, ...) \ +- AuStub(void, name, , __VA_ARGS__) +-#define AuStubInt0(name, ...) \ +- AuStub(int, name, return 0, __VA_ARGS__) +- +-#include "debug.h" +- +-#include "branch.h" +-#include "cpup.h" +-#include "dcsub.h" +-#include "dbgaufs.h" +-#include "dentry.h" +-#include "dir.h" +-#include "dynop.h" +-#include "file.h" +-#include "fstype.h" +-#include "inode.h" +-#include "loop.h" +-#include "module.h" +-#include "opts.h" +-#include "rwsem.h" +-#include "spl.h" +-#include "super.h" +-#include "sysaufs.h" +-#include "vfsub.h" +-#include "whout.h" +-#include "wkq.h" +- +-#endif /* __KERNEL__ */ +-#endif /* __AUFS_H__ */ +diff --git a/fs/aufs/branch.c b/fs/aufs/branch.c +deleted file mode 100644 +index e082b6c..0000000 +--- a/fs/aufs/branch.c ++++ /dev/null +@@ -1,1172 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * branch management +- */ +- +-#include +-#include +-#include "aufs.h" +- +-/* +- * free a single branch +- */ +-static void au_br_do_free(struct au_branch *br) +-{ +- int i; +- struct au_wbr *wbr; +- struct au_dykey **key; +- +- au_hnotify_fin_br(br); +- +- if (br->br_xino.xi_file) +- fput(br->br_xino.xi_file); +- mutex_destroy(&br->br_xino.xi_nondir_mtx); +- +- AuDebugOn(atomic_read(&br->br_count)); +- +- wbr = br->br_wbr; +- if (wbr) { +- for (i = 0; i < AuBrWh_Last; i++) +- dput(wbr->wbr_wh[i]); +- AuDebugOn(atomic_read(&wbr->wbr_wh_running)); +- AuRwDestroy(&wbr->wbr_wh_rwsem); +- } +- +- key = br->br_dykey; +- for (i = 0; i < AuBrDynOp; i++, key++) +- if (*key) +- au_dy_put(*key); +- else +- break; +- +- /* recursive lock, s_umount of branch's */ +- lockdep_off(); +- mntput(br->br_mnt); +- lockdep_on(); +- kfree(wbr); +- kfree(br); +-} +- +-/* +- * frees all branches +- */ +-void au_br_free(struct au_sbinfo *sbinfo) +-{ +- aufs_bindex_t bmax; +- struct au_branch **br; +- +- AuRwMustWriteLock(&sbinfo->si_rwsem); +- +- bmax = sbinfo->si_bend + 1; +- br = sbinfo->si_branch; +- while (bmax--) +- au_br_do_free(*br++); +-} +- +-/* +- * find the index of a branch which is specified by @br_id. +- */ +-int au_br_index(struct super_block *sb, aufs_bindex_t br_id) +-{ +- aufs_bindex_t bindex, bend; +- +- bend = au_sbend(sb); +- for (bindex = 0; bindex <= bend; bindex++) +- if (au_sbr_id(sb, bindex) == br_id) +- return bindex; +- return -1; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* +- * add a branch +- */ +- +-static int test_overlap(struct super_block *sb, struct dentry *h_adding, +- struct dentry *h_root) +-{ +- if (unlikely(h_adding == h_root +- || au_test_loopback_overlap(sb, h_adding))) +- return 1; +- if (h_adding->d_sb != h_root->d_sb) +- return 0; +- return au_test_subdir(h_adding, h_root) +- || au_test_subdir(h_root, h_adding); +-} +- +-/* +- * returns a newly allocated branch. @new_nbranch is a number of branches +- * after adding a branch. +- */ +-static struct au_branch *au_br_alloc(struct super_block *sb, int new_nbranch, +- int perm) +-{ +- struct au_branch *add_branch; +- struct dentry *root; +- int err; +- +- err = -ENOMEM; +- root = sb->s_root; +- add_branch = kmalloc(sizeof(*add_branch), GFP_NOFS); +- if (unlikely(!add_branch)) +- goto out; +- +- err = au_hnotify_init_br(add_branch, perm); +- if (unlikely(err)) +- goto out_br; +- +- add_branch->br_wbr = NULL; +- if (au_br_writable(perm)) { +- /* may be freed separately at changing the branch permission */ +- add_branch->br_wbr = kmalloc(sizeof(*add_branch->br_wbr), +- GFP_NOFS); +- if (unlikely(!add_branch->br_wbr)) +- goto out_hnotify; +- } +- +- err = au_sbr_realloc(au_sbi(sb), new_nbranch); +- if (!err) +- err = au_di_realloc(au_di(root), new_nbranch); +- if (!err) +- err = au_ii_realloc(au_ii(root->d_inode), new_nbranch); +- if (!err) +- return add_branch; /* success */ +- +- kfree(add_branch->br_wbr); +- +-out_hnotify: +- au_hnotify_fin_br(add_branch); +-out_br: +- kfree(add_branch); +-out: +- return ERR_PTR(err); +-} +- +-/* +- * test if the branch permission is legal or not. +- */ +-static int test_br(struct inode *inode, int brperm, char *path) +-{ +- int err; +- +- err = (au_br_writable(brperm) && IS_RDONLY(inode)); +- if (!err) +- goto out; +- +- err = -EINVAL; +- pr_err("write permission for readonly mount or inode, %s\n", path); +- +-out: +- return err; +-} +- +-/* +- * returns: +- * 0: success, the caller will add it +- * plus: success, it is already unified, the caller should ignore it +- * minus: error +- */ +-static int test_add(struct super_block *sb, struct au_opt_add *add, int remount) +-{ +- int err; +- aufs_bindex_t bend, bindex; +- struct dentry *root; +- struct inode *inode, *h_inode; +- +- root = sb->s_root; +- bend = au_sbend(sb); +- if (unlikely(bend >= 0 +- && au_find_dbindex(root, add->path.dentry) >= 0)) { +- err = 1; +- if (!remount) { +- err = -EINVAL; +- pr_err("%s duplicated\n", add->pathname); +- } +- goto out; +- } +- +- err = -ENOSPC; /* -E2BIG; */ +- if (unlikely(AUFS_BRANCH_MAX <= add->bindex +- || AUFS_BRANCH_MAX - 1 <= bend)) { +- pr_err("number of branches exceeded %s\n", add->pathname); +- goto out; +- } +- +- err = -EDOM; +- if (unlikely(add->bindex < 0 || bend + 1 < add->bindex)) { +- pr_err("bad index %d\n", add->bindex); +- goto out; +- } +- +- inode = add->path.dentry->d_inode; +- err = -ENOENT; +- if (unlikely(!inode->i_nlink)) { +- pr_err("no existence %s\n", add->pathname); +- goto out; +- } +- +- err = -EINVAL; +- if (unlikely(inode->i_sb == sb)) { +- pr_err("%s must be outside\n", add->pathname); +- goto out; +- } +- +- if (unlikely(au_test_fs_unsuppoted(inode->i_sb))) { +- pr_err("unsupported filesystem, %s (%s)\n", +- add->pathname, au_sbtype(inode->i_sb)); +- goto out; +- } +- +- err = test_br(add->path.dentry->d_inode, add->perm, add->pathname); +- if (unlikely(err)) +- goto out; +- +- if (bend < 0) +- return 0; /* success */ +- +- err = -EINVAL; +- for (bindex = 0; bindex <= bend; bindex++) +- if (unlikely(test_overlap(sb, add->path.dentry, +- au_h_dptr(root, bindex)))) { +- pr_err("%s is overlapped\n", add->pathname); +- goto out; +- } +- +- err = 0; +- if (au_opt_test(au_mntflags(sb), WARN_PERM)) { +- h_inode = au_h_dptr(root, 0)->d_inode; +- if ((h_inode->i_mode & S_IALLUGO) != (inode->i_mode & S_IALLUGO) +- || !uid_eq(h_inode->i_uid, inode->i_uid) +- || !gid_eq(h_inode->i_gid, inode->i_gid)) +- pr_warn("uid/gid/perm %s %u/%u/0%o, %u/%u/0%o\n", +- add->pathname, +- i_uid_read(inode), i_gid_read(inode), +- (inode->i_mode & S_IALLUGO), +- i_uid_read(h_inode), i_gid_read(h_inode), +- (h_inode->i_mode & S_IALLUGO)); +- } +- +-out: +- return err; +-} +- +-/* +- * initialize or clean the whiteouts for an adding branch +- */ +-static int au_br_init_wh(struct super_block *sb, struct au_branch *br, +- int new_perm, struct dentry *h_root) +-{ +- int err, old_perm; +- aufs_bindex_t bindex; +- struct mutex *h_mtx; +- struct au_wbr *wbr; +- struct au_hinode *hdir; +- +- wbr = br->br_wbr; +- old_perm = br->br_perm; +- br->br_perm = new_perm; +- hdir = NULL; +- h_mtx = NULL; +- bindex = au_br_index(sb, br->br_id); +- if (0 <= bindex) { +- hdir = au_hi(sb->s_root->d_inode, bindex); +- au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT); +- } else { +- h_mtx = &h_root->d_inode->i_mutex; +- mutex_lock_nested(h_mtx, AuLsc_I_PARENT); +- } +- if (!wbr) +- err = au_wh_init(h_root, br, sb); +- else { +- wbr_wh_write_lock(wbr); +- err = au_wh_init(h_root, br, sb); +- wbr_wh_write_unlock(wbr); +- } +- if (hdir) +- au_hn_imtx_unlock(hdir); +- else +- mutex_unlock(h_mtx); +- br->br_perm = old_perm; +- +- if (!err && wbr && !au_br_writable(new_perm)) { +- kfree(wbr); +- br->br_wbr = NULL; +- } +- +- return err; +-} +- +-static int au_wbr_init(struct au_branch *br, struct super_block *sb, +- int perm, struct path *path) +-{ +- int err; +- struct kstatfs kst; +- struct au_wbr *wbr; +- struct dentry *h_dentry; +- +- wbr = br->br_wbr; +- au_rw_init(&wbr->wbr_wh_rwsem); +- memset(wbr->wbr_wh, 0, sizeof(wbr->wbr_wh)); +- atomic_set(&wbr->wbr_wh_running, 0); +- wbr->wbr_bytes = 0; +- +- /* +- * a limit for rmdir/rename a dir +- * cf. AUFS_MAX_NAMELEN in include/linux/aufs_type.h +- */ +- err = vfs_statfs(path, &kst); +- if (unlikely(err)) +- goto out; +- err = -EINVAL; +- h_dentry = path->dentry; +- if (kst.f_namelen >= NAME_MAX) +- err = au_br_init_wh(sb, br, perm, h_dentry); +- else +- pr_err("%.*s(%s), unsupported namelen %ld\n", +- AuDLNPair(h_dentry), au_sbtype(h_dentry->d_sb), +- kst.f_namelen); +- +-out: +- return err; +-} +- +-/* intialize a new branch */ +-static int au_br_init(struct au_branch *br, struct super_block *sb, +- struct au_opt_add *add) +-{ +- int err; +- +- err = 0; +- memset(&br->br_xino, 0, sizeof(br->br_xino)); +- mutex_init(&br->br_xino.xi_nondir_mtx); +- br->br_perm = add->perm; +- br->br_mnt = add->path.mnt; /* set first, mntget() later */ +- spin_lock_init(&br->br_dykey_lock); +- memset(br->br_dykey, 0, sizeof(br->br_dykey)); +- atomic_set(&br->br_count, 0); +- br->br_xino_upper = AUFS_XINO_TRUNC_INIT; +- atomic_set(&br->br_xino_running, 0); +- br->br_id = au_new_br_id(sb); +- AuDebugOn(br->br_id < 0); +- +- if (au_br_writable(add->perm)) { +- err = au_wbr_init(br, sb, add->perm, &add->path); +- if (unlikely(err)) +- goto out_err; +- } +- +- if (au_opt_test(au_mntflags(sb), XINO)) { +- err = au_xino_br(sb, br, add->path.dentry->d_inode->i_ino, +- au_sbr(sb, 0)->br_xino.xi_file, /*do_test*/1); +- if (unlikely(err)) { +- AuDebugOn(br->br_xino.xi_file); +- goto out_err; +- } +- } +- +- sysaufs_br_init(br); +- mntget(add->path.mnt); +- goto out; /* success */ +- +-out_err: +- br->br_mnt = NULL; +-out: +- return err; +-} +- +-static void au_br_do_add_brp(struct au_sbinfo *sbinfo, aufs_bindex_t bindex, +- struct au_branch *br, aufs_bindex_t bend, +- aufs_bindex_t amount) +-{ +- struct au_branch **brp; +- +- AuRwMustWriteLock(&sbinfo->si_rwsem); +- +- brp = sbinfo->si_branch + bindex; +- memmove(brp + 1, brp, sizeof(*brp) * amount); +- *brp = br; +- sbinfo->si_bend++; +- if (unlikely(bend < 0)) +- sbinfo->si_bend = 0; +-} +- +-static void au_br_do_add_hdp(struct au_dinfo *dinfo, aufs_bindex_t bindex, +- aufs_bindex_t bend, aufs_bindex_t amount) +-{ +- struct au_hdentry *hdp; +- +- AuRwMustWriteLock(&dinfo->di_rwsem); +- +- hdp = dinfo->di_hdentry + bindex; +- memmove(hdp + 1, hdp, sizeof(*hdp) * amount); +- au_h_dentry_init(hdp); +- dinfo->di_bend++; +- if (unlikely(bend < 0)) +- dinfo->di_bstart = 0; +-} +- +-static void au_br_do_add_hip(struct au_iinfo *iinfo, aufs_bindex_t bindex, +- aufs_bindex_t bend, aufs_bindex_t amount) +-{ +- struct au_hinode *hip; +- +- AuRwMustWriteLock(&iinfo->ii_rwsem); +- +- hip = iinfo->ii_hinode + bindex; +- memmove(hip + 1, hip, sizeof(*hip) * amount); +- hip->hi_inode = NULL; +- au_hn_init(hip); +- iinfo->ii_bend++; +- if (unlikely(bend < 0)) +- iinfo->ii_bstart = 0; +-} +- +-static void au_br_do_add(struct super_block *sb, struct dentry *h_dentry, +- struct au_branch *br, aufs_bindex_t bindex) +-{ +- struct dentry *root; +- struct inode *root_inode; +- aufs_bindex_t bend, amount; +- +- root = sb->s_root; +- root_inode = root->d_inode; +- bend = au_sbend(sb); +- amount = bend + 1 - bindex; +- au_sbilist_lock(); +- au_br_do_add_brp(au_sbi(sb), bindex, br, bend, amount); +- au_br_do_add_hdp(au_di(root), bindex, bend, amount); +- au_br_do_add_hip(au_ii(root_inode), bindex, bend, amount); +- au_set_h_dptr(root, bindex, dget(h_dentry)); +- au_set_h_iptr(root_inode, bindex, au_igrab(h_dentry->d_inode), +- /*flags*/0); +- au_sbilist_unlock(); +-} +- +-int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount) +-{ +- int err; +- aufs_bindex_t bend, add_bindex; +- struct dentry *root, *h_dentry; +- struct inode *root_inode; +- struct au_branch *add_branch; +- +- root = sb->s_root; +- root_inode = root->d_inode; +- IMustLock(root_inode); +- err = test_add(sb, add, remount); +- if (unlikely(err < 0)) +- goto out; +- if (err) { +- err = 0; +- goto out; /* success */ +- } +- +- bend = au_sbend(sb); +- add_branch = au_br_alloc(sb, bend + 2, add->perm); +- err = PTR_ERR(add_branch); +- if (IS_ERR(add_branch)) +- goto out; +- +- err = au_br_init(add_branch, sb, add); +- if (unlikely(err)) { +- au_br_do_free(add_branch); +- goto out; +- } +- +- add_bindex = add->bindex; +- h_dentry = add->path.dentry; +- if (!remount) +- au_br_do_add(sb, h_dentry, add_branch, add_bindex); +- else { +- sysaufs_brs_del(sb, add_bindex); +- au_br_do_add(sb, h_dentry, add_branch, add_bindex); +- sysaufs_brs_add(sb, add_bindex); +- } +- +- if (!add_bindex) { +- au_cpup_attr_all(root_inode, /*force*/1); +- sb->s_maxbytes = h_dentry->d_sb->s_maxbytes; +- } else +- au_add_nlink(root_inode, h_dentry->d_inode); +- +- /* +- * this test/set prevents aufs from handling unnecesary notify events +- * of xino files, in case of re-adding a writable branch which was +- * once detached from aufs. +- */ +- if (au_xino_brid(sb) < 0 +- && au_br_writable(add_branch->br_perm) +- && !au_test_fs_bad_xino(h_dentry->d_sb) +- && add_branch->br_xino.xi_file +- && add_branch->br_xino.xi_file->f_dentry->d_parent == h_dentry) +- au_xino_brid_set(sb, add_branch->br_id); +- +-out: +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* +- * delete a branch +- */ +- +-/* to show the line number, do not make it inlined function */ +-#define AuVerbose(do_info, fmt, ...) do { \ +- if (do_info) \ +- pr_info(fmt, ##__VA_ARGS__); \ +-} while (0) +- +-static int au_test_ibusy(struct inode *inode, aufs_bindex_t bstart, +- aufs_bindex_t bend) +-{ +- return (inode && !S_ISDIR(inode->i_mode)) || bstart == bend; +-} +- +-static int au_test_dbusy(struct dentry *dentry, aufs_bindex_t bstart, +- aufs_bindex_t bend) +-{ +- return au_test_ibusy(dentry->d_inode, bstart, bend); +-} +- +-/* +- * test if the branch is deletable or not. +- */ +-static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex, +- unsigned int sigen, const unsigned int verbose) +-{ +- int err, i, j, ndentry; +- aufs_bindex_t bstart, bend; +- struct au_dcsub_pages dpages; +- struct au_dpage *dpage; +- struct dentry *d; +- +- err = au_dpages_init(&dpages, GFP_NOFS); +- if (unlikely(err)) +- goto out; +- err = au_dcsub_pages(&dpages, root, NULL, NULL); +- if (unlikely(err)) +- goto out_dpages; +- +- for (i = 0; !err && i < dpages.ndpage; i++) { +- dpage = dpages.dpages + i; +- ndentry = dpage->ndentry; +- for (j = 0; !err && j < ndentry; j++) { +- d = dpage->dentries[j]; +- AuDebugOn(!d->d_count); +- if (!au_digen_test(d, sigen)) { +- di_read_lock_child(d, AuLock_IR); +- if (unlikely(au_dbrange_test(d))) { +- di_read_unlock(d, AuLock_IR); +- continue; +- } +- } else { +- di_write_lock_child(d); +- if (unlikely(au_dbrange_test(d))) { +- di_write_unlock(d); +- continue; +- } +- err = au_reval_dpath(d, sigen); +- if (!err) +- di_downgrade_lock(d, AuLock_IR); +- else { +- di_write_unlock(d); +- break; +- } +- } +- +- /* AuDbgDentry(d); */ +- bstart = au_dbstart(d); +- bend = au_dbend(d); +- if (bstart <= bindex +- && bindex <= bend +- && au_h_dptr(d, bindex) +- && au_test_dbusy(d, bstart, bend)) { +- err = -EBUSY; +- AuVerbose(verbose, "busy %.*s\n", AuDLNPair(d)); +- AuDbgDentry(d); +- } +- di_read_unlock(d, AuLock_IR); +- } +- } +- +-out_dpages: +- au_dpages_free(&dpages); +-out: +- return err; +-} +- +-static int test_inode_busy(struct super_block *sb, aufs_bindex_t bindex, +- unsigned int sigen, const unsigned int verbose) +-{ +- int err; +- unsigned long long max, ull; +- struct inode *i, **array; +- aufs_bindex_t bstart, bend; +- +- array = au_iarray_alloc(sb, &max); +- err = PTR_ERR(array); +- if (IS_ERR(array)) +- goto out; +- +- err = 0; +- AuDbg("b%d\n", bindex); +- for (ull = 0; !err && ull < max; ull++) { +- i = array[ull]; +- if (i->i_ino == AUFS_ROOT_INO) +- continue; +- +- /* AuDbgInode(i); */ +- if (au_iigen(i, NULL) == sigen) +- ii_read_lock_child(i); +- else { +- ii_write_lock_child(i); +- err = au_refresh_hinode_self(i); +- au_iigen_dec(i); +- if (!err) +- ii_downgrade_lock(i); +- else { +- ii_write_unlock(i); +- break; +- } +- } +- +- bstart = au_ibstart(i); +- bend = au_ibend(i); +- if (bstart <= bindex +- && bindex <= bend +- && au_h_iptr(i, bindex) +- && au_test_ibusy(i, bstart, bend)) { +- err = -EBUSY; +- AuVerbose(verbose, "busy i%lu\n", i->i_ino); +- AuDbgInode(i); +- } +- ii_read_unlock(i); +- } +- au_iarray_free(array, max); +- +-out: +- return err; +-} +- +-static int test_children_busy(struct dentry *root, aufs_bindex_t bindex, +- const unsigned int verbose) +-{ +- int err; +- unsigned int sigen; +- +- sigen = au_sigen(root->d_sb); +- DiMustNoWaiters(root); +- IiMustNoWaiters(root->d_inode); +- di_write_unlock(root); +- err = test_dentry_busy(root, bindex, sigen, verbose); +- if (!err) +- err = test_inode_busy(root->d_sb, bindex, sigen, verbose); +- di_write_lock_child(root); /* aufs_write_lock() calls ..._child() */ +- +- return err; +-} +- +-static void au_br_do_del_brp(struct au_sbinfo *sbinfo, +- const aufs_bindex_t bindex, +- const aufs_bindex_t bend) +-{ +- struct au_branch **brp, **p; +- +- AuRwMustWriteLock(&sbinfo->si_rwsem); +- +- brp = sbinfo->si_branch + bindex; +- if (bindex < bend) +- memmove(brp, brp + 1, sizeof(*brp) * (bend - bindex)); +- sbinfo->si_branch[0 + bend] = NULL; +- sbinfo->si_bend--; +- +- p = krealloc(sbinfo->si_branch, sizeof(*p) * bend, AuGFP_SBILIST); +- if (p) +- sbinfo->si_branch = p; +- /* harmless error */ +-} +- +-static void au_br_do_del_hdp(struct au_dinfo *dinfo, const aufs_bindex_t bindex, +- const aufs_bindex_t bend) +-{ +- struct au_hdentry *hdp, *p; +- +- AuRwMustWriteLock(&dinfo->di_rwsem); +- +- hdp = dinfo->di_hdentry; +- if (bindex < bend) +- memmove(hdp + bindex, hdp + bindex + 1, +- sizeof(*hdp) * (bend - bindex)); +- hdp[0 + bend].hd_dentry = NULL; +- dinfo->di_bend--; +- +- p = krealloc(hdp, sizeof(*p) * bend, AuGFP_SBILIST); +- if (p) +- dinfo->di_hdentry = p; +- /* harmless error */ +-} +- +-static void au_br_do_del_hip(struct au_iinfo *iinfo, const aufs_bindex_t bindex, +- const aufs_bindex_t bend) +-{ +- struct au_hinode *hip, *p; +- +- AuRwMustWriteLock(&iinfo->ii_rwsem); +- +- hip = iinfo->ii_hinode + bindex; +- if (bindex < bend) +- memmove(hip, hip + 1, sizeof(*hip) * (bend - bindex)); +- iinfo->ii_hinode[0 + bend].hi_inode = NULL; +- au_hn_init(iinfo->ii_hinode + bend); +- iinfo->ii_bend--; +- +- p = krealloc(iinfo->ii_hinode, sizeof(*p) * bend, AuGFP_SBILIST); +- if (p) +- iinfo->ii_hinode = p; +- /* harmless error */ +-} +- +-static void au_br_do_del(struct super_block *sb, aufs_bindex_t bindex, +- struct au_branch *br) +-{ +- aufs_bindex_t bend; +- struct au_sbinfo *sbinfo; +- struct dentry *root, *h_root; +- struct inode *inode, *h_inode; +- struct au_hinode *hinode; +- +- SiMustWriteLock(sb); +- +- root = sb->s_root; +- inode = root->d_inode; +- sbinfo = au_sbi(sb); +- bend = sbinfo->si_bend; +- +- h_root = au_h_dptr(root, bindex); +- hinode = au_hi(inode, bindex); +- h_inode = au_igrab(hinode->hi_inode); +- au_hiput(hinode); +- +- au_sbilist_lock(); +- au_br_do_del_brp(sbinfo, bindex, bend); +- au_br_do_del_hdp(au_di(root), bindex, bend); +- au_br_do_del_hip(au_ii(inode), bindex, bend); +- au_sbilist_unlock(); +- +- dput(h_root); +- iput(h_inode); +- au_br_do_free(br); +-} +- +-int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount) +-{ +- int err, rerr, i; +- unsigned int mnt_flags; +- aufs_bindex_t bindex, bend, br_id; +- unsigned char do_wh, verbose; +- struct au_branch *br; +- struct au_wbr *wbr; +- +- err = 0; +- bindex = au_find_dbindex(sb->s_root, del->h_path.dentry); +- if (bindex < 0) { +- if (remount) +- goto out; /* success */ +- err = -ENOENT; +- pr_err("%s no such branch\n", del->pathname); +- goto out; +- } +- AuDbg("bindex b%d\n", bindex); +- +- err = -EBUSY; +- mnt_flags = au_mntflags(sb); +- verbose = !!au_opt_test(mnt_flags, VERBOSE); +- bend = au_sbend(sb); +- if (unlikely(!bend)) { +- AuVerbose(verbose, "no more branches left\n"); +- goto out; +- } +- br = au_sbr(sb, bindex); +- i = atomic_read(&br->br_count); +- if (unlikely(i)) { +- AuVerbose(verbose, "%d file(s) opened\n", i); +- goto out; +- } +- +- wbr = br->br_wbr; +- do_wh = wbr && (wbr->wbr_whbase || wbr->wbr_plink || wbr->wbr_orph); +- if (do_wh) { +- /* instead of WbrWhMustWriteLock(wbr) */ +- SiMustWriteLock(sb); +- for (i = 0; i < AuBrWh_Last; i++) { +- dput(wbr->wbr_wh[i]); +- wbr->wbr_wh[i] = NULL; +- } +- } +- +- err = test_children_busy(sb->s_root, bindex, verbose); +- if (unlikely(err)) { +- if (do_wh) +- goto out_wh; +- goto out; +- } +- +- err = 0; +- br_id = br->br_id; +- if (!remount) +- au_br_do_del(sb, bindex, br); +- else { +- sysaufs_brs_del(sb, bindex); +- au_br_do_del(sb, bindex, br); +- sysaufs_brs_add(sb, bindex); +- } +- +- if (!bindex) { +- au_cpup_attr_all(sb->s_root->d_inode, /*force*/1); +- sb->s_maxbytes = au_sbr_sb(sb, 0)->s_maxbytes; +- } else +- au_sub_nlink(sb->s_root->d_inode, del->h_path.dentry->d_inode); +- if (au_opt_test(mnt_flags, PLINK)) +- au_plink_half_refresh(sb, br_id); +- +- if (au_xino_brid(sb) == br_id) +- au_xino_brid_set(sb, -1); +- goto out; /* success */ +- +-out_wh: +- /* revert */ +- rerr = au_br_init_wh(sb, br, br->br_perm, del->h_path.dentry); +- if (rerr) +- pr_warn("failed re-creating base whiteout, %s. (%d)\n", +- del->pathname, rerr); +-out: +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static int au_ibusy(struct super_block *sb, struct aufs_ibusy __user *arg) +-{ +- int err; +- aufs_bindex_t bstart, bend; +- struct aufs_ibusy ibusy; +- struct inode *inode, *h_inode; +- +- err = -EPERM; +- if (unlikely(!capable(CAP_SYS_ADMIN))) +- goto out; +- +- err = copy_from_user(&ibusy, arg, sizeof(ibusy)); +- if (!err) +- err = !access_ok(VERIFY_WRITE, &arg->h_ino, sizeof(arg->h_ino)); +- if (unlikely(err)) { +- err = -EFAULT; +- AuTraceErr(err); +- goto out; +- } +- +- err = -EINVAL; +- si_read_lock(sb, AuLock_FLUSH); +- if (unlikely(ibusy.bindex < 0 || ibusy.bindex > au_sbend(sb))) +- goto out_unlock; +- +- err = 0; +- ibusy.h_ino = 0; /* invalid */ +- inode = ilookup(sb, ibusy.ino); +- if (!inode +- || inode->i_ino == AUFS_ROOT_INO +- || is_bad_inode(inode)) +- goto out_unlock; +- +- ii_read_lock_child(inode); +- bstart = au_ibstart(inode); +- bend = au_ibend(inode); +- if (bstart <= ibusy.bindex && ibusy.bindex <= bend) { +- h_inode = au_h_iptr(inode, ibusy.bindex); +- if (h_inode && au_test_ibusy(inode, bstart, bend)) +- ibusy.h_ino = h_inode->i_ino; +- } +- ii_read_unlock(inode); +- iput(inode); +- +-out_unlock: +- si_read_unlock(sb); +- if (!err) { +- err = __put_user(ibusy.h_ino, &arg->h_ino); +- if (unlikely(err)) { +- err = -EFAULT; +- AuTraceErr(err); +- } +- } +-out: +- return err; +-} +- +-long au_ibusy_ioctl(struct file *file, unsigned long arg) +-{ +- return au_ibusy(file->f_dentry->d_sb, (void __user *)arg); +-} +- +-#ifdef CONFIG_COMPAT +-long au_ibusy_compat_ioctl(struct file *file, unsigned long arg) +-{ +- return au_ibusy(file->f_dentry->d_sb, compat_ptr(arg)); +-} +-#endif +- +-/* ---------------------------------------------------------------------- */ +- +-/* +- * change a branch permission +- */ +- +-static void au_warn_ima(void) +-{ +-#ifdef CONFIG_IMA +- /* since it doesn't support mark_files_ro() */ +- AuWarn1("RW -> RO makes IMA to produce wrong message\n"); +-#endif +-} +- +-static int do_need_sigen_inc(int a, int b) +-{ +- return au_br_whable(a) && !au_br_whable(b); +-} +- +-static int need_sigen_inc(int old, int new) +-{ +- return do_need_sigen_inc(old, new) +- || do_need_sigen_inc(new, old); +-} +- +-static unsigned long long au_farray_cb(void *a, +- unsigned long long max __maybe_unused, +- void *arg) +-{ +- unsigned long long n; +- struct file **p, *f; +- struct super_block *sb = arg; +- +- n = 0; +- p = a; +- lg_global_lock(&files_lglock); +- do_file_list_for_each_entry(sb, f) { +- if (au_fi(f) +- && file_count(f) +- && !special_file(f->f_dentry->d_inode->i_mode)) { +- get_file(f); +- *p++ = f; +- n++; +- AuDebugOn(n > max); +- } +- } while_file_list_for_each_entry; +- lg_global_unlock(&files_lglock); +- +- return n; +-} +- +-static struct file **au_farray_alloc(struct super_block *sb, +- unsigned long long *max) +-{ +- *max = atomic_long_read(&au_sbi(sb)->si_nfiles); +- return au_array_alloc(max, au_farray_cb, sb); +-} +- +-static void au_farray_free(struct file **a, unsigned long long max) +-{ +- unsigned long long ull; +- +- for (ull = 0; ull < max; ull++) +- if (a[ull]) +- fput(a[ull]); +- au_array_free(a); +-} +- +-static int au_br_mod_files_ro(struct super_block *sb, aufs_bindex_t bindex) +-{ +- int err, do_warn; +- unsigned int mnt_flags; +- unsigned long long ull, max; +- aufs_bindex_t br_id; +- unsigned char verbose; +- struct file *file, *hf, **array; +- struct inode *inode; +- struct au_hfile *hfile; +- +- mnt_flags = au_mntflags(sb); +- verbose = !!au_opt_test(mnt_flags, VERBOSE); +- +- array = au_farray_alloc(sb, &max); +- err = PTR_ERR(array); +- if (IS_ERR(array)) +- goto out; +- +- do_warn = 0; +- br_id = au_sbr_id(sb, bindex); +- for (ull = 0; ull < max; ull++) { +- file = array[ull]; +- +- /* AuDbg("%.*s\n", AuDLNPair(file->f_dentry)); */ +- fi_read_lock(file); +- if (unlikely(au_test_mmapped(file))) { +- err = -EBUSY; +- AuVerbose(verbose, "mmapped %.*s\n", +- AuDLNPair(file->f_dentry)); +- AuDbgFile(file); +- FiMustNoWaiters(file); +- fi_read_unlock(file); +- goto out_array; +- } +- +- inode = file->f_dentry->d_inode; +- hfile = &au_fi(file)->fi_htop; +- hf = hfile->hf_file; +- if (!S_ISREG(inode->i_mode) +- || !(file->f_mode & FMODE_WRITE) +- || hfile->hf_br->br_id != br_id +- || !(hf->f_mode & FMODE_WRITE)) +- array[ull] = NULL; +- else { +- do_warn = 1; +- get_file(file); +- } +- +- FiMustNoWaiters(file); +- fi_read_unlock(file); +- fput(file); +- } +- +- err = 0; +- if (do_warn) +- au_warn_ima(); +- +- for (ull = 0; ull < max; ull++) { +- file = array[ull]; +- if (!file) +- continue; +- +- /* todo: already flushed? */ +- /* cf. fs/super.c:mark_files_ro() */ +- /* fi_read_lock(file); */ +- hfile = &au_fi(file)->fi_htop; +- hf = hfile->hf_file; +- /* fi_read_unlock(file); */ +- spin_lock(&hf->f_lock); +- hf->f_mode &= ~FMODE_WRITE; +- spin_unlock(&hf->f_lock); +- if (!file_check_writeable(hf)) { +- __mnt_drop_write(hf->f_path.mnt); +- file_release_write(hf); +- } +- } +- +-out_array: +- au_farray_free(array, max); +-out: +- AuTraceErr(err); +- return err; +-} +- +-int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount, +- int *do_refresh) +-{ +- int err, rerr; +- aufs_bindex_t bindex; +- struct path path; +- struct dentry *root; +- struct au_branch *br; +- +- root = sb->s_root; +- bindex = au_find_dbindex(root, mod->h_root); +- if (bindex < 0) { +- if (remount) +- return 0; /* success */ +- err = -ENOENT; +- pr_err("%s no such branch\n", mod->path); +- goto out; +- } +- AuDbg("bindex b%d\n", bindex); +- +- err = test_br(mod->h_root->d_inode, mod->perm, mod->path); +- if (unlikely(err)) +- goto out; +- +- br = au_sbr(sb, bindex); +- if (br->br_perm == mod->perm) +- return 0; /* success */ +- +- if (au_br_writable(br->br_perm)) { +- /* remove whiteout base */ +- err = au_br_init_wh(sb, br, mod->perm, mod->h_root); +- if (unlikely(err)) +- goto out; +- +- if (!au_br_writable(mod->perm)) { +- /* rw --> ro, file might be mmapped */ +- DiMustNoWaiters(root); +- IiMustNoWaiters(root->d_inode); +- di_write_unlock(root); +- err = au_br_mod_files_ro(sb, bindex); +- /* aufs_write_lock() calls ..._child() */ +- di_write_lock_child(root); +- +- if (unlikely(err)) { +- rerr = -ENOMEM; +- br->br_wbr = kmalloc(sizeof(*br->br_wbr), +- GFP_NOFS); +- if (br->br_wbr) { +- path.mnt = br->br_mnt; +- path.dentry = mod->h_root; +- rerr = au_wbr_init(br, sb, br->br_perm, +- &path); +- } +- if (unlikely(rerr)) { +- AuIOErr("nested error %d (%d)\n", +- rerr, err); +- br->br_perm = mod->perm; +- } +- } +- } +- } else if (au_br_writable(mod->perm)) { +- /* ro --> rw */ +- err = -ENOMEM; +- br->br_wbr = kmalloc(sizeof(*br->br_wbr), GFP_NOFS); +- if (br->br_wbr) { +- path.mnt = br->br_mnt; +- path.dentry = mod->h_root; +- err = au_wbr_init(br, sb, mod->perm, &path); +- if (unlikely(err)) { +- kfree(br->br_wbr); +- br->br_wbr = NULL; +- } +- } +- } +- +- if (!err) { +- *do_refresh |= need_sigen_inc(br->br_perm, mod->perm); +- br->br_perm = mod->perm; +- } +- +-out: +- AuTraceErr(err); +- return err; +-} +diff --git a/fs/aufs/branch.h b/fs/aufs/branch.h +deleted file mode 100644 +index d27da79..0000000 +--- a/fs/aufs/branch.h ++++ /dev/null +@@ -1,236 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * branch filesystems and xino for them +- */ +- +-#ifndef __AUFS_BRANCH_H__ +-#define __AUFS_BRANCH_H__ +- +-#ifdef __KERNEL__ +- +-#include +-#include "dynop.h" +-#include "rwsem.h" +-#include "super.h" +- +-/* ---------------------------------------------------------------------- */ +- +-/* a xino file */ +-struct au_xino_file { +- struct file *xi_file; +- struct mutex xi_nondir_mtx; +- +- /* todo: make xino files an array to support huge inode number */ +- +-#ifdef CONFIG_DEBUG_FS +- struct dentry *xi_dbgaufs; +-#endif +-}; +- +-/* members for writable branch only */ +-enum {AuBrWh_BASE, AuBrWh_PLINK, AuBrWh_ORPH, AuBrWh_Last}; +-struct au_wbr { +- struct au_rwsem wbr_wh_rwsem; +- struct dentry *wbr_wh[AuBrWh_Last]; +- atomic_t wbr_wh_running; +-#define wbr_whbase wbr_wh[AuBrWh_BASE] /* whiteout base */ +-#define wbr_plink wbr_wh[AuBrWh_PLINK] /* pseudo-link dir */ +-#define wbr_orph wbr_wh[AuBrWh_ORPH] /* dir for orphans */ +- +- /* mfs mode */ +- unsigned long long wbr_bytes; +-}; +- +-/* ext2 has 3 types of operations at least, ext3 has 4 */ +-#define AuBrDynOp (AuDyLast * 4) +- +-#ifdef CONFIG_AUFS_HFSNOTIFY +-/* support for asynchronous destruction */ +-struct au_br_hfsnotify { +- struct fsnotify_group *hfsn_group; +-}; +-#endif +- +-/* protected by superblock rwsem */ +-struct au_branch { +- struct au_xino_file br_xino; +- +- aufs_bindex_t br_id; +- +- int br_perm; +- struct vfsmount *br_mnt; +- spinlock_t br_dykey_lock; +- struct au_dykey *br_dykey[AuBrDynOp]; +- atomic_t br_count; +- +- struct au_wbr *br_wbr; +- +- /* xino truncation */ +- blkcnt_t br_xino_upper; /* watermark in blocks */ +- atomic_t br_xino_running; +- +-#ifdef CONFIG_AUFS_HFSNOTIFY +- struct au_br_hfsnotify *br_hfsn; +-#endif +- +-#ifdef CONFIG_SYSFS +- /* an entry under sysfs per mount-point */ +- char br_name[8]; +- struct attribute br_attr; +-#endif +-}; +- +-/* ---------------------------------------------------------------------- */ +- +-/* branch permissions and attributes */ +-#define AuBrPerm_RW 1 /* writable, hardlinkable wh */ +-#define AuBrPerm_RO (1 << 1) /* readonly */ +-#define AuBrPerm_RR (1 << 2) /* natively readonly */ +-#define AuBrPerm_Mask (AuBrPerm_RW | AuBrPerm_RO | AuBrPerm_RR) +- +-#define AuBrRAttr_WH (1 << 3) /* whiteout-able */ +- +-#define AuBrWAttr_NoLinkWH (1 << 4) /* un-hardlinkable whiteouts */ +- +-static inline int au_br_writable(int brperm) +-{ +- return brperm & AuBrPerm_RW; +-} +- +-static inline int au_br_whable(int brperm) +-{ +- return brperm & (AuBrPerm_RW | AuBrRAttr_WH); +-} +- +-static inline int au_br_wh_linkable(int brperm) +-{ +- return !(brperm & AuBrWAttr_NoLinkWH); +-} +- +-static inline int au_br_rdonly(struct au_branch *br) +-{ +- return ((br->br_mnt->mnt_sb->s_flags & MS_RDONLY) +- || !au_br_writable(br->br_perm)) +- ? -EROFS : 0; +-} +- +-static inline int au_br_hnotifyable(int brperm __maybe_unused) +-{ +-#ifdef CONFIG_AUFS_HNOTIFY +- return !(brperm & AuBrPerm_RR); +-#else +- return 0; +-#endif +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* branch.c */ +-struct au_sbinfo; +-void au_br_free(struct au_sbinfo *sinfo); +-int au_br_index(struct super_block *sb, aufs_bindex_t br_id); +-struct au_opt_add; +-int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount); +-struct au_opt_del; +-int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount); +-long au_ibusy_ioctl(struct file *file, unsigned long arg); +-#ifdef CONFIG_COMPAT +-long au_ibusy_compat_ioctl(struct file *file, unsigned long arg); +-#endif +-struct au_opt_mod; +-int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount, +- int *do_refresh); +- +-/* xino.c */ +-static const loff_t au_loff_max = LLONG_MAX; +- +-int au_xib_trunc(struct super_block *sb); +-ssize_t xino_fread(au_readf_t func, struct file *file, void *buf, size_t size, +- loff_t *pos); +-ssize_t xino_fwrite(au_writef_t func, struct file *file, void *buf, size_t size, +- loff_t *pos); +-struct file *au_xino_create2(struct file *base_file, struct file *copy_src); +-struct file *au_xino_create(struct super_block *sb, char *fname, int silent); +-ino_t au_xino_new_ino(struct super_block *sb); +-void au_xino_delete_inode(struct inode *inode, const int unlinked); +-int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, +- ino_t ino); +-int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, +- ino_t *ino); +-int au_xino_br(struct super_block *sb, struct au_branch *br, ino_t hino, +- struct file *base_file, int do_test); +-int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex); +- +-struct au_opt_xino; +-int au_xino_set(struct super_block *sb, struct au_opt_xino *xino, int remount); +-void au_xino_clr(struct super_block *sb); +-struct file *au_xino_def(struct super_block *sb); +-int au_xino_path(struct seq_file *seq, struct file *file); +- +-/* ---------------------------------------------------------------------- */ +- +-/* Superblock to branch */ +-static inline +-aufs_bindex_t au_sbr_id(struct super_block *sb, aufs_bindex_t bindex) +-{ +- return au_sbr(sb, bindex)->br_id; +-} +- +-static inline +-struct vfsmount *au_sbr_mnt(struct super_block *sb, aufs_bindex_t bindex) +-{ +- return au_sbr(sb, bindex)->br_mnt; +-} +- +-static inline +-struct super_block *au_sbr_sb(struct super_block *sb, aufs_bindex_t bindex) +-{ +- return au_sbr_mnt(sb, bindex)->mnt_sb; +-} +- +-static inline void au_sbr_put(struct super_block *sb, aufs_bindex_t bindex) +-{ +- atomic_dec(&au_sbr(sb, bindex)->br_count); +-} +- +-static inline int au_sbr_perm(struct super_block *sb, aufs_bindex_t bindex) +-{ +- return au_sbr(sb, bindex)->br_perm; +-} +- +-static inline int au_sbr_whable(struct super_block *sb, aufs_bindex_t bindex) +-{ +- return au_br_whable(au_sbr_perm(sb, bindex)); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* +- * wbr_wh_read_lock, wbr_wh_write_lock +- * wbr_wh_read_unlock, wbr_wh_write_unlock, wbr_wh_downgrade_lock +- */ +-AuSimpleRwsemFuncs(wbr_wh, struct au_wbr *wbr, &wbr->wbr_wh_rwsem); +- +-#define WbrWhMustNoWaiters(wbr) AuRwMustNoWaiters(&wbr->wbr_wh_rwsem) +-#define WbrWhMustAnyLock(wbr) AuRwMustAnyLock(&wbr->wbr_wh_rwsem) +-#define WbrWhMustWriteLock(wbr) AuRwMustWriteLock(&wbr->wbr_wh_rwsem) +- +-#endif /* __KERNEL__ */ +-#endif /* __AUFS_BRANCH_H__ */ +diff --git a/fs/aufs/conf.mk b/fs/aufs/conf.mk +deleted file mode 100644 +index 6c5108d..0000000 +--- a/fs/aufs/conf.mk ++++ /dev/null +@@ -1,38 +0,0 @@ +- +-AuConfStr = CONFIG_AUFS_FS=${CONFIG_AUFS_FS} +- +-define AuConf +-ifdef ${1} +-AuConfStr += ${1}=${${1}} +-endif +-endef +- +-AuConfAll = BRANCH_MAX_127 BRANCH_MAX_511 BRANCH_MAX_1023 BRANCH_MAX_32767 \ +- SBILIST \ +- HNOTIFY HFSNOTIFY \ +- EXPORT INO_T_64 \ +- RDU \ +- PROC_MAP \ +- SP_IATTR \ +- SHWH \ +- BR_RAMFS \ +- BR_FUSE POLL \ +- BR_HFSPLUS \ +- BDEV_LOOP \ +- DEBUG MAGIC_SYSRQ +-$(foreach i, ${AuConfAll}, \ +- $(eval $(call AuConf,CONFIG_AUFS_${i}))) +- +-AuConfName = ${obj}/conf.str +-${AuConfName}.tmp: FORCE +- @echo ${AuConfStr} | tr ' ' '\n' | sed -e 's/^/"/' -e 's/$$/\\n"/' > $@ +-${AuConfName}: ${AuConfName}.tmp +- @diff -q $< $@ > /dev/null 2>&1 || { \ +- echo ' GEN ' $@; \ +- cp -p $< $@; \ +- } +-FORCE: +-clean-files += ${AuConfName} ${AuConfName}.tmp +-${obj}/sysfs.o: ${AuConfName} +- +--include ${srctree}/${src}/conf_priv.mk +diff --git a/fs/aufs/cpup.c b/fs/aufs/cpup.c +deleted file mode 100644 +index 60636df..0000000 +--- a/fs/aufs/cpup.c ++++ /dev/null +@@ -1,1085 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * copy-up functions, see wbr_policy.c for copy-down +- */ +- +-#include +-#include +-#include "aufs.h" +- +-void au_cpup_attr_flags(struct inode *dst, struct inode *src) +-{ +- const unsigned int mask = S_DEAD | S_SWAPFILE | S_PRIVATE +- | S_NOATIME | S_NOCMTIME; +- +- dst->i_flags |= src->i_flags & ~mask; +- if (au_test_fs_notime(dst->i_sb)) +- dst->i_flags |= S_NOATIME | S_NOCMTIME; +-} +- +-void au_cpup_attr_timesizes(struct inode *inode) +-{ +- struct inode *h_inode; +- +- h_inode = au_h_iptr(inode, au_ibstart(inode)); +- fsstack_copy_attr_times(inode, h_inode); +- fsstack_copy_inode_size(inode, h_inode); +-} +- +-void au_cpup_attr_nlink(struct inode *inode, int force) +-{ +- struct inode *h_inode; +- struct super_block *sb; +- aufs_bindex_t bindex, bend; +- +- sb = inode->i_sb; +- bindex = au_ibstart(inode); +- h_inode = au_h_iptr(inode, bindex); +- if (!force +- && !S_ISDIR(h_inode->i_mode) +- && au_opt_test(au_mntflags(sb), PLINK) +- && au_plink_test(inode)) +- return; +- +- /* +- * 0 can happen in revalidating. +- * h_inode->i_mutex is not held, but it is harmless since once i_nlink +- * reaches 0, it will never become positive. +- */ +- set_nlink(inode, h_inode->i_nlink); +- +- /* +- * fewer nlink makes find(1) noisy, but larger nlink doesn't. +- * it may includes whplink directory. +- */ +- if (S_ISDIR(h_inode->i_mode)) { +- bend = au_ibend(inode); +- for (bindex++; bindex <= bend; bindex++) { +- h_inode = au_h_iptr(inode, bindex); +- if (h_inode) +- au_add_nlink(inode, h_inode); +- } +- } +-} +- +-void au_cpup_attr_changeable(struct inode *inode) +-{ +- struct inode *h_inode; +- +- h_inode = au_h_iptr(inode, au_ibstart(inode)); +- inode->i_mode = h_inode->i_mode; +- inode->i_uid = h_inode->i_uid; +- inode->i_gid = h_inode->i_gid; +- au_cpup_attr_timesizes(inode); +- au_cpup_attr_flags(inode, h_inode); +-} +- +-void au_cpup_igen(struct inode *inode, struct inode *h_inode) +-{ +- struct au_iinfo *iinfo = au_ii(inode); +- +- IiMustWriteLock(inode); +- +- iinfo->ii_higen = h_inode->i_generation; +- iinfo->ii_hsb1 = h_inode->i_sb; +-} +- +-void au_cpup_attr_all(struct inode *inode, int force) +-{ +- struct inode *h_inode; +- +- h_inode = au_h_iptr(inode, au_ibstart(inode)); +- au_cpup_attr_changeable(inode); +- if (inode->i_nlink > 0) +- au_cpup_attr_nlink(inode, force); +- inode->i_rdev = h_inode->i_rdev; +- inode->i_blkbits = h_inode->i_blkbits; +- au_cpup_igen(inode, h_inode); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* Note: dt_dentry and dt_h_dentry are not dget/dput-ed */ +- +-/* keep the timestamps of the parent dir when cpup */ +-void au_dtime_store(struct au_dtime *dt, struct dentry *dentry, +- struct path *h_path) +-{ +- struct inode *h_inode; +- +- dt->dt_dentry = dentry; +- dt->dt_h_path = *h_path; +- h_inode = h_path->dentry->d_inode; +- dt->dt_atime = h_inode->i_atime; +- dt->dt_mtime = h_inode->i_mtime; +- /* smp_mb(); */ +-} +- +-void au_dtime_revert(struct au_dtime *dt) +-{ +- struct iattr attr; +- int err; +- +- attr.ia_atime = dt->dt_atime; +- attr.ia_mtime = dt->dt_mtime; +- attr.ia_valid = ATTR_FORCE | ATTR_MTIME | ATTR_MTIME_SET +- | ATTR_ATIME | ATTR_ATIME_SET; +- +- err = vfsub_notify_change(&dt->dt_h_path, &attr); +- if (unlikely(err)) +- pr_warn("restoring timestamps failed(%d). ignored\n", err); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static noinline_for_stack +-int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct dentry *h_src) +-{ +- int err, sbits; +- struct iattr ia; +- struct path h_path; +- struct inode *h_isrc, *h_idst; +- +- h_path.dentry = au_h_dptr(dst, bindex); +- h_idst = h_path.dentry->d_inode; +- h_path.mnt = au_sbr_mnt(dst->d_sb, bindex); +- h_isrc = h_src->d_inode; +- ia.ia_valid = ATTR_FORCE | ATTR_UID | ATTR_GID +- | ATTR_ATIME | ATTR_MTIME +- | ATTR_ATIME_SET | ATTR_MTIME_SET; +- ia.ia_uid = h_isrc->i_uid; +- ia.ia_gid = h_isrc->i_gid; +- ia.ia_atime = h_isrc->i_atime; +- ia.ia_mtime = h_isrc->i_mtime; +- if (h_idst->i_mode != h_isrc->i_mode +- && !S_ISLNK(h_idst->i_mode)) { +- ia.ia_valid |= ATTR_MODE; +- ia.ia_mode = h_isrc->i_mode; +- } +- sbits = !!(h_isrc->i_mode & (S_ISUID | S_ISGID)); +- au_cpup_attr_flags(h_idst, h_isrc); +- err = vfsub_notify_change(&h_path, &ia); +- +- /* is this nfs only? */ +- if (!err && sbits && au_test_nfs(h_path.dentry->d_sb)) { +- ia.ia_valid = ATTR_FORCE | ATTR_MODE; +- ia.ia_mode = h_isrc->i_mode; +- err = vfsub_notify_change(&h_path, &ia); +- } +- +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static int au_do_copy_file(struct file *dst, struct file *src, loff_t len, +- char *buf, unsigned long blksize) +-{ +- int err; +- size_t sz, rbytes, wbytes; +- unsigned char all_zero; +- char *p, *zp; +- struct mutex *h_mtx; +- /* reduce stack usage */ +- struct iattr *ia; +- +- zp = page_address(ZERO_PAGE(0)); +- if (unlikely(!zp)) +- return -ENOMEM; /* possible? */ +- +- err = 0; +- all_zero = 0; +- while (len) { +- AuDbg("len %lld\n", len); +- sz = blksize; +- if (len < blksize) +- sz = len; +- +- rbytes = 0; +- /* todo: signal_pending? */ +- while (!rbytes || err == -EAGAIN || err == -EINTR) { +- rbytes = vfsub_read_k(src, buf, sz, &src->f_pos); +- err = rbytes; +- } +- if (unlikely(err < 0)) +- break; +- +- all_zero = 0; +- if (len >= rbytes && rbytes == blksize) +- all_zero = !memcmp(buf, zp, rbytes); +- if (!all_zero) { +- wbytes = rbytes; +- p = buf; +- while (wbytes) { +- size_t b; +- +- b = vfsub_write_k(dst, p, wbytes, &dst->f_pos); +- err = b; +- /* todo: signal_pending? */ +- if (unlikely(err == -EAGAIN || err == -EINTR)) +- continue; +- if (unlikely(err < 0)) +- break; +- wbytes -= b; +- p += b; +- } +- } else { +- loff_t res; +- +- AuLabel(hole); +- res = vfsub_llseek(dst, rbytes, SEEK_CUR); +- err = res; +- if (unlikely(res < 0)) +- break; +- } +- len -= rbytes; +- err = 0; +- } +- +- /* the last block may be a hole */ +- if (!err && all_zero) { +- AuLabel(last hole); +- +- err = 1; +- if (au_test_nfs(dst->f_dentry->d_sb)) { +- /* nfs requires this step to make last hole */ +- /* is this only nfs? */ +- do { +- /* todo: signal_pending? */ +- err = vfsub_write_k(dst, "\0", 1, &dst->f_pos); +- } while (err == -EAGAIN || err == -EINTR); +- if (err == 1) +- dst->f_pos--; +- } +- +- if (err == 1) { +- ia = (void *)buf; +- ia->ia_size = dst->f_pos; +- ia->ia_valid = ATTR_SIZE | ATTR_FILE; +- ia->ia_file = dst; +- h_mtx = &dst->f_dentry->d_inode->i_mutex; +- mutex_lock_nested(h_mtx, AuLsc_I_CHILD2); +- err = vfsub_notify_change(&dst->f_path, ia); +- mutex_unlock(h_mtx); +- } +- } +- +- return err; +-} +- +-int au_copy_file(struct file *dst, struct file *src, loff_t len) +-{ +- int err; +- unsigned long blksize; +- unsigned char do_kfree; +- char *buf; +- +- err = -ENOMEM; +- blksize = dst->f_dentry->d_sb->s_blocksize; +- if (!blksize || PAGE_SIZE < blksize) +- blksize = PAGE_SIZE; +- AuDbg("blksize %lu\n", blksize); +- do_kfree = (blksize != PAGE_SIZE && blksize >= sizeof(struct iattr *)); +- if (do_kfree) +- buf = kmalloc(blksize, GFP_NOFS); +- else +- buf = (void *)__get_free_page(GFP_NOFS); +- if (unlikely(!buf)) +- goto out; +- +- if (len > (1 << 22)) +- AuDbg("copying a large file %lld\n", (long long)len); +- +- src->f_pos = 0; +- dst->f_pos = 0; +- err = au_do_copy_file(dst, src, len, buf, blksize); +- if (do_kfree) +- kfree(buf); +- else +- free_page((unsigned long)buf); +- +-out: +- return err; +-} +- +-/* +- * to support a sparse file which is opened with O_APPEND, +- * we need to close the file. +- */ +-static int au_cp_regular(struct dentry *dentry, aufs_bindex_t bdst, +- aufs_bindex_t bsrc, loff_t len) +-{ +- int err, i; +- enum { SRC, DST }; +- struct { +- aufs_bindex_t bindex; +- unsigned int flags; +- struct dentry *dentry; +- struct file *file; +- void *label, *label_file; +- } *f, file[] = { +- { +- .bindex = bsrc, +- .flags = O_RDONLY | O_NOATIME | O_LARGEFILE, +- .file = NULL, +- .label = &&out, +- .label_file = &&out_src +- }, +- { +- .bindex = bdst, +- .flags = O_WRONLY | O_NOATIME | O_LARGEFILE, +- .file = NULL, +- .label = &&out_src, +- .label_file = &&out_dst +- } +- }; +- struct super_block *sb; +- +- /* bsrc branch can be ro/rw. */ +- sb = dentry->d_sb; +- f = file; +- for (i = 0; i < 2; i++, f++) { +- f->dentry = au_h_dptr(dentry, f->bindex); +- f->file = au_h_open(dentry, f->bindex, f->flags, /*file*/NULL); +- err = PTR_ERR(f->file); +- if (IS_ERR(f->file)) +- goto *f->label; +- err = -EINVAL; +- if (unlikely(!f->file->f_op)) +- goto *f->label_file; +- } +- +- /* try stopping to update while we copyup */ +- IMustLock(file[SRC].dentry->d_inode); +- err = au_copy_file(file[DST].file, file[SRC].file, len); +- +-out_dst: +- fput(file[DST].file); +- au_sbr_put(sb, file[DST].bindex); +-out_src: +- fput(file[SRC].file); +- au_sbr_put(sb, file[SRC].bindex); +-out: +- return err; +-} +- +-static int au_do_cpup_regular(struct dentry *dentry, aufs_bindex_t bdst, +- aufs_bindex_t bsrc, loff_t len, +- struct inode *h_dir, struct path *h_path) +-{ +- int err, rerr; +- loff_t l; +- +- err = 0; +- l = i_size_read(au_h_iptr(dentry->d_inode, bsrc)); +- if (len == -1 || l < len) +- len = l; +- if (len) +- err = au_cp_regular(dentry, bdst, bsrc, len); +- if (!err) +- goto out; /* success */ +- +- rerr = vfsub_unlink(h_dir, h_path, /*force*/0); +- if (rerr) { +- AuIOErr("failed unlinking cpup-ed %.*s(%d, %d)\n", +- AuDLNPair(h_path->dentry), err, rerr); +- err = -EIO; +- } +- +-out: +- return err; +-} +- +-static int au_do_cpup_symlink(struct path *h_path, struct dentry *h_src, +- struct inode *h_dir) +-{ +- int err, symlen; +- mm_segment_t old_fs; +- union { +- char *k; +- char __user *u; +- } sym; +- +- err = -ENOSYS; +- if (unlikely(!h_src->d_inode->i_op->readlink)) +- goto out; +- +- err = -ENOMEM; +- sym.k = (void *)__get_free_page(GFP_NOFS); +- if (unlikely(!sym.k)) +- goto out; +- +- /* unnecessary to support mmap_sem since symlink is not mmap-able */ +- old_fs = get_fs(); +- set_fs(KERNEL_DS); +- symlen = h_src->d_inode->i_op->readlink(h_src, sym.u, PATH_MAX); +- err = symlen; +- set_fs(old_fs); +- +- if (symlen > 0) { +- sym.k[symlen] = 0; +- err = vfsub_symlink(h_dir, h_path, sym.k); +- } +- free_page((unsigned long)sym.k); +- +-out: +- return err; +-} +- +-/* return with the lower dst inode is locked */ +-static noinline_for_stack +-int cpup_entry(struct dentry *dentry, aufs_bindex_t bdst, +- aufs_bindex_t bsrc, loff_t len, unsigned int flags, +- struct dentry *dst_parent) +-{ +- int err; +- umode_t mode; +- unsigned int mnt_flags; +- unsigned char isdir; +- const unsigned char do_dt = !!au_ftest_cpup(flags, DTIME); +- struct au_dtime dt; +- struct path h_path; +- struct dentry *h_src, *h_dst, *h_parent; +- struct inode *h_inode, *h_dir; +- struct super_block *sb; +- +- /* bsrc branch can be ro/rw. */ +- h_src = au_h_dptr(dentry, bsrc); +- h_inode = h_src->d_inode; +- AuDebugOn(h_inode != au_h_iptr(dentry->d_inode, bsrc)); +- +- /* try stopping to be referenced while we are creating */ +- h_dst = au_h_dptr(dentry, bdst); +- h_parent = h_dst->d_parent; /* dir inode is locked */ +- h_dir = h_parent->d_inode; +- IMustLock(h_dir); +- AuDebugOn(h_parent != h_dst->d_parent); +- +- sb = dentry->d_sb; +- h_path.mnt = au_sbr_mnt(sb, bdst); +- if (do_dt) { +- h_path.dentry = h_parent; +- au_dtime_store(&dt, dst_parent, &h_path); +- } +- h_path.dentry = h_dst; +- +- isdir = 0; +- mode = h_inode->i_mode; +- switch (mode & S_IFMT) { +- case S_IFREG: +- /* try stopping to update while we are referencing */ +- IMustLock(h_inode); +- err = vfsub_create(h_dir, &h_path, mode | S_IWUSR, +- /*want_excl*/true); +- if (!err) +- err = au_do_cpup_regular +- (dentry, bdst, bsrc, len, +- au_h_iptr(dst_parent->d_inode, bdst), &h_path); +- break; +- case S_IFDIR: +- isdir = 1; +- err = vfsub_mkdir(h_dir, &h_path, mode); +- if (!err) { +- /* +- * strange behaviour from the users view, +- * particularry setattr case +- */ +- if (au_ibstart(dst_parent->d_inode) == bdst) +- au_cpup_attr_nlink(dst_parent->d_inode, +- /*force*/1); +- au_cpup_attr_nlink(dentry->d_inode, /*force*/1); +- } +- break; +- case S_IFLNK: +- err = au_do_cpup_symlink(&h_path, h_src, h_dir); +- break; +- case S_IFCHR: +- case S_IFBLK: +- AuDebugOn(!capable(CAP_MKNOD)); +- /*FALLTHROUGH*/ +- case S_IFIFO: +- case S_IFSOCK: +- err = vfsub_mknod(h_dir, &h_path, mode, h_inode->i_rdev); +- break; +- default: +- AuIOErr("Unknown inode type 0%o\n", mode); +- err = -EIO; +- } +- +- mnt_flags = au_mntflags(sb); +- if (!au_opt_test(mnt_flags, UDBA_NONE) +- && !isdir +- && au_opt_test(mnt_flags, XINO) +- && h_inode->i_nlink == 1 +- /* todo: unnecessary? */ +- /* && dentry->d_inode->i_nlink == 1 */ +- && bdst < bsrc +- && !au_ftest_cpup(flags, KEEPLINO)) +- au_xino_write(sb, bsrc, h_inode->i_ino, /*ino*/0); +- /* ignore this error */ +- +- if (do_dt) +- au_dtime_revert(&dt); +- return err; +-} +- +-/* +- * copyup the @dentry from @bsrc to @bdst. +- * the caller must set the both of lower dentries. +- * @len is for truncating when it is -1 copyup the entire file. +- * in link/rename cases, @dst_parent may be different from the real one. +- */ +-static int au_cpup_single(struct dentry *dentry, aufs_bindex_t bdst, +- aufs_bindex_t bsrc, loff_t len, unsigned int flags, +- struct dentry *dst_parent) +-{ +- int err, rerr; +- aufs_bindex_t old_ibstart; +- unsigned char isdir, plink; +- struct au_dtime dt; +- struct path h_path; +- struct dentry *h_src, *h_dst, *h_parent; +- struct inode *dst_inode, *h_dir, *inode; +- struct super_block *sb; +- +- AuDebugOn(bsrc <= bdst); +- +- sb = dentry->d_sb; +- h_path.mnt = au_sbr_mnt(sb, bdst); +- h_dst = au_h_dptr(dentry, bdst); +- h_parent = h_dst->d_parent; /* dir inode is locked */ +- h_dir = h_parent->d_inode; +- IMustLock(h_dir); +- +- h_src = au_h_dptr(dentry, bsrc); +- inode = dentry->d_inode; +- +- if (!dst_parent) +- dst_parent = dget_parent(dentry); +- else +- dget(dst_parent); +- +- plink = !!au_opt_test(au_mntflags(sb), PLINK); +- dst_inode = au_h_iptr(inode, bdst); +- if (dst_inode) { +- if (unlikely(!plink)) { +- err = -EIO; +- AuIOErr("hi%lu(i%lu) exists on b%d " +- "but plink is disabled\n", +- dst_inode->i_ino, inode->i_ino, bdst); +- goto out; +- } +- +- if (dst_inode->i_nlink) { +- const int do_dt = au_ftest_cpup(flags, DTIME); +- +- h_src = au_plink_lkup(inode, bdst); +- err = PTR_ERR(h_src); +- if (IS_ERR(h_src)) +- goto out; +- if (unlikely(!h_src->d_inode)) { +- err = -EIO; +- AuIOErr("i%lu exists on a upper branch " +- "but not pseudo-linked\n", +- inode->i_ino); +- dput(h_src); +- goto out; +- } +- +- if (do_dt) { +- h_path.dentry = h_parent; +- au_dtime_store(&dt, dst_parent, &h_path); +- } +- h_path.dentry = h_dst; +- err = vfsub_link(h_src, h_dir, &h_path); +- if (do_dt) +- au_dtime_revert(&dt); +- dput(h_src); +- goto out; +- } else +- /* todo: cpup_wh_file? */ +- /* udba work */ +- au_update_ibrange(inode, /*do_put_zero*/1); +- } +- +- old_ibstart = au_ibstart(inode); +- err = cpup_entry(dentry, bdst, bsrc, len, flags, dst_parent); +- if (unlikely(err)) +- goto out; +- dst_inode = h_dst->d_inode; +- mutex_lock_nested(&dst_inode->i_mutex, AuLsc_I_CHILD2); +- +- err = cpup_iattr(dentry, bdst, h_src); +- isdir = S_ISDIR(dst_inode->i_mode); +- if (!err) { +- if (bdst < old_ibstart) { +- if (S_ISREG(inode->i_mode)) { +- err = au_dy_iaop(inode, bdst, dst_inode); +- if (unlikely(err)) +- goto out_rev; +- } +- au_set_ibstart(inode, bdst); +- } +- au_set_h_iptr(inode, bdst, au_igrab(dst_inode), +- au_hi_flags(inode, isdir)); +- mutex_unlock(&dst_inode->i_mutex); +- if (!isdir +- && h_src->d_inode->i_nlink > 1 +- && plink) +- au_plink_append(inode, bdst, h_dst); +- goto out; /* success */ +- } +- +- /* revert */ +-out_rev: +- h_path.dentry = h_parent; +- mutex_unlock(&dst_inode->i_mutex); +- au_dtime_store(&dt, dst_parent, &h_path); +- h_path.dentry = h_dst; +- if (!isdir) +- rerr = vfsub_unlink(h_dir, &h_path, /*force*/0); +- else +- rerr = vfsub_rmdir(h_dir, &h_path); +- au_dtime_revert(&dt); +- if (rerr) { +- AuIOErr("failed removing broken entry(%d, %d)\n", err, rerr); +- err = -EIO; +- } +- +-out: +- dput(dst_parent); +- return err; +-} +- +-struct au_cpup_single_args { +- int *errp; +- struct dentry *dentry; +- aufs_bindex_t bdst, bsrc; +- loff_t len; +- unsigned int flags; +- struct dentry *dst_parent; +-}; +- +-static void au_call_cpup_single(void *args) +-{ +- struct au_cpup_single_args *a = args; +- *a->errp = au_cpup_single(a->dentry, a->bdst, a->bsrc, a->len, +- a->flags, a->dst_parent); +-} +- +-/* +- * prevent SIGXFSZ in copy-up. +- * testing CAP_MKNOD is for generic fs, +- * but CAP_FSETID is for xfs only, currently. +- */ +-static int au_cpup_sio_test(struct super_block *sb, umode_t mode) +-{ +- int do_sio; +- +- do_sio = 0; +- if (!au_wkq_test() +- && (!au_sbi(sb)->si_plink_maint_pid +- || au_plink_maint(sb, AuLock_NOPLM))) { +- switch (mode & S_IFMT) { +- case S_IFREG: +- /* no condition about RLIMIT_FSIZE and the file size */ +- do_sio = 1; +- break; +- case S_IFCHR: +- case S_IFBLK: +- do_sio = !capable(CAP_MKNOD); +- break; +- } +- if (!do_sio) +- do_sio = ((mode & (S_ISUID | S_ISGID)) +- && !capable(CAP_FSETID)); +- } +- +- return do_sio; +-} +- +-int au_sio_cpup_single(struct dentry *dentry, aufs_bindex_t bdst, +- aufs_bindex_t bsrc, loff_t len, unsigned int flags, +- struct dentry *dst_parent) +-{ +- int err, wkq_err; +- struct dentry *h_dentry; +- +- h_dentry = au_h_dptr(dentry, bsrc); +- if (!au_cpup_sio_test(dentry->d_sb, h_dentry->d_inode->i_mode)) +- err = au_cpup_single(dentry, bdst, bsrc, len, flags, +- dst_parent); +- else { +- struct au_cpup_single_args args = { +- .errp = &err, +- .dentry = dentry, +- .bdst = bdst, +- .bsrc = bsrc, +- .len = len, +- .flags = flags, +- .dst_parent = dst_parent +- }; +- wkq_err = au_wkq_wait(au_call_cpup_single, &args); +- if (unlikely(wkq_err)) +- err = wkq_err; +- } +- +- return err; +-} +- +-/* +- * copyup the @dentry from the first active lower branch to @bdst, +- * using au_cpup_single(). +- */ +-static int au_cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, +- unsigned int flags) +-{ +- int err; +- aufs_bindex_t bsrc, bend; +- +- bend = au_dbend(dentry); +- for (bsrc = bdst + 1; bsrc <= bend; bsrc++) +- if (au_h_dptr(dentry, bsrc)) +- break; +- +- err = au_lkup_neg(dentry, bdst); +- if (!err) { +- err = au_cpup_single(dentry, bdst, bsrc, len, flags, NULL); +- if (!err) +- return 0; /* success */ +- +- /* revert */ +- au_set_h_dptr(dentry, bdst, NULL); +- au_set_dbstart(dentry, bsrc); +- } +- +- return err; +-} +- +-struct au_cpup_simple_args { +- int *errp; +- struct dentry *dentry; +- aufs_bindex_t bdst; +- loff_t len; +- unsigned int flags; +-}; +- +-static void au_call_cpup_simple(void *args) +-{ +- struct au_cpup_simple_args *a = args; +- *a->errp = au_cpup_simple(a->dentry, a->bdst, a->len, a->flags); +-} +- +-int au_sio_cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, +- unsigned int flags) +-{ +- int err, wkq_err; +- struct dentry *parent; +- struct inode *h_dir; +- +- parent = dget_parent(dentry); +- h_dir = au_h_iptr(parent->d_inode, bdst); +- if (!au_test_h_perm_sio(h_dir, MAY_EXEC | MAY_WRITE) +- && !au_cpup_sio_test(dentry->d_sb, dentry->d_inode->i_mode)) +- err = au_cpup_simple(dentry, bdst, len, flags); +- else { +- struct au_cpup_simple_args args = { +- .errp = &err, +- .dentry = dentry, +- .bdst = bdst, +- .len = len, +- .flags = flags +- }; +- wkq_err = au_wkq_wait(au_call_cpup_simple, &args); +- if (unlikely(wkq_err)) +- err = wkq_err; +- } +- +- dput(parent); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* +- * copyup the deleted file for writing. +- */ +-static int au_do_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst, +- struct dentry *wh_dentry, struct file *file, +- loff_t len) +-{ +- int err; +- aufs_bindex_t bstart; +- struct au_dinfo *dinfo; +- struct dentry *h_d_dst, *h_d_start; +- struct au_hdentry *hdp; +- +- dinfo = au_di(dentry); +- AuRwMustWriteLock(&dinfo->di_rwsem); +- +- bstart = dinfo->di_bstart; +- hdp = dinfo->di_hdentry; +- h_d_dst = hdp[0 + bdst].hd_dentry; +- dinfo->di_bstart = bdst; +- hdp[0 + bdst].hd_dentry = wh_dentry; +- if (file) { +- h_d_start = hdp[0 + bstart].hd_dentry; +- hdp[0 + bstart].hd_dentry = au_hf_top(file)->f_dentry; +- } +- err = au_cpup_single(dentry, bdst, bstart, len, !AuCpup_DTIME, +- /*h_parent*/NULL); +- if (file) { +- if (!err) +- err = au_reopen_nondir(file); +- hdp[0 + bstart].hd_dentry = h_d_start; +- } +- hdp[0 + bdst].hd_dentry = h_d_dst; +- dinfo->di_bstart = bstart; +- +- return err; +-} +- +-static int au_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, +- struct file *file) +-{ +- int err; +- struct au_dtime dt; +- struct dentry *parent, *h_parent, *wh_dentry; +- struct au_branch *br; +- struct path h_path; +- +- br = au_sbr(dentry->d_sb, bdst); +- parent = dget_parent(dentry); +- h_parent = au_h_dptr(parent, bdst); +- wh_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name); +- err = PTR_ERR(wh_dentry); +- if (IS_ERR(wh_dentry)) +- goto out; +- +- h_path.dentry = h_parent; +- h_path.mnt = br->br_mnt; +- au_dtime_store(&dt, parent, &h_path); +- err = au_do_cpup_wh(dentry, bdst, wh_dentry, file, len); +- if (unlikely(err)) +- goto out_wh; +- +- dget(wh_dentry); +- h_path.dentry = wh_dentry; +- if (!S_ISDIR(wh_dentry->d_inode->i_mode)) +- err = vfsub_unlink(h_parent->d_inode, &h_path, /*force*/0); +- else +- err = vfsub_rmdir(h_parent->d_inode, &h_path); +- if (unlikely(err)) { +- AuIOErr("failed remove copied-up tmp file %.*s(%d)\n", +- AuDLNPair(wh_dentry), err); +- err = -EIO; +- } +- au_dtime_revert(&dt); +- au_set_hi_wh(dentry->d_inode, bdst, wh_dentry); +- +-out_wh: +- dput(wh_dentry); +-out: +- dput(parent); +- return err; +-} +- +-struct au_cpup_wh_args { +- int *errp; +- struct dentry *dentry; +- aufs_bindex_t bdst; +- loff_t len; +- struct file *file; +-}; +- +-static void au_call_cpup_wh(void *args) +-{ +- struct au_cpup_wh_args *a = args; +- *a->errp = au_cpup_wh(a->dentry, a->bdst, a->len, a->file); +-} +- +-int au_sio_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, +- struct file *file) +-{ +- int err, wkq_err; +- struct dentry *parent, *h_orph, *h_parent, *h_dentry; +- struct inode *dir, *h_dir, *h_tmpdir, *h_inode; +- struct au_wbr *wbr; +- +- parent = dget_parent(dentry); +- dir = parent->d_inode; +- h_orph = NULL; +- h_parent = NULL; +- h_dir = au_igrab(au_h_iptr(dir, bdst)); +- h_tmpdir = h_dir; +- if (!h_dir->i_nlink) { +- wbr = au_sbr(dentry->d_sb, bdst)->br_wbr; +- h_orph = wbr->wbr_orph; +- +- h_parent = dget(au_h_dptr(parent, bdst)); +- au_set_h_dptr(parent, bdst, dget(h_orph)); +- h_tmpdir = h_orph->d_inode; +- au_set_h_iptr(dir, bdst, au_igrab(h_tmpdir), /*flags*/0); +- +- /* this temporary unlock is safe */ +- if (file) +- h_dentry = au_hf_top(file)->f_dentry; +- else +- h_dentry = au_h_dptr(dentry, au_dbstart(dentry)); +- h_inode = h_dentry->d_inode; +- IMustLock(h_inode); +- mutex_unlock(&h_inode->i_mutex); +- mutex_lock_nested(&h_tmpdir->i_mutex, AuLsc_I_PARENT3); +- mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); +- /* todo: au_h_open_pre()? */ +- } +- +- if (!au_test_h_perm_sio(h_tmpdir, MAY_EXEC | MAY_WRITE) +- && !au_cpup_sio_test(dentry->d_sb, dentry->d_inode->i_mode)) +- err = au_cpup_wh(dentry, bdst, len, file); +- else { +- struct au_cpup_wh_args args = { +- .errp = &err, +- .dentry = dentry, +- .bdst = bdst, +- .len = len, +- .file = file +- }; +- wkq_err = au_wkq_wait(au_call_cpup_wh, &args); +- if (unlikely(wkq_err)) +- err = wkq_err; +- } +- +- if (h_orph) { +- mutex_unlock(&h_tmpdir->i_mutex); +- /* todo: au_h_open_post()? */ +- au_set_h_iptr(dir, bdst, au_igrab(h_dir), /*flags*/0); +- au_set_h_dptr(parent, bdst, h_parent); +- } +- iput(h_dir); +- dput(parent); +- +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* +- * generic routine for both of copy-up and copy-down. +- */ +-/* cf. revalidate function in file.c */ +-int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst, +- int (*cp)(struct dentry *dentry, aufs_bindex_t bdst, +- struct dentry *h_parent, void *arg), +- void *arg) +-{ +- int err; +- struct au_pin pin; +- struct dentry *d, *parent, *h_parent, *real_parent; +- +- err = 0; +- parent = dget_parent(dentry); +- if (IS_ROOT(parent)) +- goto out; +- +- au_pin_init(&pin, dentry, bdst, AuLsc_DI_PARENT2, AuLsc_I_PARENT2, +- au_opt_udba(dentry->d_sb), AuPin_MNT_WRITE); +- +- /* do not use au_dpage */ +- real_parent = parent; +- while (1) { +- dput(parent); +- parent = dget_parent(dentry); +- h_parent = au_h_dptr(parent, bdst); +- if (h_parent) +- goto out; /* success */ +- +- /* find top dir which is necessary to cpup */ +- do { +- d = parent; +- dput(parent); +- parent = dget_parent(d); +- di_read_lock_parent3(parent, !AuLock_IR); +- h_parent = au_h_dptr(parent, bdst); +- di_read_unlock(parent, !AuLock_IR); +- } while (!h_parent); +- +- if (d != real_parent) +- di_write_lock_child3(d); +- +- /* somebody else might create while we were sleeping */ +- if (!au_h_dptr(d, bdst) || !au_h_dptr(d, bdst)->d_inode) { +- if (au_h_dptr(d, bdst)) +- au_update_dbstart(d); +- +- au_pin_set_dentry(&pin, d); +- err = au_do_pin(&pin); +- if (!err) { +- err = cp(d, bdst, h_parent, arg); +- au_unpin(&pin); +- } +- } +- +- if (d != real_parent) +- di_write_unlock(d); +- if (unlikely(err)) +- break; +- } +- +-out: +- dput(parent); +- return err; +-} +- +-static int au_cpup_dir(struct dentry *dentry, aufs_bindex_t bdst, +- struct dentry *h_parent __maybe_unused , +- void *arg __maybe_unused) +-{ +- return au_sio_cpup_simple(dentry, bdst, -1, AuCpup_DTIME); +-} +- +-int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst) +-{ +- return au_cp_dirs(dentry, bdst, au_cpup_dir, NULL); +-} +- +-int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst) +-{ +- int err; +- struct dentry *parent; +- struct inode *dir; +- +- parent = dget_parent(dentry); +- dir = parent->d_inode; +- err = 0; +- if (au_h_iptr(dir, bdst)) +- goto out; +- +- di_read_unlock(parent, AuLock_IR); +- di_write_lock_parent(parent); +- /* someone else might change our inode while we were sleeping */ +- if (!au_h_iptr(dir, bdst)) +- err = au_cpup_dirs(dentry, bdst); +- di_downgrade_lock(parent, AuLock_IR); +- +-out: +- dput(parent); +- return err; +-} +diff --git a/fs/aufs/cpup.h b/fs/aufs/cpup.h +deleted file mode 100644 +index 068fbbd..0000000 +--- a/fs/aufs/cpup.h ++++ /dev/null +@@ -1,81 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * copy-up/down functions +- */ +- +-#ifndef __AUFS_CPUP_H__ +-#define __AUFS_CPUP_H__ +- +-#ifdef __KERNEL__ +- +-#include +- +-struct inode; +-struct file; +- +-void au_cpup_attr_flags(struct inode *dst, struct inode *src); +-void au_cpup_attr_timesizes(struct inode *inode); +-void au_cpup_attr_nlink(struct inode *inode, int force); +-void au_cpup_attr_changeable(struct inode *inode); +-void au_cpup_igen(struct inode *inode, struct inode *h_inode); +-void au_cpup_attr_all(struct inode *inode, int force); +- +-/* ---------------------------------------------------------------------- */ +- +-/* cpup flags */ +-#define AuCpup_DTIME 1 /* do dtime_store/revert */ +-#define AuCpup_KEEPLINO (1 << 1) /* do not clear the lower xino, +- for link(2) */ +-#define au_ftest_cpup(flags, name) ((flags) & AuCpup_##name) +-#define au_fset_cpup(flags, name) \ +- do { (flags) |= AuCpup_##name; } while (0) +-#define au_fclr_cpup(flags, name) \ +- do { (flags) &= ~AuCpup_##name; } while (0) +- +-int au_copy_file(struct file *dst, struct file *src, loff_t len); +-int au_sio_cpup_single(struct dentry *dentry, aufs_bindex_t bdst, +- aufs_bindex_t bsrc, loff_t len, unsigned int flags, +- struct dentry *dst_parent); +-int au_sio_cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, +- unsigned int flags); +-int au_sio_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, +- struct file *file); +- +-int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst, +- int (*cp)(struct dentry *dentry, aufs_bindex_t bdst, +- struct dentry *h_parent, void *arg), +- void *arg); +-int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst); +-int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst); +- +-/* ---------------------------------------------------------------------- */ +- +-/* keep timestamps when copyup */ +-struct au_dtime { +- struct dentry *dt_dentry; +- struct path dt_h_path; +- struct timespec dt_atime, dt_mtime; +-}; +-void au_dtime_store(struct au_dtime *dt, struct dentry *dentry, +- struct path *h_path); +-void au_dtime_revert(struct au_dtime *dt); +- +-#endif /* __KERNEL__ */ +-#endif /* __AUFS_CPUP_H__ */ +diff --git a/fs/aufs/dbgaufs.c b/fs/aufs/dbgaufs.c +deleted file mode 100644 +index 1cea670..0000000 +--- a/fs/aufs/dbgaufs.c ++++ /dev/null +@@ -1,332 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * debugfs interface +- */ +- +-#include +-#include "aufs.h" +- +-#ifndef CONFIG_SYSFS +-#error DEBUG_FS depends upon SYSFS +-#endif +- +-static struct dentry *dbgaufs; +-static const mode_t dbgaufs_mode = S_IRUSR | S_IRGRP | S_IROTH; +- +-/* 20 is max digits length of ulong 64 */ +-struct dbgaufs_arg { +- int n; +- char a[20 * 4]; +-}; +- +-/* +- * common function for all XINO files +- */ +-static int dbgaufs_xi_release(struct inode *inode __maybe_unused, +- struct file *file) +-{ +- kfree(file->private_data); +- return 0; +-} +- +-static int dbgaufs_xi_open(struct file *xf, struct file *file, int do_fcnt) +-{ +- int err; +- struct kstat st; +- struct dbgaufs_arg *p; +- +- err = -ENOMEM; +- p = kmalloc(sizeof(*p), GFP_NOFS); +- if (unlikely(!p)) +- goto out; +- +- err = 0; +- p->n = 0; +- file->private_data = p; +- if (!xf) +- goto out; +- +- err = vfs_getattr(xf->f_vfsmnt, xf->f_dentry, &st); +- if (!err) { +- if (do_fcnt) +- p->n = snprintf +- (p->a, sizeof(p->a), "%ld, %llux%lu %lld\n", +- (long)file_count(xf), st.blocks, st.blksize, +- (long long)st.size); +- else +- p->n = snprintf(p->a, sizeof(p->a), "%llux%lu %lld\n", +- st.blocks, st.blksize, +- (long long)st.size); +- AuDebugOn(p->n >= sizeof(p->a)); +- } else { +- p->n = snprintf(p->a, sizeof(p->a), "err %d\n", err); +- err = 0; +- } +- +-out: +- return err; +- +-} +- +-static ssize_t dbgaufs_xi_read(struct file *file, char __user *buf, +- size_t count, loff_t *ppos) +-{ +- struct dbgaufs_arg *p; +- +- p = file->private_data; +- return simple_read_from_buffer(buf, count, ppos, p->a, p->n); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static int dbgaufs_xib_open(struct inode *inode, struct file *file) +-{ +- int err; +- struct au_sbinfo *sbinfo; +- struct super_block *sb; +- +- sbinfo = inode->i_private; +- sb = sbinfo->si_sb; +- si_noflush_read_lock(sb); +- err = dbgaufs_xi_open(sbinfo->si_xib, file, /*do_fcnt*/0); +- si_read_unlock(sb); +- return err; +-} +- +-static const struct file_operations dbgaufs_xib_fop = { +- .owner = THIS_MODULE, +- .open = dbgaufs_xib_open, +- .release = dbgaufs_xi_release, +- .read = dbgaufs_xi_read +-}; +- +-/* ---------------------------------------------------------------------- */ +- +-#define DbgaufsXi_PREFIX "xi" +- +-static int dbgaufs_xino_open(struct inode *inode, struct file *file) +-{ +- int err; +- long l; +- struct au_sbinfo *sbinfo; +- struct super_block *sb; +- struct file *xf; +- struct qstr *name; +- +- err = -ENOENT; +- xf = NULL; +- name = &file->f_dentry->d_name; +- if (unlikely(name->len < sizeof(DbgaufsXi_PREFIX) +- || memcmp(name->name, DbgaufsXi_PREFIX, +- sizeof(DbgaufsXi_PREFIX) - 1))) +- goto out; +- err = kstrtol(name->name + sizeof(DbgaufsXi_PREFIX) - 1, 10, &l); +- if (unlikely(err)) +- goto out; +- +- sbinfo = inode->i_private; +- sb = sbinfo->si_sb; +- si_noflush_read_lock(sb); +- if (l <= au_sbend(sb)) { +- xf = au_sbr(sb, (aufs_bindex_t)l)->br_xino.xi_file; +- err = dbgaufs_xi_open(xf, file, /*do_fcnt*/1); +- } else +- err = -ENOENT; +- si_read_unlock(sb); +- +-out: +- return err; +-} +- +-static const struct file_operations dbgaufs_xino_fop = { +- .owner = THIS_MODULE, +- .open = dbgaufs_xino_open, +- .release = dbgaufs_xi_release, +- .read = dbgaufs_xi_read +-}; +- +-void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) +-{ +- aufs_bindex_t bend; +- struct au_branch *br; +- struct au_xino_file *xi; +- +- if (!au_sbi(sb)->si_dbgaufs) +- return; +- +- bend = au_sbend(sb); +- for (; bindex <= bend; bindex++) { +- br = au_sbr(sb, bindex); +- xi = &br->br_xino; +- debugfs_remove(xi->xi_dbgaufs); +- xi->xi_dbgaufs = NULL; +- } +-} +- +-void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex) +-{ +- struct au_sbinfo *sbinfo; +- struct dentry *parent; +- struct au_branch *br; +- struct au_xino_file *xi; +- aufs_bindex_t bend; +- char name[sizeof(DbgaufsXi_PREFIX) + 5]; /* "xi" bindex NULL */ +- +- sbinfo = au_sbi(sb); +- parent = sbinfo->si_dbgaufs; +- if (!parent) +- return; +- +- bend = au_sbend(sb); +- for (; bindex <= bend; bindex++) { +- snprintf(name, sizeof(name), DbgaufsXi_PREFIX "%d", bindex); +- br = au_sbr(sb, bindex); +- xi = &br->br_xino; +- AuDebugOn(xi->xi_dbgaufs); +- xi->xi_dbgaufs = debugfs_create_file(name, dbgaufs_mode, parent, +- sbinfo, &dbgaufs_xino_fop); +- /* ignore an error */ +- if (unlikely(!xi->xi_dbgaufs)) +- AuWarn1("failed %s under debugfs\n", name); +- } +-} +- +-/* ---------------------------------------------------------------------- */ +- +-#ifdef CONFIG_AUFS_EXPORT +-static int dbgaufs_xigen_open(struct inode *inode, struct file *file) +-{ +- int err; +- struct au_sbinfo *sbinfo; +- struct super_block *sb; +- +- sbinfo = inode->i_private; +- sb = sbinfo->si_sb; +- si_noflush_read_lock(sb); +- err = dbgaufs_xi_open(sbinfo->si_xigen, file, /*do_fcnt*/0); +- si_read_unlock(sb); +- return err; +-} +- +-static const struct file_operations dbgaufs_xigen_fop = { +- .owner = THIS_MODULE, +- .open = dbgaufs_xigen_open, +- .release = dbgaufs_xi_release, +- .read = dbgaufs_xi_read +-}; +- +-static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo) +-{ +- int err; +- +- /* +- * This function is a dynamic '__init' fucntion actually, +- * so the tiny check for si_rwsem is unnecessary. +- */ +- /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ +- +- err = -EIO; +- sbinfo->si_dbgaufs_xigen = debugfs_create_file +- ("xigen", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, +- &dbgaufs_xigen_fop); +- if (sbinfo->si_dbgaufs_xigen) +- err = 0; +- +- return err; +-} +-#else +-static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo) +-{ +- return 0; +-} +-#endif /* CONFIG_AUFS_EXPORT */ +- +-/* ---------------------------------------------------------------------- */ +- +-void dbgaufs_si_fin(struct au_sbinfo *sbinfo) +-{ +- /* +- * This function is a dynamic '__init' fucntion actually, +- * so the tiny check for si_rwsem is unnecessary. +- */ +- /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ +- +- debugfs_remove_recursive(sbinfo->si_dbgaufs); +- sbinfo->si_dbgaufs = NULL; +- kobject_put(&sbinfo->si_kobj); +-} +- +-int dbgaufs_si_init(struct au_sbinfo *sbinfo) +-{ +- int err; +- char name[SysaufsSiNameLen]; +- +- /* +- * This function is a dynamic '__init' fucntion actually, +- * so the tiny check for si_rwsem is unnecessary. +- */ +- /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ +- +- err = -ENOENT; +- if (!dbgaufs) { +- AuErr1("/debug/aufs is uninitialized\n"); +- goto out; +- } +- +- err = -EIO; +- sysaufs_name(sbinfo, name); +- sbinfo->si_dbgaufs = debugfs_create_dir(name, dbgaufs); +- if (unlikely(!sbinfo->si_dbgaufs)) +- goto out; +- kobject_get(&sbinfo->si_kobj); +- +- sbinfo->si_dbgaufs_xib = debugfs_create_file +- ("xib", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, +- &dbgaufs_xib_fop); +- if (unlikely(!sbinfo->si_dbgaufs_xib)) +- goto out_dir; +- +- err = dbgaufs_xigen_init(sbinfo); +- if (!err) +- goto out; /* success */ +- +-out_dir: +- dbgaufs_si_fin(sbinfo); +-out: +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-void dbgaufs_fin(void) +-{ +- debugfs_remove(dbgaufs); +-} +- +-int __init dbgaufs_init(void) +-{ +- int err; +- +- err = -EIO; +- dbgaufs = debugfs_create_dir(AUFS_NAME, NULL); +- if (dbgaufs) +- err = 0; +- return err; +-} +diff --git a/fs/aufs/dbgaufs.h b/fs/aufs/dbgaufs.h +deleted file mode 100644 +index f418c92d..0000000 +--- a/fs/aufs/dbgaufs.h ++++ /dev/null +@@ -1,49 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * debugfs interface +- */ +- +-#ifndef __DBGAUFS_H__ +-#define __DBGAUFS_H__ +- +-#ifdef __KERNEL__ +- +-struct super_block; +-struct au_sbinfo; +- +-#ifdef CONFIG_DEBUG_FS +-/* dbgaufs.c */ +-void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex); +-void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex); +-void dbgaufs_si_fin(struct au_sbinfo *sbinfo); +-int dbgaufs_si_init(struct au_sbinfo *sbinfo); +-void dbgaufs_fin(void); +-int __init dbgaufs_init(void); +-#else +-AuStubVoid(dbgaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex) +-AuStubVoid(dbgaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex) +-AuStubVoid(dbgaufs_si_fin, struct au_sbinfo *sbinfo) +-AuStubInt0(dbgaufs_si_init, struct au_sbinfo *sbinfo) +-AuStubVoid(dbgaufs_fin, void) +-AuStubInt0(__init dbgaufs_init, void) +-#endif /* CONFIG_DEBUG_FS */ +- +-#endif /* __KERNEL__ */ +-#endif /* __DBGAUFS_H__ */ +diff --git a/fs/aufs/dcsub.c b/fs/aufs/dcsub.c +deleted file mode 100644 +index 5b3d904..0000000 +--- a/fs/aufs/dcsub.c ++++ /dev/null +@@ -1,243 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * sub-routines for dentry cache +- */ +- +-#include "aufs.h" +- +-static void au_dpage_free(struct au_dpage *dpage) +-{ +- int i; +- struct dentry **p; +- +- p = dpage->dentries; +- for (i = 0; i < dpage->ndentry; i++) +- dput(*p++); +- free_page((unsigned long)dpage->dentries); +-} +- +-int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp) +-{ +- int err; +- void *p; +- +- err = -ENOMEM; +- dpages->dpages = kmalloc(sizeof(*dpages->dpages), gfp); +- if (unlikely(!dpages->dpages)) +- goto out; +- +- p = (void *)__get_free_page(gfp); +- if (unlikely(!p)) +- goto out_dpages; +- +- dpages->dpages[0].ndentry = 0; +- dpages->dpages[0].dentries = p; +- dpages->ndpage = 1; +- return 0; /* success */ +- +-out_dpages: +- kfree(dpages->dpages); +-out: +- return err; +-} +- +-void au_dpages_free(struct au_dcsub_pages *dpages) +-{ +- int i; +- struct au_dpage *p; +- +- p = dpages->dpages; +- for (i = 0; i < dpages->ndpage; i++) +- au_dpage_free(p++); +- kfree(dpages->dpages); +-} +- +-static int au_dpages_append(struct au_dcsub_pages *dpages, +- struct dentry *dentry, gfp_t gfp) +-{ +- int err, sz; +- struct au_dpage *dpage; +- void *p; +- +- dpage = dpages->dpages + dpages->ndpage - 1; +- sz = PAGE_SIZE / sizeof(dentry); +- if (unlikely(dpage->ndentry >= sz)) { +- AuLabel(new dpage); +- err = -ENOMEM; +- sz = dpages->ndpage * sizeof(*dpages->dpages); +- p = au_kzrealloc(dpages->dpages, sz, +- sz + sizeof(*dpages->dpages), gfp); +- if (unlikely(!p)) +- goto out; +- +- dpages->dpages = p; +- dpage = dpages->dpages + dpages->ndpage; +- p = (void *)__get_free_page(gfp); +- if (unlikely(!p)) +- goto out; +- +- dpage->ndentry = 0; +- dpage->dentries = p; +- dpages->ndpage++; +- } +- +- AuDebugOn(!dentry->d_count); +- dpage->dentries[dpage->ndentry++] = dget_dlock(dentry); +- return 0; /* success */ +- +-out: +- return err; +-} +- +-int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, +- au_dpages_test test, void *arg) +-{ +- int err; +- struct dentry *this_parent; +- struct list_head *next; +- struct super_block *sb = root->d_sb; +- +- err = 0; +- write_seqlock(&rename_lock); +- this_parent = root; +- spin_lock(&this_parent->d_lock); +-repeat: +- next = this_parent->d_subdirs.next; +-resume: +- if (this_parent->d_sb == sb +- && !IS_ROOT(this_parent) +- && au_di(this_parent) +- && this_parent->d_count +- && (!test || test(this_parent, arg))) { +- err = au_dpages_append(dpages, this_parent, GFP_ATOMIC); +- if (unlikely(err)) +- goto out; +- } +- +- while (next != &this_parent->d_subdirs) { +- struct list_head *tmp = next; +- struct dentry *dentry = list_entry(tmp, struct dentry, +- d_u.d_child); +- +- next = tmp->next; +- spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); +- if (dentry->d_count) { +- if (!list_empty(&dentry->d_subdirs)) { +- spin_unlock(&this_parent->d_lock); +- spin_release(&dentry->d_lock.dep_map, 1, +- _RET_IP_); +- this_parent = dentry; +- spin_acquire(&this_parent->d_lock.dep_map, 0, 1, +- _RET_IP_); +- goto repeat; +- } +- if (dentry->d_sb == sb +- && au_di(dentry) +- && (!test || test(dentry, arg))) +- err = au_dpages_append(dpages, dentry, +- GFP_ATOMIC); +- } +- spin_unlock(&dentry->d_lock); +- if (unlikely(err)) +- goto out; +- } +- +- if (this_parent != root) { +- struct dentry *tmp; +- struct dentry *child; +- +- tmp = this_parent->d_parent; +- rcu_read_lock(); +- spin_unlock(&this_parent->d_lock); +- child = this_parent; +- this_parent = tmp; +- spin_lock(&this_parent->d_lock); +- rcu_read_unlock(); +- next = child->d_u.d_child.next; +- goto resume; +- } +- +-out: +- spin_unlock(&this_parent->d_lock); +- write_sequnlock(&rename_lock); +- return err; +-} +- +-int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry, +- int do_include, au_dpages_test test, void *arg) +-{ +- int err; +- +- err = 0; +- write_seqlock(&rename_lock); +- spin_lock(&dentry->d_lock); +- if (do_include +- && dentry->d_count +- && (!test || test(dentry, arg))) +- err = au_dpages_append(dpages, dentry, GFP_ATOMIC); +- spin_unlock(&dentry->d_lock); +- if (unlikely(err)) +- goto out; +- +- /* +- * vfsmount_lock is unnecessary since this is a traverse in a single +- * mount +- */ +- while (!IS_ROOT(dentry)) { +- dentry = dentry->d_parent; /* rename_lock is locked */ +- spin_lock(&dentry->d_lock); +- if (dentry->d_count +- && (!test || test(dentry, arg))) +- err = au_dpages_append(dpages, dentry, GFP_ATOMIC); +- spin_unlock(&dentry->d_lock); +- if (unlikely(err)) +- break; +- } +- +-out: +- write_sequnlock(&rename_lock); +- return err; +-} +- +-static inline int au_dcsub_dpages_aufs(struct dentry *dentry, void *arg) +-{ +- return au_di(dentry) && dentry->d_sb == arg; +-} +- +-int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages, +- struct dentry *dentry, int do_include) +-{ +- return au_dcsub_pages_rev(dpages, dentry, do_include, +- au_dcsub_dpages_aufs, dentry->d_sb); +-} +- +-int au_test_subdir(struct dentry *d1, struct dentry *d2) +-{ +- struct path path[2] = { +- { +- .dentry = d1 +- }, +- { +- .dentry = d2 +- } +- }; +- +- return path_is_under(path + 0, path + 1); +-} +diff --git a/fs/aufs/dcsub.h b/fs/aufs/dcsub.h +deleted file mode 100644 +index 53dcbd7..0000000 +--- a/fs/aufs/dcsub.h ++++ /dev/null +@@ -1,94 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * sub-routines for dentry cache +- */ +- +-#ifndef __AUFS_DCSUB_H__ +-#define __AUFS_DCSUB_H__ +- +-#ifdef __KERNEL__ +- +-#include +-#include +- +-struct dentry; +- +-struct au_dpage { +- int ndentry; +- struct dentry **dentries; +-}; +- +-struct au_dcsub_pages { +- int ndpage; +- struct au_dpage *dpages; +-}; +- +-/* ---------------------------------------------------------------------- */ +- +-/* dcsub.c */ +-int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp); +-void au_dpages_free(struct au_dcsub_pages *dpages); +-typedef int (*au_dpages_test)(struct dentry *dentry, void *arg); +-int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, +- au_dpages_test test, void *arg); +-int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry, +- int do_include, au_dpages_test test, void *arg); +-int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages, +- struct dentry *dentry, int do_include); +-int au_test_subdir(struct dentry *d1, struct dentry *d2); +- +-/* ---------------------------------------------------------------------- */ +- +-static inline int au_d_hashed_positive(struct dentry *d) +-{ +- int err; +- struct inode *inode = d->d_inode; +- err = 0; +- if (unlikely(d_unhashed(d) || !inode || !inode->i_nlink)) +- err = -ENOENT; +- return err; +-} +- +-static inline int au_d_alive(struct dentry *d) +-{ +- int err; +- struct inode *inode; +- err = 0; +- if (!IS_ROOT(d)) +- err = au_d_hashed_positive(d); +- else { +- inode = d->d_inode; +- if (unlikely(d_unlinked(d) || !inode || !inode->i_nlink)) +- err = -ENOENT; +- } +- return err; +-} +- +-static inline int au_alive_dir(struct dentry *d) +-{ +- int err; +- err = au_d_alive(d); +- if (unlikely(err || IS_DEADDIR(d->d_inode))) +- err = -ENOENT; +- return err; +-} +- +-#endif /* __KERNEL__ */ +-#endif /* __AUFS_DCSUB_H__ */ +diff --git a/fs/aufs/debug.c b/fs/aufs/debug.c +deleted file mode 100644 +index 8e18fcf..0000000 +--- a/fs/aufs/debug.c ++++ /dev/null +@@ -1,493 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * debug print functions +- */ +- +-#include +-#include "aufs.h" +- +-int aufs_debug; +-MODULE_PARM_DESC(debug, "debug print"); +-module_param_named(debug, aufs_debug, int, S_IRUGO | S_IWUSR | S_IWGRP); +- +-char *au_plevel = KERN_DEBUG; +-#define dpri(fmt, ...) do { \ +- if ((au_plevel \ +- && strcmp(au_plevel, KERN_DEBUG)) \ +- || au_debug_test()) \ +- printk("%s" fmt, au_plevel, ##__VA_ARGS__); \ +-} while (0) +- +-/* ---------------------------------------------------------------------- */ +- +-void au_dpri_whlist(struct au_nhash *whlist) +-{ +- unsigned long ul, n; +- struct hlist_head *head; +- struct au_vdir_wh *tpos; +- struct hlist_node *pos; +- +- n = whlist->nh_num; +- head = whlist->nh_head; +- for (ul = 0; ul < n; ul++) { +- hlist_for_each_entry(tpos, pos, head, wh_hash) +- dpri("b%d, %.*s, %d\n", +- tpos->wh_bindex, +- tpos->wh_str.len, tpos->wh_str.name, +- tpos->wh_str.len); +- head++; +- } +-} +- +-void au_dpri_vdir(struct au_vdir *vdir) +-{ +- unsigned long ul; +- union au_vdir_deblk_p p; +- unsigned char *o; +- +- if (!vdir || IS_ERR(vdir)) { +- dpri("err %ld\n", PTR_ERR(vdir)); +- return; +- } +- +- dpri("deblk %u, nblk %lu, deblk %p, last{%lu, %p}, ver %lu\n", +- vdir->vd_deblk_sz, vdir->vd_nblk, vdir->vd_deblk, +- vdir->vd_last.ul, vdir->vd_last.p.deblk, vdir->vd_version); +- for (ul = 0; ul < vdir->vd_nblk; ul++) { +- p.deblk = vdir->vd_deblk[ul]; +- o = p.deblk; +- dpri("[%lu]: %p\n", ul, o); +- } +-} +- +-static int do_pri_inode(aufs_bindex_t bindex, struct inode *inode, int hn, +- struct dentry *wh) +-{ +- char *n = NULL; +- int l = 0; +- +- if (!inode || IS_ERR(inode)) { +- dpri("i%d: err %ld\n", bindex, PTR_ERR(inode)); +- return -1; +- } +- +- /* the type of i_blocks depends upon CONFIG_LSF */ +- BUILD_BUG_ON(sizeof(inode->i_blocks) != sizeof(unsigned long) +- && sizeof(inode->i_blocks) != sizeof(u64)); +- if (wh) { +- n = (void *)wh->d_name.name; +- l = wh->d_name.len; +- } +- +- dpri("i%d: %p, i%lu, %s, cnt %d, nl %u, 0%o, sz %llu, blk %llu," +- " hn %d, ct %lld, np %lu, st 0x%lx, f 0x%x, v %llu, g %x%s%.*s\n", +- bindex, inode, +- inode->i_ino, inode->i_sb ? au_sbtype(inode->i_sb) : "??", +- atomic_read(&inode->i_count), inode->i_nlink, inode->i_mode, +- i_size_read(inode), (unsigned long long)inode->i_blocks, +- hn, (long long)timespec_to_ns(&inode->i_ctime) & 0x0ffff, +- inode->i_mapping ? inode->i_mapping->nrpages : 0, +- inode->i_state, inode->i_flags, inode->i_version, +- inode->i_generation, +- l ? ", wh " : "", l, n); +- return 0; +-} +- +-void au_dpri_inode(struct inode *inode) +-{ +- struct au_iinfo *iinfo; +- aufs_bindex_t bindex; +- int err, hn; +- +- err = do_pri_inode(-1, inode, -1, NULL); +- if (err || !au_test_aufs(inode->i_sb)) +- return; +- +- iinfo = au_ii(inode); +- if (!iinfo) +- return; +- dpri("i-1: bstart %d, bend %d, gen %d\n", +- iinfo->ii_bstart, iinfo->ii_bend, au_iigen(inode, NULL)); +- if (iinfo->ii_bstart < 0) +- return; +- hn = 0; +- for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; bindex++) { +- hn = !!au_hn(iinfo->ii_hinode + bindex); +- do_pri_inode(bindex, iinfo->ii_hinode[0 + bindex].hi_inode, hn, +- iinfo->ii_hinode[0 + bindex].hi_whdentry); +- } +-} +- +-void au_dpri_dalias(struct inode *inode) +-{ +- struct dentry *d; +- struct hlist_node *p; +- +- spin_lock(&inode->i_lock); +- hlist_for_each_entry(d, p, &inode->i_dentry, d_alias) +- au_dpri_dentry(d); +- spin_unlock(&inode->i_lock); +-} +- +-static int do_pri_dentry(aufs_bindex_t bindex, struct dentry *dentry) +-{ +- struct dentry *wh = NULL; +- int hn; +- +- if (!dentry || IS_ERR(dentry)) { +- dpri("d%d: err %ld\n", bindex, PTR_ERR(dentry)); +- return -1; +- } +- /* do not call dget_parent() here */ +- /* note: access d_xxx without d_lock */ +- dpri("d%d: %.*s?/%.*s, %s, cnt %d, flags 0x%x\n", +- bindex, +- AuDLNPair(dentry->d_parent), AuDLNPair(dentry), +- dentry->d_sb ? au_sbtype(dentry->d_sb) : "??", +- dentry->d_count, dentry->d_flags); +- hn = -1; +- if (bindex >= 0 && dentry->d_inode && au_test_aufs(dentry->d_sb)) { +- struct au_iinfo *iinfo = au_ii(dentry->d_inode); +- if (iinfo) { +- hn = !!au_hn(iinfo->ii_hinode + bindex); +- wh = iinfo->ii_hinode[0 + bindex].hi_whdentry; +- } +- } +- do_pri_inode(bindex, dentry->d_inode, hn, wh); +- return 0; +-} +- +-void au_dpri_dentry(struct dentry *dentry) +-{ +- struct au_dinfo *dinfo; +- aufs_bindex_t bindex; +- int err; +- struct au_hdentry *hdp; +- +- err = do_pri_dentry(-1, dentry); +- if (err || !au_test_aufs(dentry->d_sb)) +- return; +- +- dinfo = au_di(dentry); +- if (!dinfo) +- return; +- dpri("d-1: bstart %d, bend %d, bwh %d, bdiropq %d, gen %d\n", +- dinfo->di_bstart, dinfo->di_bend, +- dinfo->di_bwh, dinfo->di_bdiropq, au_digen(dentry)); +- if (dinfo->di_bstart < 0) +- return; +- hdp = dinfo->di_hdentry; +- for (bindex = dinfo->di_bstart; bindex <= dinfo->di_bend; bindex++) +- do_pri_dentry(bindex, hdp[0 + bindex].hd_dentry); +-} +- +-static int do_pri_file(aufs_bindex_t bindex, struct file *file) +-{ +- char a[32]; +- +- if (!file || IS_ERR(file)) { +- dpri("f%d: err %ld\n", bindex, PTR_ERR(file)); +- return -1; +- } +- a[0] = 0; +- if (bindex < 0 +- && file->f_dentry +- && au_test_aufs(file->f_dentry->d_sb) +- && au_fi(file)) +- snprintf(a, sizeof(a), ", gen %d, mmapped %d", +- au_figen(file), atomic_read(&au_fi(file)->fi_mmapped)); +- dpri("f%d: mode 0x%x, flags 0%o, cnt %ld, v %llu, pos %llu%s\n", +- bindex, file->f_mode, file->f_flags, (long)file_count(file), +- file->f_version, file->f_pos, a); +- if (file->f_dentry) +- do_pri_dentry(bindex, file->f_dentry); +- return 0; +-} +- +-void au_dpri_file(struct file *file) +-{ +- struct au_finfo *finfo; +- struct au_fidir *fidir; +- struct au_hfile *hfile; +- aufs_bindex_t bindex; +- int err; +- +- err = do_pri_file(-1, file); +- if (err || !file->f_dentry || !au_test_aufs(file->f_dentry->d_sb)) +- return; +- +- finfo = au_fi(file); +- if (!finfo) +- return; +- if (finfo->fi_btop < 0) +- return; +- fidir = finfo->fi_hdir; +- if (!fidir) +- do_pri_file(finfo->fi_btop, finfo->fi_htop.hf_file); +- else +- for (bindex = finfo->fi_btop; +- bindex >= 0 && bindex <= fidir->fd_bbot; +- bindex++) { +- hfile = fidir->fd_hfile + bindex; +- do_pri_file(bindex, hfile ? hfile->hf_file : NULL); +- } +-} +- +-static int do_pri_br(aufs_bindex_t bindex, struct au_branch *br) +-{ +- struct vfsmount *mnt; +- struct super_block *sb; +- +- if (!br || IS_ERR(br)) +- goto out; +- mnt = br->br_mnt; +- if (!mnt || IS_ERR(mnt)) +- goto out; +- sb = mnt->mnt_sb; +- if (!sb || IS_ERR(sb)) +- goto out; +- +- dpri("s%d: {perm 0x%x, id %d, cnt %d, wbr %p}, " +- "%s, dev 0x%02x%02x, flags 0x%lx, cnt %d, active %d, " +- "xino %d\n", +- bindex, br->br_perm, br->br_id, atomic_read(&br->br_count), +- br->br_wbr, au_sbtype(sb), MAJOR(sb->s_dev), MINOR(sb->s_dev), +- sb->s_flags, sb->s_count, +- atomic_read(&sb->s_active), !!br->br_xino.xi_file); +- return 0; +- +-out: +- dpri("s%d: err %ld\n", bindex, PTR_ERR(br)); +- return -1; +-} +- +-void au_dpri_sb(struct super_block *sb) +-{ +- struct au_sbinfo *sbinfo; +- aufs_bindex_t bindex; +- int err; +- /* to reuduce stack size */ +- struct { +- struct vfsmount mnt; +- struct au_branch fake; +- } *a; +- +- /* this function can be called from magic sysrq */ +- a = kzalloc(sizeof(*a), GFP_ATOMIC); +- if (unlikely(!a)) { +- dpri("no memory\n"); +- return; +- } +- +- a->mnt.mnt_sb = sb; +- a->fake.br_perm = 0; +- a->fake.br_mnt = &a->mnt; +- a->fake.br_xino.xi_file = NULL; +- atomic_set(&a->fake.br_count, 0); +- smp_mb(); /* atomic_set */ +- err = do_pri_br(-1, &a->fake); +- kfree(a); +- dpri("dev 0x%x\n", sb->s_dev); +- if (err || !au_test_aufs(sb)) +- return; +- +- sbinfo = au_sbi(sb); +- if (!sbinfo) +- return; +- dpri("nw %d, gen %u, kobj %d\n", +- atomic_read(&sbinfo->si_nowait.nw_len), sbinfo->si_generation, +- atomic_read(&sbinfo->si_kobj.kref.refcount)); +- for (bindex = 0; bindex <= sbinfo->si_bend; bindex++) +- do_pri_br(bindex, sbinfo->si_branch[0 + bindex]); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-void au_dbg_sleep_jiffy(int jiffy) +-{ +- while (jiffy) +- jiffy = schedule_timeout_uninterruptible(jiffy); +-} +- +-void au_dbg_iattr(struct iattr *ia) +-{ +-#define AuBit(name) \ +- do { \ +- if (ia->ia_valid & ATTR_ ## name) \ +- dpri(#name "\n"); \ +- } while (0) +- AuBit(MODE); +- AuBit(UID); +- AuBit(GID); +- AuBit(SIZE); +- AuBit(ATIME); +- AuBit(MTIME); +- AuBit(CTIME); +- AuBit(ATIME_SET); +- AuBit(MTIME_SET); +- AuBit(FORCE); +- AuBit(ATTR_FLAG); +- AuBit(KILL_SUID); +- AuBit(KILL_SGID); +- AuBit(FILE); +- AuBit(KILL_PRIV); +- AuBit(OPEN); +- AuBit(TIMES_SET); +-#undef AuBit +- dpri("ia_file %p\n", ia->ia_file); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line) +-{ +- struct inode *h_inode, *inode = dentry->d_inode; +- struct dentry *h_dentry; +- aufs_bindex_t bindex, bend, bi; +- +- if (!inode /* || au_di(dentry)->di_lsc == AuLsc_DI_TMP */) +- return; +- +- bend = au_dbend(dentry); +- bi = au_ibend(inode); +- if (bi < bend) +- bend = bi; +- bindex = au_dbstart(dentry); +- bi = au_ibstart(inode); +- if (bi > bindex) +- bindex = bi; +- +- for (; bindex <= bend; bindex++) { +- h_dentry = au_h_dptr(dentry, bindex); +- if (!h_dentry) +- continue; +- h_inode = au_h_iptr(inode, bindex); +- if (unlikely(h_inode != h_dentry->d_inode)) { +- int old = au_debug_test(); +- if (!old) +- au_debug(1); +- AuDbg("b%d, %s:%d\n", bindex, func, line); +- AuDbgDentry(dentry); +- AuDbgInode(inode); +- if (!old) +- au_debug(0); +- BUG(); +- } +- } +-} +- +-void au_dbg_verify_dir_parent(struct dentry *dentry, unsigned int sigen) +-{ +- struct dentry *parent; +- +- parent = dget_parent(dentry); +- AuDebugOn(!S_ISDIR(dentry->d_inode->i_mode)); +- AuDebugOn(IS_ROOT(dentry)); +- AuDebugOn(au_digen_test(parent, sigen)); +- dput(parent); +-} +- +-void au_dbg_verify_nondir_parent(struct dentry *dentry, unsigned int sigen) +-{ +- struct dentry *parent; +- struct inode *inode; +- +- parent = dget_parent(dentry); +- inode = dentry->d_inode; +- AuDebugOn(inode && S_ISDIR(dentry->d_inode->i_mode)); +- AuDebugOn(au_digen_test(parent, sigen)); +- dput(parent); +-} +- +-void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen) +-{ +- int err, i, j; +- struct au_dcsub_pages dpages; +- struct au_dpage *dpage; +- struct dentry **dentries; +- +- err = au_dpages_init(&dpages, GFP_NOFS); +- AuDebugOn(err); +- err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/1); +- AuDebugOn(err); +- for (i = dpages.ndpage - 1; !err && i >= 0; i--) { +- dpage = dpages.dpages + i; +- dentries = dpage->dentries; +- for (j = dpage->ndentry - 1; !err && j >= 0; j--) +- AuDebugOn(au_digen_test(dentries[j], sigen)); +- } +- au_dpages_free(&dpages); +-} +- +-void au_dbg_verify_kthread(void) +-{ +- if (au_wkq_test()) { +- au_dbg_blocked(); +- /* +- * It may be recursive, but udba=notify between two aufs mounts, +- * where a single ro branch is shared, is not a problem. +- */ +- /* WARN_ON(1); */ +- } +-} +- +-/* ---------------------------------------------------------------------- */ +- +-void au_debug_sbinfo_init(struct au_sbinfo *sbinfo __maybe_unused) +-{ +-#ifdef AuForceNoPlink +- au_opt_clr(sbinfo->si_mntflags, PLINK); +-#endif +-#ifdef AuForceNoXino +- au_opt_clr(sbinfo->si_mntflags, XINO); +-#endif +-#ifdef AuForceNoRefrof +- au_opt_clr(sbinfo->si_mntflags, REFROF); +-#endif +-#ifdef AuForceHnotify +- au_opt_set_udba(sbinfo->si_mntflags, UDBA_HNOTIFY); +-#endif +-#ifdef AuForceRd0 +- sbinfo->si_rdblk = 0; +- sbinfo->si_rdhash = 0; +-#endif +-} +- +-int __init au_debug_init(void) +-{ +- aufs_bindex_t bindex; +- struct au_vdir_destr destr; +- +- bindex = -1; +- AuDebugOn(bindex >= 0); +- +- destr.len = -1; +- AuDebugOn(destr.len < NAME_MAX); +- +-#ifdef CONFIG_4KSTACKS +- pr_warn("CONFIG_4KSTACKS is defined.\n"); +-#endif +- +-#ifdef AuForceNoBrs +- sysaufs_brs = 0; +-#endif +- +- return 0; +-} +diff --git a/fs/aufs/debug.h b/fs/aufs/debug.h +deleted file mode 100644 +index 28ff8a7..0000000 +--- a/fs/aufs/debug.h ++++ /dev/null +@@ -1,242 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * debug print functions +- */ +- +-#ifndef __AUFS_DEBUG_H__ +-#define __AUFS_DEBUG_H__ +- +-#ifdef __KERNEL__ +- +-#include +-#include +-#include +- +-#ifdef CONFIG_AUFS_DEBUG +-#define AuDebugOn(a) BUG_ON(a) +- +-/* module parameter */ +-extern int aufs_debug; +-static inline void au_debug(int n) +-{ +- aufs_debug = n; +- smp_mb(); +-} +- +-static inline int au_debug_test(void) +-{ +- return aufs_debug; +-} +-#else +-#define AuDebugOn(a) do {} while (0) +-AuStubVoid(au_debug, int n) +-AuStubInt0(au_debug_test, void) +-#endif /* CONFIG_AUFS_DEBUG */ +- +-/* ---------------------------------------------------------------------- */ +- +-/* debug print */ +- +-#define AuDbg(fmt, ...) do { \ +- if (au_debug_test()) \ +- pr_debug("DEBUG: " fmt, ##__VA_ARGS__); \ +-} while (0) +-#define AuLabel(l) AuDbg(#l "\n") +-#define AuIOErr(fmt, ...) pr_err("I/O Error, " fmt, ##__VA_ARGS__) +-#define AuWarn1(fmt, ...) do { \ +- static unsigned char _c; \ +- if (!_c++) \ +- pr_warn(fmt, ##__VA_ARGS__); \ +-} while (0) +- +-#define AuErr1(fmt, ...) do { \ +- static unsigned char _c; \ +- if (!_c++) \ +- pr_err(fmt, ##__VA_ARGS__); \ +-} while (0) +- +-#define AuIOErr1(fmt, ...) do { \ +- static unsigned char _c; \ +- if (!_c++) \ +- AuIOErr(fmt, ##__VA_ARGS__); \ +-} while (0) +- +-#define AuUnsupportMsg "This operation is not supported." \ +- " Please report this application to aufs-users ML." +-#define AuUnsupport(fmt, ...) do { \ +- pr_err(AuUnsupportMsg "\n" fmt, ##__VA_ARGS__); \ +- dump_stack(); \ +-} while (0) +- +-#define AuTraceErr(e) do { \ +- if (unlikely((e) < 0)) \ +- AuDbg("err %d\n", (int)(e)); \ +-} while (0) +- +-#define AuTraceErrPtr(p) do { \ +- if (IS_ERR(p)) \ +- AuDbg("err %ld\n", PTR_ERR(p)); \ +-} while (0) +- +-/* dirty macros for debug print, use with "%.*s" and caution */ +-#define AuLNPair(qstr) (qstr)->len, (qstr)->name +-#define AuDLNPair(d) AuLNPair(&(d)->d_name) +- +-/* ---------------------------------------------------------------------- */ +- +-struct au_sbinfo; +-struct au_finfo; +-struct dentry; +-#ifdef CONFIG_AUFS_DEBUG +-extern char *au_plevel; +-struct au_nhash; +-void au_dpri_whlist(struct au_nhash *whlist); +-struct au_vdir; +-void au_dpri_vdir(struct au_vdir *vdir); +-struct inode; +-void au_dpri_inode(struct inode *inode); +-void au_dpri_dalias(struct inode *inode); +-void au_dpri_dentry(struct dentry *dentry); +-struct file; +-void au_dpri_file(struct file *filp); +-struct super_block; +-void au_dpri_sb(struct super_block *sb); +- +-void au_dbg_sleep_jiffy(int jiffy); +-struct iattr; +-void au_dbg_iattr(struct iattr *ia); +- +-#define au_dbg_verify_dinode(d) __au_dbg_verify_dinode(d, __func__, __LINE__) +-void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line); +-void au_dbg_verify_dir_parent(struct dentry *dentry, unsigned int sigen); +-void au_dbg_verify_nondir_parent(struct dentry *dentry, unsigned int sigen); +-void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen); +-void au_dbg_verify_kthread(void); +- +-int __init au_debug_init(void); +-void au_debug_sbinfo_init(struct au_sbinfo *sbinfo); +-#define AuDbgWhlist(w) do { \ +- AuDbg(#w "\n"); \ +- au_dpri_whlist(w); \ +-} while (0) +- +-#define AuDbgVdir(v) do { \ +- AuDbg(#v "\n"); \ +- au_dpri_vdir(v); \ +-} while (0) +- +-#define AuDbgInode(i) do { \ +- AuDbg(#i "\n"); \ +- au_dpri_inode(i); \ +-} while (0) +- +-#define AuDbgDAlias(i) do { \ +- AuDbg(#i "\n"); \ +- au_dpri_dalias(i); \ +-} while (0) +- +-#define AuDbgDentry(d) do { \ +- AuDbg(#d "\n"); \ +- au_dpri_dentry(d); \ +-} while (0) +- +-#define AuDbgFile(f) do { \ +- AuDbg(#f "\n"); \ +- au_dpri_file(f); \ +-} while (0) +- +-#define AuDbgSb(sb) do { \ +- AuDbg(#sb "\n"); \ +- au_dpri_sb(sb); \ +-} while (0) +- +-#define AuDbgSleep(sec) do { \ +- AuDbg("sleep %d sec\n", sec); \ +- ssleep(sec); \ +-} while (0) +- +-#define AuDbgSleepJiffy(jiffy) do { \ +- AuDbg("sleep %d jiffies\n", jiffy); \ +- au_dbg_sleep_jiffy(jiffy); \ +-} while (0) +- +-#define AuDbgIAttr(ia) do { \ +- AuDbg("ia_valid 0x%x\n", (ia)->ia_valid); \ +- au_dbg_iattr(ia); \ +-} while (0) +- +-#define AuDbgSym(addr) do { \ +- char sym[KSYM_SYMBOL_LEN]; \ +- sprint_symbol(sym, (unsigned long)addr); \ +- AuDbg("%s\n", sym); \ +-} while (0) +- +-#define AuInfoSym(addr) do { \ +- char sym[KSYM_SYMBOL_LEN]; \ +- sprint_symbol(sym, (unsigned long)addr); \ +- AuInfo("%s\n", sym); \ +-} while (0) +-#else +-AuStubVoid(au_dbg_verify_dinode, struct dentry *dentry) +-AuStubVoid(au_dbg_verify_dir_parent, struct dentry *dentry, unsigned int sigen) +-AuStubVoid(au_dbg_verify_nondir_parent, struct dentry *dentry, +- unsigned int sigen) +-AuStubVoid(au_dbg_verify_gen, struct dentry *parent, unsigned int sigen) +-AuStubVoid(au_dbg_verify_kthread, void) +-AuStubInt0(__init au_debug_init, void) +-AuStubVoid(au_debug_sbinfo_init, struct au_sbinfo *sbinfo) +- +-#define AuDbgWhlist(w) do {} while (0) +-#define AuDbgVdir(v) do {} while (0) +-#define AuDbgInode(i) do {} while (0) +-#define AuDbgDAlias(i) do {} while (0) +-#define AuDbgDentry(d) do {} while (0) +-#define AuDbgFile(f) do {} while (0) +-#define AuDbgSb(sb) do {} while (0) +-#define AuDbgSleep(sec) do {} while (0) +-#define AuDbgSleepJiffy(jiffy) do {} while (0) +-#define AuDbgIAttr(ia) do {} while (0) +-#define AuDbgSym(addr) do {} while (0) +-#define AuInfoSym(addr) do {} while (0) +-#endif /* CONFIG_AUFS_DEBUG */ +- +-/* ---------------------------------------------------------------------- */ +- +-#ifdef CONFIG_AUFS_MAGIC_SYSRQ +-int __init au_sysrq_init(void); +-void au_sysrq_fin(void); +- +-#ifdef CONFIG_HW_CONSOLE +-#define au_dbg_blocked() do { \ +- WARN_ON(1); \ +- handle_sysrq('w'); \ +-} while (0) +-#else +-AuStubVoid(au_dbg_blocked, void) +-#endif +- +-#else +-AuStubInt0(__init au_sysrq_init, void) +-AuStubVoid(au_sysrq_fin, void) +-AuStubVoid(au_dbg_blocked, void) +-#endif /* CONFIG_AUFS_MAGIC_SYSRQ */ +- +-#endif /* __KERNEL__ */ +-#endif /* __AUFS_DEBUG_H__ */ +diff --git a/fs/aufs/dentry.c b/fs/aufs/dentry.c +deleted file mode 100644 +index 3001768..0000000 +--- a/fs/aufs/dentry.c ++++ /dev/null +@@ -1,1060 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * lookup and dentry operations +- */ +- +-#include +-#include "aufs.h" +- +-#define AuLkup_ALLOW_NEG 1 +-#define au_ftest_lkup(flags, name) ((flags) & AuLkup_##name) +-#define au_fset_lkup(flags, name) \ +- do { (flags) |= AuLkup_##name; } while (0) +-#define au_fclr_lkup(flags, name) \ +- do { (flags) &= ~AuLkup_##name; } while (0) +- +-struct au_do_lookup_args { +- unsigned int flags; +- mode_t type; +-}; +- +-/* +- * returns positive/negative dentry, NULL or an error. +- * NULL means whiteout-ed or not-found. +- */ +-static struct dentry* +-au_do_lookup(struct dentry *h_parent, struct dentry *dentry, +- aufs_bindex_t bindex, struct qstr *wh_name, +- struct au_do_lookup_args *args) +-{ +- struct dentry *h_dentry; +- struct inode *h_inode, *inode; +- struct au_branch *br; +- int wh_found, opq; +- unsigned char wh_able; +- const unsigned char allow_neg = !!au_ftest_lkup(args->flags, ALLOW_NEG); +- +- wh_found = 0; +- br = au_sbr(dentry->d_sb, bindex); +- wh_able = !!au_br_whable(br->br_perm); +- if (wh_able) +- wh_found = au_wh_test(h_parent, wh_name, br, /*try_sio*/0); +- h_dentry = ERR_PTR(wh_found); +- if (!wh_found) +- goto real_lookup; +- if (unlikely(wh_found < 0)) +- goto out; +- +- /* We found a whiteout */ +- /* au_set_dbend(dentry, bindex); */ +- au_set_dbwh(dentry, bindex); +- if (!allow_neg) +- return NULL; /* success */ +- +-real_lookup: +- h_dentry = vfsub_lkup_one(&dentry->d_name, h_parent); +- if (IS_ERR(h_dentry)) +- goto out; +- +- h_inode = h_dentry->d_inode; +- if (!h_inode) { +- if (!allow_neg) +- goto out_neg; +- } else if (wh_found +- || (args->type && args->type != (h_inode->i_mode & S_IFMT))) +- goto out_neg; +- +- if (au_dbend(dentry) <= bindex) +- au_set_dbend(dentry, bindex); +- if (au_dbstart(dentry) < 0 || bindex < au_dbstart(dentry)) +- au_set_dbstart(dentry, bindex); +- au_set_h_dptr(dentry, bindex, h_dentry); +- +- inode = dentry->d_inode; +- if (!h_inode || !S_ISDIR(h_inode->i_mode) || !wh_able +- || (inode && !S_ISDIR(inode->i_mode))) +- goto out; /* success */ +- +- mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); +- opq = au_diropq_test(h_dentry, br); +- mutex_unlock(&h_inode->i_mutex); +- if (opq > 0) +- au_set_dbdiropq(dentry, bindex); +- else if (unlikely(opq < 0)) { +- au_set_h_dptr(dentry, bindex, NULL); +- h_dentry = ERR_PTR(opq); +- } +- goto out; +- +-out_neg: +- dput(h_dentry); +- h_dentry = NULL; +-out: +- return h_dentry; +-} +- +-static int au_test_shwh(struct super_block *sb, const struct qstr *name) +-{ +- if (unlikely(!au_opt_test(au_mntflags(sb), SHWH) +- && !strncmp(name->name, AUFS_WH_PFX, AUFS_WH_PFX_LEN))) +- return -EPERM; +- return 0; +-} +- +-/* +- * returns the number of lower positive dentries, +- * otherwise an error. +- * can be called at unlinking with @type is zero. +- */ +-int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type) +-{ +- int npositive, err; +- aufs_bindex_t bindex, btail, bdiropq; +- unsigned char isdir; +- struct qstr whname; +- struct au_do_lookup_args args = { +- .flags = 0, +- .type = type +- }; +- const struct qstr *name = &dentry->d_name; +- struct dentry *parent; +- struct inode *inode; +- +- err = au_test_shwh(dentry->d_sb, name); +- if (unlikely(err)) +- goto out; +- +- err = au_wh_name_alloc(&whname, name); +- if (unlikely(err)) +- goto out; +- +- inode = dentry->d_inode; +- isdir = !!(inode && S_ISDIR(inode->i_mode)); +- if (!type) +- au_fset_lkup(args.flags, ALLOW_NEG); +- +- npositive = 0; +- parent = dget_parent(dentry); +- btail = au_dbtaildir(parent); +- for (bindex = bstart; bindex <= btail; bindex++) { +- struct dentry *h_parent, *h_dentry; +- struct inode *h_inode, *h_dir; +- +- h_dentry = au_h_dptr(dentry, bindex); +- if (h_dentry) { +- if (h_dentry->d_inode) +- npositive++; +- if (type != S_IFDIR) +- break; +- continue; +- } +- h_parent = au_h_dptr(parent, bindex); +- if (!h_parent) +- continue; +- h_dir = h_parent->d_inode; +- if (!h_dir || !S_ISDIR(h_dir->i_mode)) +- continue; +- +- mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT); +- h_dentry = au_do_lookup(h_parent, dentry, bindex, &whname, +- &args); +- mutex_unlock(&h_dir->i_mutex); +- err = PTR_ERR(h_dentry); +- if (IS_ERR(h_dentry)) +- goto out_parent; +- au_fclr_lkup(args.flags, ALLOW_NEG); +- +- if (au_dbwh(dentry) >= 0) +- break; +- if (!h_dentry) +- continue; +- h_inode = h_dentry->d_inode; +- if (!h_inode) +- continue; +- npositive++; +- if (!args.type) +- args.type = h_inode->i_mode & S_IFMT; +- if (args.type != S_IFDIR) +- break; +- else if (isdir) { +- /* the type of lower may be different */ +- bdiropq = au_dbdiropq(dentry); +- if (bdiropq >= 0 && bdiropq <= bindex) +- break; +- } +- } +- +- if (npositive) { +- AuLabel(positive); +- au_update_dbstart(dentry); +- } +- err = npositive; +- if (unlikely(!au_opt_test(au_mntflags(dentry->d_sb), UDBA_NONE) +- && au_dbstart(dentry) < 0)) { +- err = -EIO; +- AuIOErr("both of real entry and whiteout found, %.*s, err %d\n", +- AuDLNPair(dentry), err); +- } +- +-out_parent: +- dput(parent); +- kfree(whname.name); +-out: +- return err; +-} +- +-struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent, +- struct au_branch *br) +-{ +- struct dentry *dentry; +- int wkq_err; +- +- if (!au_test_h_perm_sio(parent->d_inode, MAY_EXEC)) +- dentry = vfsub_lkup_one(name, parent); +- else { +- struct vfsub_lkup_one_args args = { +- .errp = &dentry, +- .name = name, +- .parent = parent +- }; +- +- wkq_err = au_wkq_wait(vfsub_call_lkup_one, &args); +- if (unlikely(wkq_err)) +- dentry = ERR_PTR(wkq_err); +- } +- +- return dentry; +-} +- +-/* +- * lookup @dentry on @bindex which should be negative. +- */ +-int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex) +-{ +- int err; +- struct dentry *parent, *h_parent, *h_dentry; +- +- parent = dget_parent(dentry); +- h_parent = au_h_dptr(parent, bindex); +- h_dentry = au_sio_lkup_one(&dentry->d_name, h_parent, +- au_sbr(dentry->d_sb, bindex)); +- err = PTR_ERR(h_dentry); +- if (IS_ERR(h_dentry)) +- goto out; +- if (unlikely(h_dentry->d_inode)) { +- err = -EIO; +- AuIOErr("%.*s should be negative on b%d.\n", +- AuDLNPair(h_dentry), bindex); +- dput(h_dentry); +- goto out; +- } +- +- err = 0; +- if (bindex < au_dbstart(dentry)) +- au_set_dbstart(dentry, bindex); +- if (au_dbend(dentry) < bindex) +- au_set_dbend(dentry, bindex); +- au_set_h_dptr(dentry, bindex, h_dentry); +- +-out: +- dput(parent); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* subset of struct inode */ +-struct au_iattr { +- unsigned long i_ino; +- /* unsigned int i_nlink; */ +- kuid_t i_uid; +- kgid_t i_gid; +- u64 i_version; +-/* +- loff_t i_size; +- blkcnt_t i_blocks; +-*/ +- umode_t i_mode; +-}; +- +-static void au_iattr_save(struct au_iattr *ia, struct inode *h_inode) +-{ +- ia->i_ino = h_inode->i_ino; +- /* ia->i_nlink = h_inode->i_nlink; */ +- ia->i_uid = h_inode->i_uid; +- ia->i_gid = h_inode->i_gid; +- ia->i_version = h_inode->i_version; +-/* +- ia->i_size = h_inode->i_size; +- ia->i_blocks = h_inode->i_blocks; +-*/ +- ia->i_mode = (h_inode->i_mode & S_IFMT); +-} +- +-static int au_iattr_test(struct au_iattr *ia, struct inode *h_inode) +-{ +- return ia->i_ino != h_inode->i_ino +- /* || ia->i_nlink != h_inode->i_nlink */ +- || !uid_eq(ia->i_uid, h_inode->i_uid) +- || !gid_eq(ia->i_gid, h_inode->i_gid) +- || ia->i_version != h_inode->i_version +-/* +- || ia->i_size != h_inode->i_size +- || ia->i_blocks != h_inode->i_blocks +-*/ +- || ia->i_mode != (h_inode->i_mode & S_IFMT); +-} +- +-static int au_h_verify_dentry(struct dentry *h_dentry, struct dentry *h_parent, +- struct au_branch *br) +-{ +- int err; +- struct au_iattr ia; +- struct inode *h_inode; +- struct dentry *h_d; +- struct super_block *h_sb; +- +- err = 0; +- memset(&ia, -1, sizeof(ia)); +- h_sb = h_dentry->d_sb; +- h_inode = h_dentry->d_inode; +- if (h_inode) +- au_iattr_save(&ia, h_inode); +- else if (au_test_nfs(h_sb) || au_test_fuse(h_sb)) +- /* nfs d_revalidate may return 0 for negative dentry */ +- /* fuse d_revalidate always return 0 for negative dentry */ +- goto out; +- +- /* main purpose is namei.c:cached_lookup() and d_revalidate */ +- h_d = vfsub_lkup_one(&h_dentry->d_name, h_parent); +- err = PTR_ERR(h_d); +- if (IS_ERR(h_d)) +- goto out; +- +- err = 0; +- if (unlikely(h_d != h_dentry +- || h_d->d_inode != h_inode +- || (h_inode && au_iattr_test(&ia, h_inode)))) +- err = au_busy_or_stale(); +- dput(h_d); +- +-out: +- AuTraceErr(err); +- return err; +-} +- +-int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir, +- struct dentry *h_parent, struct au_branch *br) +-{ +- int err; +- +- err = 0; +- if (udba == AuOpt_UDBA_REVAL +- && !au_test_fs_remote(h_dentry->d_sb)) { +- IMustLock(h_dir); +- err = (h_dentry->d_parent->d_inode != h_dir); +- } else if (udba != AuOpt_UDBA_NONE) +- err = au_h_verify_dentry(h_dentry, h_parent, br); +- +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static int au_do_refresh_hdentry(struct dentry *dentry, struct dentry *parent) +-{ +- int err; +- aufs_bindex_t new_bindex, bindex, bend, bwh, bdiropq; +- struct au_hdentry tmp, *p, *q; +- struct au_dinfo *dinfo; +- struct super_block *sb; +- +- DiMustWriteLock(dentry); +- +- sb = dentry->d_sb; +- dinfo = au_di(dentry); +- bend = dinfo->di_bend; +- bwh = dinfo->di_bwh; +- bdiropq = dinfo->di_bdiropq; +- p = dinfo->di_hdentry + dinfo->di_bstart; +- for (bindex = dinfo->di_bstart; bindex <= bend; bindex++, p++) { +- if (!p->hd_dentry) +- continue; +- +- new_bindex = au_br_index(sb, p->hd_id); +- if (new_bindex == bindex) +- continue; +- +- if (dinfo->di_bwh == bindex) +- bwh = new_bindex; +- if (dinfo->di_bdiropq == bindex) +- bdiropq = new_bindex; +- if (new_bindex < 0) { +- au_hdput(p); +- p->hd_dentry = NULL; +- continue; +- } +- +- /* swap two lower dentries, and loop again */ +- q = dinfo->di_hdentry + new_bindex; +- tmp = *q; +- *q = *p; +- *p = tmp; +- if (tmp.hd_dentry) { +- bindex--; +- p--; +- } +- } +- +- dinfo->di_bwh = -1; +- if (bwh >= 0 && bwh <= au_sbend(sb) && au_sbr_whable(sb, bwh)) +- dinfo->di_bwh = bwh; +- +- dinfo->di_bdiropq = -1; +- if (bdiropq >= 0 +- && bdiropq <= au_sbend(sb) +- && au_sbr_whable(sb, bdiropq)) +- dinfo->di_bdiropq = bdiropq; +- +- err = -EIO; +- dinfo->di_bstart = -1; +- dinfo->di_bend = -1; +- bend = au_dbend(parent); +- p = dinfo->di_hdentry; +- for (bindex = 0; bindex <= bend; bindex++, p++) +- if (p->hd_dentry) { +- dinfo->di_bstart = bindex; +- break; +- } +- +- if (dinfo->di_bstart >= 0) { +- p = dinfo->di_hdentry + bend; +- for (bindex = bend; bindex >= 0; bindex--, p--) +- if (p->hd_dentry) { +- dinfo->di_bend = bindex; +- err = 0; +- break; +- } +- } +- +- return err; +-} +- +-static void au_do_hide(struct dentry *dentry) +-{ +- struct inode *inode; +- +- inode = dentry->d_inode; +- if (inode) { +- if (!S_ISDIR(inode->i_mode)) { +- if (inode->i_nlink && !d_unhashed(dentry)) +- drop_nlink(inode); +- } else { +- clear_nlink(inode); +- /* stop next lookup */ +- inode->i_flags |= S_DEAD; +- } +- smp_mb(); /* necessary? */ +- } +- d_drop(dentry); +-} +- +-static int au_hide_children(struct dentry *parent) +-{ +- int err, i, j, ndentry; +- struct au_dcsub_pages dpages; +- struct au_dpage *dpage; +- struct dentry *dentry; +- +- err = au_dpages_init(&dpages, GFP_NOFS); +- if (unlikely(err)) +- goto out; +- err = au_dcsub_pages(&dpages, parent, NULL, NULL); +- if (unlikely(err)) +- goto out_dpages; +- +- /* in reverse order */ +- for (i = dpages.ndpage - 1; i >= 0; i--) { +- dpage = dpages.dpages + i; +- ndentry = dpage->ndentry; +- for (j = ndentry - 1; j >= 0; j--) { +- dentry = dpage->dentries[j]; +- if (dentry != parent) +- au_do_hide(dentry); +- } +- } +- +-out_dpages: +- au_dpages_free(&dpages); +-out: +- return err; +-} +- +-static void au_hide(struct dentry *dentry) +-{ +- int err; +- struct inode *inode; +- +- AuDbgDentry(dentry); +- inode = dentry->d_inode; +- if (inode && S_ISDIR(inode->i_mode)) { +- /* shrink_dcache_parent(dentry); */ +- err = au_hide_children(dentry); +- if (unlikely(err)) +- AuIOErr("%.*s, failed hiding children, ignored %d\n", +- AuDLNPair(dentry), err); +- } +- au_do_hide(dentry); +-} +- +-/* +- * By adding a dirty branch, a cached dentry may be affected in various ways. +- * +- * a dirty branch is added +- * - on the top of layers +- * - in the middle of layers +- * - to the bottom of layers +- * +- * on the added branch there exists +- * - a whiteout +- * - a diropq +- * - a same named entry +- * + exist +- * * negative --> positive +- * * positive --> positive +- * - type is unchanged +- * - type is changed +- * + doesn't exist +- * * negative --> negative +- * * positive --> negative (rejected by au_br_del() for non-dir case) +- * - none +- */ +-static int au_refresh_by_dinfo(struct dentry *dentry, struct au_dinfo *dinfo, +- struct au_dinfo *tmp) +-{ +- int err; +- aufs_bindex_t bindex, bend; +- struct { +- struct dentry *dentry; +- struct inode *inode; +- mode_t mode; +- } orig_h, tmp_h; +- struct au_hdentry *hd; +- struct inode *inode, *h_inode; +- struct dentry *h_dentry; +- +- err = 0; +- AuDebugOn(dinfo->di_bstart < 0); +- orig_h.dentry = dinfo->di_hdentry[dinfo->di_bstart].hd_dentry; +- orig_h.inode = orig_h.dentry->d_inode; +- orig_h.mode = 0; +- if (orig_h.inode) +- orig_h.mode = orig_h.inode->i_mode & S_IFMT; +- memset(&tmp_h, 0, sizeof(tmp_h)); +- if (tmp->di_bstart >= 0) { +- tmp_h.dentry = tmp->di_hdentry[tmp->di_bstart].hd_dentry; +- tmp_h.inode = tmp_h.dentry->d_inode; +- if (tmp_h.inode) +- tmp_h.mode = tmp_h.inode->i_mode & S_IFMT; +- } +- +- inode = dentry->d_inode; +- if (!orig_h.inode) { +- AuDbg("nagative originally\n"); +- if (inode) { +- au_hide(dentry); +- goto out; +- } +- AuDebugOn(inode); +- AuDebugOn(dinfo->di_bstart != dinfo->di_bend); +- AuDebugOn(dinfo->di_bdiropq != -1); +- +- if (!tmp_h.inode) { +- AuDbg("negative --> negative\n"); +- /* should have only one negative lower */ +- if (tmp->di_bstart >= 0 +- && tmp->di_bstart < dinfo->di_bstart) { +- AuDebugOn(tmp->di_bstart != tmp->di_bend); +- AuDebugOn(dinfo->di_bstart != dinfo->di_bend); +- au_set_h_dptr(dentry, dinfo->di_bstart, NULL); +- au_di_cp(dinfo, tmp); +- hd = tmp->di_hdentry + tmp->di_bstart; +- au_set_h_dptr(dentry, tmp->di_bstart, +- dget(hd->hd_dentry)); +- } +- au_dbg_verify_dinode(dentry); +- } else { +- AuDbg("negative --> positive\n"); +- /* +- * similar to the behaviour of creating with bypassing +- * aufs. +- * unhash it in order to force an error in the +- * succeeding create operation. +- * we should not set S_DEAD here. +- */ +- d_drop(dentry); +- /* au_di_swap(tmp, dinfo); */ +- au_dbg_verify_dinode(dentry); +- } +- } else { +- AuDbg("positive originally\n"); +- /* inode may be NULL */ +- AuDebugOn(inode && (inode->i_mode & S_IFMT) != orig_h.mode); +- if (!tmp_h.inode) { +- AuDbg("positive --> negative\n"); +- /* or bypassing aufs */ +- au_hide(dentry); +- if (tmp->di_bwh >= 0 && tmp->di_bwh <= dinfo->di_bstart) +- dinfo->di_bwh = tmp->di_bwh; +- if (inode) +- err = au_refresh_hinode_self(inode); +- au_dbg_verify_dinode(dentry); +- } else if (orig_h.mode == tmp_h.mode) { +- AuDbg("positive --> positive, same type\n"); +- if (!S_ISDIR(orig_h.mode) +- && dinfo->di_bstart > tmp->di_bstart) { +- /* +- * similar to the behaviour of removing and +- * creating. +- */ +- au_hide(dentry); +- if (inode) +- err = au_refresh_hinode_self(inode); +- au_dbg_verify_dinode(dentry); +- } else { +- /* fill empty slots */ +- if (dinfo->di_bstart > tmp->di_bstart) +- dinfo->di_bstart = tmp->di_bstart; +- if (dinfo->di_bend < tmp->di_bend) +- dinfo->di_bend = tmp->di_bend; +- dinfo->di_bwh = tmp->di_bwh; +- dinfo->di_bdiropq = tmp->di_bdiropq; +- hd = tmp->di_hdentry; +- bend = dinfo->di_bend; +- for (bindex = tmp->di_bstart; bindex <= bend; +- bindex++) { +- if (au_h_dptr(dentry, bindex)) +- continue; +- h_dentry = hd[bindex].hd_dentry; +- if (!h_dentry) +- continue; +- h_inode = h_dentry->d_inode; +- AuDebugOn(!h_inode); +- AuDebugOn(orig_h.mode +- != (h_inode->i_mode +- & S_IFMT)); +- au_set_h_dptr(dentry, bindex, +- dget(h_dentry)); +- } +- err = au_refresh_hinode(inode, dentry); +- au_dbg_verify_dinode(dentry); +- } +- } else { +- AuDbg("positive --> positive, different type\n"); +- /* similar to the behaviour of removing and creating */ +- au_hide(dentry); +- if (inode) +- err = au_refresh_hinode_self(inode); +- au_dbg_verify_dinode(dentry); +- } +- } +- +-out: +- return err; +-} +- +-int au_refresh_dentry(struct dentry *dentry, struct dentry *parent) +-{ +- int err, ebrange; +- unsigned int sigen; +- struct au_dinfo *dinfo, *tmp; +- struct super_block *sb; +- struct inode *inode; +- +- DiMustWriteLock(dentry); +- AuDebugOn(IS_ROOT(dentry)); +- AuDebugOn(!parent->d_inode); +- +- sb = dentry->d_sb; +- inode = dentry->d_inode; +- sigen = au_sigen(sb); +- err = au_digen_test(parent, sigen); +- if (unlikely(err)) +- goto out; +- +- dinfo = au_di(dentry); +- err = au_di_realloc(dinfo, au_sbend(sb) + 1); +- if (unlikely(err)) +- goto out; +- ebrange = au_dbrange_test(dentry); +- if (!ebrange) +- ebrange = au_do_refresh_hdentry(dentry, parent); +- +- if (d_unhashed(dentry) || ebrange) { +- AuDebugOn(au_dbstart(dentry) < 0 && au_dbend(dentry) >= 0); +- if (inode) +- err = au_refresh_hinode_self(inode); +- au_dbg_verify_dinode(dentry); +- if (!err) +- goto out_dgen; /* success */ +- goto out; +- } +- +- /* temporary dinfo */ +- AuDbgDentry(dentry); +- err = -ENOMEM; +- tmp = au_di_alloc(sb, AuLsc_DI_TMP); +- if (unlikely(!tmp)) +- goto out; +- au_di_swap(tmp, dinfo); +- /* returns the number of positive dentries */ +- /* +- * if current working dir is removed, it returns an error. +- * but the dentry is legal. +- */ +- err = au_lkup_dentry(dentry, /*bstart*/0, /*type*/0); +- AuDbgDentry(dentry); +- au_di_swap(tmp, dinfo); +- if (err == -ENOENT) +- err = 0; +- if (err >= 0) { +- /* compare/refresh by dinfo */ +- AuDbgDentry(dentry); +- err = au_refresh_by_dinfo(dentry, dinfo, tmp); +- au_dbg_verify_dinode(dentry); +- AuTraceErr(err); +- } +- au_rw_write_unlock(&tmp->di_rwsem); +- au_di_free(tmp); +- if (unlikely(err)) +- goto out; +- +-out_dgen: +- au_update_digen(dentry); +-out: +- if (unlikely(err && !(dentry->d_flags & DCACHE_NFSFS_RENAMED))) { +- AuIOErr("failed refreshing %.*s, %d\n", +- AuDLNPair(dentry), err); +- AuDbgDentry(dentry); +- } +- AuTraceErr(err); +- return err; +-} +- +-static int au_do_h_d_reval(struct dentry *h_dentry, unsigned int flags, +- struct dentry *dentry, aufs_bindex_t bindex) +-{ +- int err, valid; +- +- err = 0; +- if (!(h_dentry->d_flags & DCACHE_OP_REVALIDATE)) +- goto out; +- +- AuDbg("b%d\n", bindex); +- /* +- * gave up supporting LOOKUP_CREATE/OPEN for lower fs, +- * due to whiteout and branch permission. +- */ +- flags &= ~(/*LOOKUP_PARENT |*/ LOOKUP_OPEN | LOOKUP_CREATE +- | LOOKUP_FOLLOW | LOOKUP_EXCL); +- /* it may return tri-state */ +- valid = h_dentry->d_op->d_revalidate(h_dentry, flags); +- +- if (unlikely(valid < 0)) +- err = valid; +- else if (!valid) +- err = -EINVAL; +- +-out: +- AuTraceErr(err); +- return err; +-} +- +-/* todo: remove this */ +-static int h_d_revalidate(struct dentry *dentry, struct inode *inode, +- unsigned int flags, int do_udba) +-{ +- int err; +- umode_t mode, h_mode; +- aufs_bindex_t bindex, btail, bstart, ibs, ibe; +- unsigned char plus, unhashed, is_root, h_plus; +- struct inode *h_inode, *h_cached_inode; +- struct dentry *h_dentry; +- struct qstr *name, *h_name; +- +- err = 0; +- plus = 0; +- mode = 0; +- ibs = -1; +- ibe = -1; +- unhashed = !!d_unhashed(dentry); +- is_root = !!IS_ROOT(dentry); +- name = &dentry->d_name; +- +- /* +- * Theoretically, REVAL test should be unnecessary in case of +- * {FS,I}NOTIFY. +- * But {fs,i}notify doesn't fire some necessary events, +- * IN_ATTRIB for atime/nlink/pageio +- * IN_DELETE for NFS dentry +- * Let's do REVAL test too. +- */ +- if (do_udba && inode) { +- mode = (inode->i_mode & S_IFMT); +- plus = (inode->i_nlink > 0); +- ibs = au_ibstart(inode); +- ibe = au_ibend(inode); +- } +- +- bstart = au_dbstart(dentry); +- btail = bstart; +- if (inode && S_ISDIR(inode->i_mode)) +- btail = au_dbtaildir(dentry); +- for (bindex = bstart; bindex <= btail; bindex++) { +- h_dentry = au_h_dptr(dentry, bindex); +- if (!h_dentry) +- continue; +- +- AuDbg("b%d, %.*s\n", bindex, AuDLNPair(h_dentry)); +- spin_lock(&h_dentry->d_lock); +- h_name = &h_dentry->d_name; +- if (unlikely(do_udba +- && !is_root +- && (unhashed != !!d_unhashed(h_dentry) +- || name->len != h_name->len +- || memcmp(name->name, h_name->name, name->len)) +- )) { +- AuDbg("unhash 0x%x 0x%x, %.*s %.*s\n", +- unhashed, d_unhashed(h_dentry), +- AuDLNPair(dentry), AuDLNPair(h_dentry)); +- spin_unlock(&h_dentry->d_lock); +- goto err; +- } +- spin_unlock(&h_dentry->d_lock); +- +- err = au_do_h_d_reval(h_dentry, flags, dentry, bindex); +- if (unlikely(err)) +- /* do not goto err, to keep the errno */ +- break; +- +- /* todo: plink too? */ +- if (!do_udba) +- continue; +- +- /* UDBA tests */ +- h_inode = h_dentry->d_inode; +- if (unlikely(!!inode != !!h_inode)) +- goto err; +- +- h_plus = plus; +- h_mode = mode; +- h_cached_inode = h_inode; +- if (h_inode) { +- h_mode = (h_inode->i_mode & S_IFMT); +- h_plus = (h_inode->i_nlink > 0); +- } +- if (inode && ibs <= bindex && bindex <= ibe) +- h_cached_inode = au_h_iptr(inode, bindex); +- +- if (unlikely(plus != h_plus +- || mode != h_mode +- || h_cached_inode != h_inode)) +- goto err; +- continue; +- +- err: +- err = -EINVAL; +- break; +- } +- +- return err; +-} +- +-/* todo: consolidate with do_refresh() and au_reval_for_attr() */ +-static int simple_reval_dpath(struct dentry *dentry, unsigned int sigen) +-{ +- int err; +- struct dentry *parent; +- +- if (!au_digen_test(dentry, sigen)) +- return 0; +- +- parent = dget_parent(dentry); +- di_read_lock_parent(parent, AuLock_IR); +- AuDebugOn(au_digen_test(parent, sigen)); +- au_dbg_verify_gen(parent, sigen); +- err = au_refresh_dentry(dentry, parent); +- di_read_unlock(parent, AuLock_IR); +- dput(parent); +- AuTraceErr(err); +- return err; +-} +- +-int au_reval_dpath(struct dentry *dentry, unsigned int sigen) +-{ +- int err; +- struct dentry *d, *parent; +- struct inode *inode; +- +- if (!au_ftest_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR)) +- return simple_reval_dpath(dentry, sigen); +- +- /* slow loop, keep it simple and stupid */ +- /* cf: au_cpup_dirs() */ +- err = 0; +- parent = NULL; +- while (au_digen_test(dentry, sigen)) { +- d = dentry; +- while (1) { +- dput(parent); +- parent = dget_parent(d); +- if (!au_digen_test(parent, sigen)) +- break; +- d = parent; +- } +- +- inode = d->d_inode; +- if (d != dentry) +- di_write_lock_child2(d); +- +- /* someone might update our dentry while we were sleeping */ +- if (au_digen_test(d, sigen)) { +- /* +- * todo: consolidate with simple_reval_dpath(), +- * do_refresh() and au_reval_for_attr(). +- */ +- di_read_lock_parent(parent, AuLock_IR); +- err = au_refresh_dentry(d, parent); +- di_read_unlock(parent, AuLock_IR); +- } +- +- if (d != dentry) +- di_write_unlock(d); +- dput(parent); +- if (unlikely(err)) +- break; +- } +- +- return err; +-} +- +-/* +- * if valid returns 1, otherwise 0. +- */ +-static int aufs_d_revalidate(struct dentry *dentry, unsigned int flags) +-{ +- int valid, err; +- unsigned int sigen; +- unsigned char do_udba; +- struct super_block *sb; +- struct inode *inode; +- +- /* todo: support rcu-walk? */ +- if (flags & LOOKUP_RCU) +- return -ECHILD; +- +- valid = 0; +- if (unlikely(!au_di(dentry))) +- goto out; +- +- inode = dentry->d_inode; +- if (inode && is_bad_inode(inode)) +- goto out; +- +- valid = 1; +- sb = dentry->d_sb; +- /* +- * todo: very ugly +- * i_mutex of parent dir may be held, +- * but we should not return 'invalid' due to busy. +- */ +- err = aufs_read_lock(dentry, AuLock_FLUSH | AuLock_DW | AuLock_NOPLM); +- if (unlikely(err)) { +- valid = err; +- AuTraceErr(err); +- goto out; +- } +- if (unlikely(au_dbrange_test(dentry))) { +- err = -EINVAL; +- AuTraceErr(err); +- goto out_dgrade; +- } +- +- sigen = au_sigen(sb); +- if (au_digen_test(dentry, sigen)) { +- AuDebugOn(IS_ROOT(dentry)); +- err = au_reval_dpath(dentry, sigen); +- if (unlikely(err)) { +- AuTraceErr(err); +- goto out_dgrade; +- } +- } +- di_downgrade_lock(dentry, AuLock_IR); +- +- err = -EINVAL; +- if (inode && (IS_DEADDIR(inode) || !inode->i_nlink)) +- goto out_inval; +- +- do_udba = !au_opt_test(au_mntflags(sb), UDBA_NONE); +- if (do_udba && inode) { +- aufs_bindex_t bstart = au_ibstart(inode); +- struct inode *h_inode; +- +- if (bstart >= 0) { +- h_inode = au_h_iptr(inode, bstart); +- if (h_inode && au_test_higen(inode, h_inode)) +- goto out_inval; +- } +- } +- +- err = h_d_revalidate(dentry, inode, flags, do_udba); +- if (unlikely(!err && do_udba && au_dbstart(dentry) < 0)) { +- err = -EIO; +- AuDbg("both of real entry and whiteout found, %.*s, err %d\n", +- AuDLNPair(dentry), err); +- } +- goto out_inval; +- +-out_dgrade: +- di_downgrade_lock(dentry, AuLock_IR); +-out_inval: +- aufs_read_unlock(dentry, AuLock_IR); +- AuTraceErr(err); +- valid = !err; +-out: +- if (!valid) { +- AuDbg("%.*s invalid, %d\n", AuDLNPair(dentry), valid); +- d_drop(dentry); +- } +- return valid; +-} +- +-static void aufs_d_release(struct dentry *dentry) +-{ +- if (au_di(dentry)) { +- au_di_fin(dentry); +- au_hn_di_reinit(dentry); +- } +-} +- +-const struct dentry_operations aufs_dop = { +- .d_revalidate = aufs_d_revalidate, +- .d_release = aufs_d_release +-}; +diff --git a/fs/aufs/dentry.h b/fs/aufs/dentry.h +deleted file mode 100644 +index 1c05b94..0000000 +--- a/fs/aufs/dentry.h ++++ /dev/null +@@ -1,234 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * lookup and dentry operations +- */ +- +-#ifndef __AUFS_DENTRY_H__ +-#define __AUFS_DENTRY_H__ +- +-#ifdef __KERNEL__ +- +-#include +-#include "rwsem.h" +- +-struct au_hdentry { +- struct dentry *hd_dentry; +- aufs_bindex_t hd_id; +-}; +- +-struct au_dinfo { +- atomic_t di_generation; +- +- struct au_rwsem di_rwsem; +- aufs_bindex_t di_bstart, di_bend, di_bwh, di_bdiropq; +- struct au_hdentry *di_hdentry; +-} ____cacheline_aligned_in_smp; +- +-/* ---------------------------------------------------------------------- */ +- +-/* dentry.c */ +-extern const struct dentry_operations aufs_dop; +-struct au_branch; +-struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent, +- struct au_branch *br); +-int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir, +- struct dentry *h_parent, struct au_branch *br); +- +-int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type); +-int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex); +-int au_refresh_dentry(struct dentry *dentry, struct dentry *parent); +-int au_reval_dpath(struct dentry *dentry, unsigned int sigen); +- +-/* dinfo.c */ +-void au_di_init_once(void *_di); +-struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc); +-void au_di_free(struct au_dinfo *dinfo); +-void au_di_swap(struct au_dinfo *a, struct au_dinfo *b); +-void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src); +-int au_di_init(struct dentry *dentry); +-void au_di_fin(struct dentry *dentry); +-int au_di_realloc(struct au_dinfo *dinfo, int nbr); +- +-void di_read_lock(struct dentry *d, int flags, unsigned int lsc); +-void di_read_unlock(struct dentry *d, int flags); +-void di_downgrade_lock(struct dentry *d, int flags); +-void di_write_lock(struct dentry *d, unsigned int lsc); +-void di_write_unlock(struct dentry *d); +-void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir); +-void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir); +-void di_write_unlock2(struct dentry *d1, struct dentry *d2); +- +-struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex); +-struct dentry *au_h_d_alias(struct dentry *dentry, aufs_bindex_t bindex); +-aufs_bindex_t au_dbtail(struct dentry *dentry); +-aufs_bindex_t au_dbtaildir(struct dentry *dentry); +- +-void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, +- struct dentry *h_dentry); +-int au_digen_test(struct dentry *dentry, unsigned int sigen); +-int au_dbrange_test(struct dentry *dentry); +-void au_update_digen(struct dentry *dentry); +-void au_update_dbrange(struct dentry *dentry, int do_put_zero); +-void au_update_dbstart(struct dentry *dentry); +-void au_update_dbend(struct dentry *dentry); +-int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry); +- +-/* ---------------------------------------------------------------------- */ +- +-static inline struct au_dinfo *au_di(struct dentry *dentry) +-{ +- return dentry->d_fsdata; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* lock subclass for dinfo */ +-enum { +- AuLsc_DI_CHILD, /* child first */ +- AuLsc_DI_CHILD2, /* rename(2), link(2), and cpup at hnotify */ +- AuLsc_DI_CHILD3, /* copyup dirs */ +- AuLsc_DI_PARENT, +- AuLsc_DI_PARENT2, +- AuLsc_DI_PARENT3, +- AuLsc_DI_TMP /* temp for replacing dinfo */ +-}; +- +-/* +- * di_read_lock_child, di_write_lock_child, +- * di_read_lock_child2, di_write_lock_child2, +- * di_read_lock_child3, di_write_lock_child3, +- * di_read_lock_parent, di_write_lock_parent, +- * di_read_lock_parent2, di_write_lock_parent2, +- * di_read_lock_parent3, di_write_lock_parent3, +- */ +-#define AuReadLockFunc(name, lsc) \ +-static inline void di_read_lock_##name(struct dentry *d, int flags) \ +-{ di_read_lock(d, flags, AuLsc_DI_##lsc); } +- +-#define AuWriteLockFunc(name, lsc) \ +-static inline void di_write_lock_##name(struct dentry *d) \ +-{ di_write_lock(d, AuLsc_DI_##lsc); } +- +-#define AuRWLockFuncs(name, lsc) \ +- AuReadLockFunc(name, lsc) \ +- AuWriteLockFunc(name, lsc) +- +-AuRWLockFuncs(child, CHILD); +-AuRWLockFuncs(child2, CHILD2); +-AuRWLockFuncs(child3, CHILD3); +-AuRWLockFuncs(parent, PARENT); +-AuRWLockFuncs(parent2, PARENT2); +-AuRWLockFuncs(parent3, PARENT3); +- +-#undef AuReadLockFunc +-#undef AuWriteLockFunc +-#undef AuRWLockFuncs +- +-#define DiMustNoWaiters(d) AuRwMustNoWaiters(&au_di(d)->di_rwsem) +-#define DiMustAnyLock(d) AuRwMustAnyLock(&au_di(d)->di_rwsem) +-#define DiMustWriteLock(d) AuRwMustWriteLock(&au_di(d)->di_rwsem) +- +-/* ---------------------------------------------------------------------- */ +- +-/* todo: memory barrier? */ +-static inline unsigned int au_digen(struct dentry *d) +-{ +- return atomic_read(&au_di(d)->di_generation); +-} +- +-static inline void au_h_dentry_init(struct au_hdentry *hdentry) +-{ +- hdentry->hd_dentry = NULL; +-} +- +-static inline void au_hdput(struct au_hdentry *hd) +-{ +- if (hd) +- dput(hd->hd_dentry); +-} +- +-static inline aufs_bindex_t au_dbstart(struct dentry *dentry) +-{ +- DiMustAnyLock(dentry); +- return au_di(dentry)->di_bstart; +-} +- +-static inline aufs_bindex_t au_dbend(struct dentry *dentry) +-{ +- DiMustAnyLock(dentry); +- return au_di(dentry)->di_bend; +-} +- +-static inline aufs_bindex_t au_dbwh(struct dentry *dentry) +-{ +- DiMustAnyLock(dentry); +- return au_di(dentry)->di_bwh; +-} +- +-static inline aufs_bindex_t au_dbdiropq(struct dentry *dentry) +-{ +- DiMustAnyLock(dentry); +- return au_di(dentry)->di_bdiropq; +-} +- +-/* todo: hard/soft set? */ +-static inline void au_set_dbstart(struct dentry *dentry, aufs_bindex_t bindex) +-{ +- DiMustWriteLock(dentry); +- au_di(dentry)->di_bstart = bindex; +-} +- +-static inline void au_set_dbend(struct dentry *dentry, aufs_bindex_t bindex) +-{ +- DiMustWriteLock(dentry); +- au_di(dentry)->di_bend = bindex; +-} +- +-static inline void au_set_dbwh(struct dentry *dentry, aufs_bindex_t bindex) +-{ +- DiMustWriteLock(dentry); +- /* dbwh can be outside of bstart - bend range */ +- au_di(dentry)->di_bwh = bindex; +-} +- +-static inline void au_set_dbdiropq(struct dentry *dentry, aufs_bindex_t bindex) +-{ +- DiMustWriteLock(dentry); +- au_di(dentry)->di_bdiropq = bindex; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-#ifdef CONFIG_AUFS_HNOTIFY +-static inline void au_digen_dec(struct dentry *d) +-{ +- atomic_dec(&au_di(d)->di_generation); +-} +- +-static inline void au_hn_di_reinit(struct dentry *dentry) +-{ +- dentry->d_fsdata = NULL; +-} +-#else +-AuStubVoid(au_hn_di_reinit, struct dentry *dentry __maybe_unused) +-#endif /* CONFIG_AUFS_HNOTIFY */ +- +-#endif /* __KERNEL__ */ +-#endif /* __AUFS_DENTRY_H__ */ +diff --git a/fs/aufs/dinfo.c b/fs/aufs/dinfo.c +deleted file mode 100644 +index 2a92487..0000000 +--- a/fs/aufs/dinfo.c ++++ /dev/null +@@ -1,543 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * dentry private data +- */ +- +-#include "aufs.h" +- +-void au_di_init_once(void *_dinfo) +-{ +- struct au_dinfo *dinfo = _dinfo; +- static struct lock_class_key aufs_di; +- +- au_rw_init(&dinfo->di_rwsem); +- au_rw_class(&dinfo->di_rwsem, &aufs_di); +-} +- +-struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc) +-{ +- struct au_dinfo *dinfo; +- int nbr, i; +- +- dinfo = au_cache_alloc_dinfo(); +- if (unlikely(!dinfo)) +- goto out; +- +- nbr = au_sbend(sb) + 1; +- if (nbr <= 0) +- nbr = 1; +- dinfo->di_hdentry = kcalloc(nbr, sizeof(*dinfo->di_hdentry), GFP_NOFS); +- if (dinfo->di_hdentry) { +- au_rw_write_lock_nested(&dinfo->di_rwsem, lsc); +- dinfo->di_bstart = -1; +- dinfo->di_bend = -1; +- dinfo->di_bwh = -1; +- dinfo->di_bdiropq = -1; +- for (i = 0; i < nbr; i++) +- dinfo->di_hdentry[i].hd_id = -1; +- goto out; +- } +- +- au_cache_free_dinfo(dinfo); +- dinfo = NULL; +- +-out: +- return dinfo; +-} +- +-void au_di_free(struct au_dinfo *dinfo) +-{ +- struct au_hdentry *p; +- aufs_bindex_t bend, bindex; +- +- /* dentry may not be revalidated */ +- bindex = dinfo->di_bstart; +- if (bindex >= 0) { +- bend = dinfo->di_bend; +- p = dinfo->di_hdentry + bindex; +- while (bindex++ <= bend) +- au_hdput(p++); +- } +- kfree(dinfo->di_hdentry); +- au_cache_free_dinfo(dinfo); +-} +- +-void au_di_swap(struct au_dinfo *a, struct au_dinfo *b) +-{ +- struct au_hdentry *p; +- aufs_bindex_t bi; +- +- AuRwMustWriteLock(&a->di_rwsem); +- AuRwMustWriteLock(&b->di_rwsem); +- +-#define DiSwap(v, name) \ +- do { \ +- v = a->di_##name; \ +- a->di_##name = b->di_##name; \ +- b->di_##name = v; \ +- } while (0) +- +- DiSwap(p, hdentry); +- DiSwap(bi, bstart); +- DiSwap(bi, bend); +- DiSwap(bi, bwh); +- DiSwap(bi, bdiropq); +- /* smp_mb(); */ +- +-#undef DiSwap +-} +- +-void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src) +-{ +- AuRwMustWriteLock(&dst->di_rwsem); +- AuRwMustWriteLock(&src->di_rwsem); +- +- dst->di_bstart = src->di_bstart; +- dst->di_bend = src->di_bend; +- dst->di_bwh = src->di_bwh; +- dst->di_bdiropq = src->di_bdiropq; +- /* smp_mb(); */ +-} +- +-int au_di_init(struct dentry *dentry) +-{ +- int err; +- struct super_block *sb; +- struct au_dinfo *dinfo; +- +- err = 0; +- sb = dentry->d_sb; +- dinfo = au_di_alloc(sb, AuLsc_DI_CHILD); +- if (dinfo) { +- atomic_set(&dinfo->di_generation, au_sigen(sb)); +- /* smp_mb(); */ /* atomic_set */ +- dentry->d_fsdata = dinfo; +- } else +- err = -ENOMEM; +- +- return err; +-} +- +-void au_di_fin(struct dentry *dentry) +-{ +- struct au_dinfo *dinfo; +- +- dinfo = au_di(dentry); +- AuRwDestroy(&dinfo->di_rwsem); +- au_di_free(dinfo); +-} +- +-int au_di_realloc(struct au_dinfo *dinfo, int nbr) +-{ +- int err, sz; +- struct au_hdentry *hdp; +- +- AuRwMustWriteLock(&dinfo->di_rwsem); +- +- err = -ENOMEM; +- sz = sizeof(*hdp) * (dinfo->di_bend + 1); +- if (!sz) +- sz = sizeof(*hdp); +- hdp = au_kzrealloc(dinfo->di_hdentry, sz, sizeof(*hdp) * nbr, GFP_NOFS); +- if (hdp) { +- dinfo->di_hdentry = hdp; +- err = 0; +- } +- +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static void do_ii_write_lock(struct inode *inode, unsigned int lsc) +-{ +- switch (lsc) { +- case AuLsc_DI_CHILD: +- ii_write_lock_child(inode); +- break; +- case AuLsc_DI_CHILD2: +- ii_write_lock_child2(inode); +- break; +- case AuLsc_DI_CHILD3: +- ii_write_lock_child3(inode); +- break; +- case AuLsc_DI_PARENT: +- ii_write_lock_parent(inode); +- break; +- case AuLsc_DI_PARENT2: +- ii_write_lock_parent2(inode); +- break; +- case AuLsc_DI_PARENT3: +- ii_write_lock_parent3(inode); +- break; +- default: +- BUG(); +- } +-} +- +-static void do_ii_read_lock(struct inode *inode, unsigned int lsc) +-{ +- switch (lsc) { +- case AuLsc_DI_CHILD: +- ii_read_lock_child(inode); +- break; +- case AuLsc_DI_CHILD2: +- ii_read_lock_child2(inode); +- break; +- case AuLsc_DI_CHILD3: +- ii_read_lock_child3(inode); +- break; +- case AuLsc_DI_PARENT: +- ii_read_lock_parent(inode); +- break; +- case AuLsc_DI_PARENT2: +- ii_read_lock_parent2(inode); +- break; +- case AuLsc_DI_PARENT3: +- ii_read_lock_parent3(inode); +- break; +- default: +- BUG(); +- } +-} +- +-void di_read_lock(struct dentry *d, int flags, unsigned int lsc) +-{ +- au_rw_read_lock_nested(&au_di(d)->di_rwsem, lsc); +- if (d->d_inode) { +- if (au_ftest_lock(flags, IW)) +- do_ii_write_lock(d->d_inode, lsc); +- else if (au_ftest_lock(flags, IR)) +- do_ii_read_lock(d->d_inode, lsc); +- } +-} +- +-void di_read_unlock(struct dentry *d, int flags) +-{ +- if (d->d_inode) { +- if (au_ftest_lock(flags, IW)) { +- au_dbg_verify_dinode(d); +- ii_write_unlock(d->d_inode); +- } else if (au_ftest_lock(flags, IR)) { +- au_dbg_verify_dinode(d); +- ii_read_unlock(d->d_inode); +- } +- } +- au_rw_read_unlock(&au_di(d)->di_rwsem); +-} +- +-void di_downgrade_lock(struct dentry *d, int flags) +-{ +- if (d->d_inode && au_ftest_lock(flags, IR)) +- ii_downgrade_lock(d->d_inode); +- au_rw_dgrade_lock(&au_di(d)->di_rwsem); +-} +- +-void di_write_lock(struct dentry *d, unsigned int lsc) +-{ +- au_rw_write_lock_nested(&au_di(d)->di_rwsem, lsc); +- if (d->d_inode) +- do_ii_write_lock(d->d_inode, lsc); +-} +- +-void di_write_unlock(struct dentry *d) +-{ +- au_dbg_verify_dinode(d); +- if (d->d_inode) +- ii_write_unlock(d->d_inode); +- au_rw_write_unlock(&au_di(d)->di_rwsem); +-} +- +-void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir) +-{ +- AuDebugOn(d1 == d2 +- || d1->d_inode == d2->d_inode +- || d1->d_sb != d2->d_sb); +- +- if (isdir && au_test_subdir(d1, d2)) { +- di_write_lock_child(d1); +- di_write_lock_child2(d2); +- } else { +- /* there should be no races */ +- di_write_lock_child(d2); +- di_write_lock_child2(d1); +- } +-} +- +-void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir) +-{ +- AuDebugOn(d1 == d2 +- || d1->d_inode == d2->d_inode +- || d1->d_sb != d2->d_sb); +- +- if (isdir && au_test_subdir(d1, d2)) { +- di_write_lock_parent(d1); +- di_write_lock_parent2(d2); +- } else { +- /* there should be no races */ +- di_write_lock_parent(d2); +- di_write_lock_parent2(d1); +- } +-} +- +-void di_write_unlock2(struct dentry *d1, struct dentry *d2) +-{ +- di_write_unlock(d1); +- if (d1->d_inode == d2->d_inode) +- au_rw_write_unlock(&au_di(d2)->di_rwsem); +- else +- di_write_unlock(d2); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex) +-{ +- struct dentry *d; +- +- DiMustAnyLock(dentry); +- +- if (au_dbstart(dentry) < 0 || bindex < au_dbstart(dentry)) +- return NULL; +- AuDebugOn(bindex < 0); +- d = au_di(dentry)->di_hdentry[0 + bindex].hd_dentry; +- AuDebugOn(d && d->d_count <= 0); +- return d; +-} +- +-/* +- * extended version of au_h_dptr(). +- * returns a hashed and positive h_dentry in bindex, NULL, or error. +- */ +-struct dentry *au_h_d_alias(struct dentry *dentry, aufs_bindex_t bindex) +-{ +- struct dentry *h_dentry; +- struct inode *inode, *h_inode; +- +- inode = dentry->d_inode; +- AuDebugOn(!inode); +- +- h_dentry = NULL; +- if (au_dbstart(dentry) <= bindex +- && bindex <= au_dbend(dentry)) +- h_dentry = au_h_dptr(dentry, bindex); +- if (h_dentry && !au_d_hashed_positive(h_dentry)) { +- dget(h_dentry); +- goto out; /* success */ +- } +- +- AuDebugOn(bindex < au_ibstart(inode)); +- AuDebugOn(au_ibend(inode) < bindex); +- h_inode = au_h_iptr(inode, bindex); +- h_dentry = d_find_alias(h_inode); +- if (h_dentry) { +- if (!IS_ERR(h_dentry)) { +- if (!au_d_hashed_positive(h_dentry)) +- goto out; /* success */ +- dput(h_dentry); +- } else +- goto out; +- } +- +- if (au_opt_test(au_mntflags(dentry->d_sb), PLINK)) { +- h_dentry = au_plink_lkup(inode, bindex); +- AuDebugOn(!h_dentry); +- if (!IS_ERR(h_dentry)) { +- if (!au_d_hashed_positive(h_dentry)) +- goto out; /* success */ +- dput(h_dentry); +- h_dentry = NULL; +- } +- } +- +-out: +- AuDbgDentry(h_dentry); +- return h_dentry; +-} +- +-aufs_bindex_t au_dbtail(struct dentry *dentry) +-{ +- aufs_bindex_t bend, bwh; +- +- bend = au_dbend(dentry); +- if (0 <= bend) { +- bwh = au_dbwh(dentry); +- if (!bwh) +- return bwh; +- if (0 < bwh && bwh < bend) +- return bwh - 1; +- } +- return bend; +-} +- +-aufs_bindex_t au_dbtaildir(struct dentry *dentry) +-{ +- aufs_bindex_t bend, bopq; +- +- bend = au_dbtail(dentry); +- if (0 <= bend) { +- bopq = au_dbdiropq(dentry); +- if (0 <= bopq && bopq < bend) +- bend = bopq; +- } +- return bend; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, +- struct dentry *h_dentry) +-{ +- struct au_hdentry *hd = au_di(dentry)->di_hdentry + bindex; +- struct au_branch *br; +- +- DiMustWriteLock(dentry); +- +- au_hdput(hd); +- hd->hd_dentry = h_dentry; +- if (h_dentry) { +- br = au_sbr(dentry->d_sb, bindex); +- hd->hd_id = br->br_id; +- } +-} +- +-int au_dbrange_test(struct dentry *dentry) +-{ +- int err; +- aufs_bindex_t bstart, bend; +- +- err = 0; +- bstart = au_dbstart(dentry); +- bend = au_dbend(dentry); +- if (bstart >= 0) +- AuDebugOn(bend < 0 && bstart > bend); +- else { +- err = -EIO; +- AuDebugOn(bend >= 0); +- } +- +- return err; +-} +- +-int au_digen_test(struct dentry *dentry, unsigned int sigen) +-{ +- int err; +- +- err = 0; +- if (unlikely(au_digen(dentry) != sigen +- || au_iigen_test(dentry->d_inode, sigen))) +- err = -EIO; +- +- return err; +-} +- +-void au_update_digen(struct dentry *dentry) +-{ +- atomic_set(&au_di(dentry)->di_generation, au_sigen(dentry->d_sb)); +- /* smp_mb(); */ /* atomic_set */ +-} +- +-void au_update_dbrange(struct dentry *dentry, int do_put_zero) +-{ +- struct au_dinfo *dinfo; +- struct dentry *h_d; +- struct au_hdentry *hdp; +- +- DiMustWriteLock(dentry); +- +- dinfo = au_di(dentry); +- if (!dinfo || dinfo->di_bstart < 0) +- return; +- +- hdp = dinfo->di_hdentry; +- if (do_put_zero) { +- aufs_bindex_t bindex, bend; +- +- bend = dinfo->di_bend; +- for (bindex = dinfo->di_bstart; bindex <= bend; bindex++) { +- h_d = hdp[0 + bindex].hd_dentry; +- if (h_d && !h_d->d_inode) +- au_set_h_dptr(dentry, bindex, NULL); +- } +- } +- +- dinfo->di_bstart = -1; +- while (++dinfo->di_bstart <= dinfo->di_bend) +- if (hdp[0 + dinfo->di_bstart].hd_dentry) +- break; +- if (dinfo->di_bstart > dinfo->di_bend) { +- dinfo->di_bstart = -1; +- dinfo->di_bend = -1; +- return; +- } +- +- dinfo->di_bend++; +- while (0 <= --dinfo->di_bend) +- if (hdp[0 + dinfo->di_bend].hd_dentry) +- break; +- AuDebugOn(dinfo->di_bstart > dinfo->di_bend || dinfo->di_bend < 0); +-} +- +-void au_update_dbstart(struct dentry *dentry) +-{ +- aufs_bindex_t bindex, bend; +- struct dentry *h_dentry; +- +- bend = au_dbend(dentry); +- for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) { +- h_dentry = au_h_dptr(dentry, bindex); +- if (!h_dentry) +- continue; +- if (h_dentry->d_inode) { +- au_set_dbstart(dentry, bindex); +- return; +- } +- au_set_h_dptr(dentry, bindex, NULL); +- } +-} +- +-void au_update_dbend(struct dentry *dentry) +-{ +- aufs_bindex_t bindex, bstart; +- struct dentry *h_dentry; +- +- bstart = au_dbstart(dentry); +- for (bindex = au_dbend(dentry); bindex >= bstart; bindex--) { +- h_dentry = au_h_dptr(dentry, bindex); +- if (!h_dentry) +- continue; +- if (h_dentry->d_inode) { +- au_set_dbend(dentry, bindex); +- return; +- } +- au_set_h_dptr(dentry, bindex, NULL); +- } +-} +- +-int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry) +-{ +- aufs_bindex_t bindex, bend; +- +- bend = au_dbend(dentry); +- for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) +- if (au_h_dptr(dentry, bindex) == h_dentry) +- return bindex; +- return -1; +-} +diff --git a/fs/aufs/dir.c b/fs/aufs/dir.c +deleted file mode 100644 +index 2367ae5..0000000 +--- a/fs/aufs/dir.c ++++ /dev/null +@@ -1,633 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * directory operations +- */ +- +-#include +-#include "aufs.h" +- +-void au_add_nlink(struct inode *dir, struct inode *h_dir) +-{ +- unsigned int nlink; +- +- AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode)); +- +- nlink = dir->i_nlink; +- nlink += h_dir->i_nlink - 2; +- if (h_dir->i_nlink < 2) +- nlink += 2; +- /* 0 can happen in revaliding */ +- set_nlink(dir, nlink); +-} +- +-void au_sub_nlink(struct inode *dir, struct inode *h_dir) +-{ +- unsigned int nlink; +- +- AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode)); +- +- nlink = dir->i_nlink; +- nlink -= h_dir->i_nlink - 2; +- if (h_dir->i_nlink < 2) +- nlink -= 2; +- /* nlink == 0 means the branch-fs is broken */ +- set_nlink(dir, nlink); +-} +- +-loff_t au_dir_size(struct file *file, struct dentry *dentry) +-{ +- loff_t sz; +- aufs_bindex_t bindex, bend; +- struct file *h_file; +- struct dentry *h_dentry; +- +- sz = 0; +- if (file) { +- AuDebugOn(!file->f_dentry); +- AuDebugOn(!file->f_dentry->d_inode); +- AuDebugOn(!S_ISDIR(file->f_dentry->d_inode->i_mode)); +- +- bend = au_fbend_dir(file); +- for (bindex = au_fbstart(file); +- bindex <= bend && sz < KMALLOC_MAX_SIZE; +- bindex++) { +- h_file = au_hf_dir(file, bindex); +- if (h_file +- && h_file->f_dentry +- && h_file->f_dentry->d_inode) +- sz += i_size_read(h_file->f_dentry->d_inode); +- } +- } else { +- AuDebugOn(!dentry); +- AuDebugOn(!dentry->d_inode); +- AuDebugOn(!S_ISDIR(dentry->d_inode->i_mode)); +- +- bend = au_dbtaildir(dentry); +- for (bindex = au_dbstart(dentry); +- bindex <= bend && sz < KMALLOC_MAX_SIZE; +- bindex++) { +- h_dentry = au_h_dptr(dentry, bindex); +- if (h_dentry && h_dentry->d_inode) +- sz += i_size_read(h_dentry->d_inode); +- } +- } +- if (sz < KMALLOC_MAX_SIZE) +- sz = roundup_pow_of_two(sz); +- if (sz > KMALLOC_MAX_SIZE) +- sz = KMALLOC_MAX_SIZE; +- else if (sz < NAME_MAX) { +- BUILD_BUG_ON(AUFS_RDBLK_DEF < NAME_MAX); +- sz = AUFS_RDBLK_DEF; +- } +- return sz; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static int reopen_dir(struct file *file) +-{ +- int err; +- unsigned int flags; +- aufs_bindex_t bindex, btail, bstart; +- struct dentry *dentry, *h_dentry; +- struct file *h_file; +- +- /* open all lower dirs */ +- dentry = file->f_dentry; +- bstart = au_dbstart(dentry); +- for (bindex = au_fbstart(file); bindex < bstart; bindex++) +- au_set_h_fptr(file, bindex, NULL); +- au_set_fbstart(file, bstart); +- +- btail = au_dbtaildir(dentry); +- for (bindex = au_fbend_dir(file); btail < bindex; bindex--) +- au_set_h_fptr(file, bindex, NULL); +- au_set_fbend_dir(file, btail); +- +- flags = vfsub_file_flags(file); +- for (bindex = bstart; bindex <= btail; bindex++) { +- h_dentry = au_h_dptr(dentry, bindex); +- if (!h_dentry) +- continue; +- h_file = au_hf_dir(file, bindex); +- if (h_file) +- continue; +- +- h_file = au_h_open(dentry, bindex, flags, file); +- err = PTR_ERR(h_file); +- if (IS_ERR(h_file)) +- goto out; /* close all? */ +- au_set_h_fptr(file, bindex, h_file); +- } +- au_update_figen(file); +- /* todo: necessary? */ +- /* file->f_ra = h_file->f_ra; */ +- err = 0; +- +-out: +- return err; +-} +- +-static int do_open_dir(struct file *file, int flags) +-{ +- int err; +- aufs_bindex_t bindex, btail; +- struct dentry *dentry, *h_dentry; +- struct file *h_file; +- +- FiMustWriteLock(file); +- +- dentry = file->f_dentry; +- err = au_alive_dir(dentry); +- if (unlikely(err)) +- goto out; +- +- file->f_version = dentry->d_inode->i_version; +- bindex = au_dbstart(dentry); +- au_set_fbstart(file, bindex); +- btail = au_dbtaildir(dentry); +- au_set_fbend_dir(file, btail); +- for (; !err && bindex <= btail; bindex++) { +- h_dentry = au_h_dptr(dentry, bindex); +- if (!h_dentry) +- continue; +- +- h_file = au_h_open(dentry, bindex, flags, file); +- if (IS_ERR(h_file)) { +- err = PTR_ERR(h_file); +- break; +- } +- au_set_h_fptr(file, bindex, h_file); +- } +- au_update_figen(file); +- /* todo: necessary? */ +- /* file->f_ra = h_file->f_ra; */ +- if (!err) +- return 0; /* success */ +- +- /* close all */ +- for (bindex = au_fbstart(file); bindex <= btail; bindex++) +- au_set_h_fptr(file, bindex, NULL); +- au_set_fbstart(file, -1); +- au_set_fbend_dir(file, -1); +- +-out: +- return err; +-} +- +-static int aufs_open_dir(struct inode *inode __maybe_unused, +- struct file *file) +-{ +- int err; +- struct super_block *sb; +- struct au_fidir *fidir; +- +- err = -ENOMEM; +- sb = file->f_dentry->d_sb; +- si_read_lock(sb, AuLock_FLUSH); +- fidir = au_fidir_alloc(sb); +- if (fidir) { +- err = au_do_open(file, do_open_dir, fidir); +- if (unlikely(err)) +- kfree(fidir); +- } +- si_read_unlock(sb); +- return err; +-} +- +-static int aufs_release_dir(struct inode *inode __maybe_unused, +- struct file *file) +-{ +- struct au_vdir *vdir_cache; +- struct au_finfo *finfo; +- struct au_fidir *fidir; +- aufs_bindex_t bindex, bend; +- +- finfo = au_fi(file); +- fidir = finfo->fi_hdir; +- if (fidir) { +- vdir_cache = fidir->fd_vdir_cache; /* lock-free */ +- if (vdir_cache) +- au_vdir_free(vdir_cache); +- +- bindex = finfo->fi_btop; +- if (bindex >= 0) { +- /* +- * calls fput() instead of filp_close(), +- * since no dnotify or lock for the lower file. +- */ +- bend = fidir->fd_bbot; +- for (; bindex <= bend; bindex++) +- au_set_h_fptr(file, bindex, NULL); +- } +- kfree(fidir); +- finfo->fi_hdir = NULL; +- } +- au_finfo_fin(file); +- return 0; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static int au_do_flush_dir(struct file *file, fl_owner_t id) +-{ +- int err; +- aufs_bindex_t bindex, bend; +- struct file *h_file; +- +- err = 0; +- bend = au_fbend_dir(file); +- for (bindex = au_fbstart(file); !err && bindex <= bend; bindex++) { +- h_file = au_hf_dir(file, bindex); +- if (h_file) +- err = vfsub_flush(h_file, id); +- } +- return err; +-} +- +-static int aufs_flush_dir(struct file *file, fl_owner_t id) +-{ +- return au_do_flush(file, id, au_do_flush_dir); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static int au_do_fsync_dir_no_file(struct dentry *dentry, int datasync) +-{ +- int err; +- aufs_bindex_t bend, bindex; +- struct inode *inode; +- struct super_block *sb; +- +- err = 0; +- sb = dentry->d_sb; +- inode = dentry->d_inode; +- IMustLock(inode); +- bend = au_dbend(dentry); +- for (bindex = au_dbstart(dentry); !err && bindex <= bend; bindex++) { +- struct path h_path; +- +- if (au_test_ro(sb, bindex, inode)) +- continue; +- h_path.dentry = au_h_dptr(dentry, bindex); +- if (!h_path.dentry) +- continue; +- +- h_path.mnt = au_sbr_mnt(sb, bindex); +- err = vfsub_fsync(NULL, &h_path, datasync); +- } +- +- return err; +-} +- +-static int au_do_fsync_dir(struct file *file, int datasync) +-{ +- int err; +- aufs_bindex_t bend, bindex; +- struct file *h_file; +- struct super_block *sb; +- struct inode *inode; +- +- err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1); +- if (unlikely(err)) +- goto out; +- +- sb = file->f_dentry->d_sb; +- inode = file->f_dentry->d_inode; +- bend = au_fbend_dir(file); +- for (bindex = au_fbstart(file); !err && bindex <= bend; bindex++) { +- h_file = au_hf_dir(file, bindex); +- if (!h_file || au_test_ro(sb, bindex, inode)) +- continue; +- +- err = vfsub_fsync(h_file, &h_file->f_path, datasync); +- } +- +-out: +- return err; +-} +- +-/* +- * @file may be NULL +- */ +-static int aufs_fsync_dir(struct file *file, loff_t start, loff_t end, +- int datasync) +-{ +- int err; +- struct dentry *dentry; +- struct super_block *sb; +- struct mutex *mtx; +- +- err = 0; +- dentry = file->f_dentry; +- mtx = &dentry->d_inode->i_mutex; +- mutex_lock(mtx); +- sb = dentry->d_sb; +- si_noflush_read_lock(sb); +- if (file) +- err = au_do_fsync_dir(file, datasync); +- else { +- di_write_lock_child(dentry); +- err = au_do_fsync_dir_no_file(dentry, datasync); +- } +- au_cpup_attr_timesizes(dentry->d_inode); +- di_write_unlock(dentry); +- if (file) +- fi_write_unlock(file); +- +- si_read_unlock(sb); +- mutex_unlock(mtx); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static int aufs_readdir(struct file *file, void *dirent, filldir_t filldir) +-{ +- int err; +- struct dentry *dentry; +- struct inode *inode, *h_inode; +- struct super_block *sb; +- +- dentry = file->f_dentry; +- inode = dentry->d_inode; +- IMustLock(inode); +- +- sb = dentry->d_sb; +- si_read_lock(sb, AuLock_FLUSH); +- err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1); +- if (unlikely(err)) +- goto out; +- err = au_alive_dir(dentry); +- if (!err) +- err = au_vdir_init(file); +- di_downgrade_lock(dentry, AuLock_IR); +- if (unlikely(err)) +- goto out_unlock; +- +- h_inode = au_h_iptr(inode, au_ibstart(inode)); +- if (!au_test_nfsd()) { +- err = au_vdir_fill_de(file, dirent, filldir); +- fsstack_copy_attr_atime(inode, h_inode); +- } else { +- /* +- * nfsd filldir may call lookup_one_len(), vfs_getattr(), +- * encode_fh() and others. +- */ +- atomic_inc(&h_inode->i_count); +- di_read_unlock(dentry, AuLock_IR); +- si_read_unlock(sb); +- err = au_vdir_fill_de(file, dirent, filldir); +- fsstack_copy_attr_atime(inode, h_inode); +- fi_write_unlock(file); +- iput(h_inode); +- +- AuTraceErr(err); +- return err; +- } +- +-out_unlock: +- di_read_unlock(dentry, AuLock_IR); +- fi_write_unlock(file); +-out: +- si_read_unlock(sb); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-#define AuTestEmpty_WHONLY 1 +-#define AuTestEmpty_CALLED (1 << 1) +-#define AuTestEmpty_SHWH (1 << 2) +-#define au_ftest_testempty(flags, name) ((flags) & AuTestEmpty_##name) +-#define au_fset_testempty(flags, name) \ +- do { (flags) |= AuTestEmpty_##name; } while (0) +-#define au_fclr_testempty(flags, name) \ +- do { (flags) &= ~AuTestEmpty_##name; } while (0) +- +-#ifndef CONFIG_AUFS_SHWH +-#undef AuTestEmpty_SHWH +-#define AuTestEmpty_SHWH 0 +-#endif +- +-struct test_empty_arg { +- struct au_nhash *whlist; +- unsigned int flags; +- int err; +- aufs_bindex_t bindex; +-}; +- +-static int test_empty_cb(void *__arg, const char *__name, int namelen, +- loff_t offset __maybe_unused, u64 ino, +- unsigned int d_type) +-{ +- struct test_empty_arg *arg = __arg; +- char *name = (void *)__name; +- +- arg->err = 0; +- au_fset_testempty(arg->flags, CALLED); +- /* smp_mb(); */ +- if (name[0] == '.' +- && (namelen == 1 || (name[1] == '.' && namelen == 2))) +- goto out; /* success */ +- +- if (namelen <= AUFS_WH_PFX_LEN +- || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { +- if (au_ftest_testempty(arg->flags, WHONLY) +- && !au_nhash_test_known_wh(arg->whlist, name, namelen)) +- arg->err = -ENOTEMPTY; +- goto out; +- } +- +- name += AUFS_WH_PFX_LEN; +- namelen -= AUFS_WH_PFX_LEN; +- if (!au_nhash_test_known_wh(arg->whlist, name, namelen)) +- arg->err = au_nhash_append_wh +- (arg->whlist, name, namelen, ino, d_type, arg->bindex, +- au_ftest_testempty(arg->flags, SHWH)); +- +-out: +- /* smp_mb(); */ +- AuTraceErr(arg->err); +- return arg->err; +-} +- +-static int do_test_empty(struct dentry *dentry, struct test_empty_arg *arg) +-{ +- int err; +- struct file *h_file; +- +- h_file = au_h_open(dentry, arg->bindex, +- O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_LARGEFILE, +- /*file*/NULL); +- err = PTR_ERR(h_file); +- if (IS_ERR(h_file)) +- goto out; +- +- err = 0; +- if (!au_opt_test(au_mntflags(dentry->d_sb), UDBA_NONE) +- && !h_file->f_dentry->d_inode->i_nlink) +- goto out_put; +- +- do { +- arg->err = 0; +- au_fclr_testempty(arg->flags, CALLED); +- /* smp_mb(); */ +- err = vfsub_readdir(h_file, test_empty_cb, arg); +- if (err >= 0) +- err = arg->err; +- } while (!err && au_ftest_testempty(arg->flags, CALLED)); +- +-out_put: +- fput(h_file); +- au_sbr_put(dentry->d_sb, arg->bindex); +-out: +- return err; +-} +- +-struct do_test_empty_args { +- int *errp; +- struct dentry *dentry; +- struct test_empty_arg *arg; +-}; +- +-static void call_do_test_empty(void *args) +-{ +- struct do_test_empty_args *a = args; +- *a->errp = do_test_empty(a->dentry, a->arg); +-} +- +-static int sio_test_empty(struct dentry *dentry, struct test_empty_arg *arg) +-{ +- int err, wkq_err; +- struct dentry *h_dentry; +- struct inode *h_inode; +- +- h_dentry = au_h_dptr(dentry, arg->bindex); +- h_inode = h_dentry->d_inode; +- /* todo: i_mode changes anytime? */ +- mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); +- err = au_test_h_perm_sio(h_inode, MAY_EXEC | MAY_READ); +- mutex_unlock(&h_inode->i_mutex); +- if (!err) +- err = do_test_empty(dentry, arg); +- else { +- struct do_test_empty_args args = { +- .errp = &err, +- .dentry = dentry, +- .arg = arg +- }; +- unsigned int flags = arg->flags; +- +- wkq_err = au_wkq_wait(call_do_test_empty, &args); +- if (unlikely(wkq_err)) +- err = wkq_err; +- arg->flags = flags; +- } +- +- return err; +-} +- +-int au_test_empty_lower(struct dentry *dentry) +-{ +- int err; +- unsigned int rdhash; +- aufs_bindex_t bindex, bstart, btail; +- struct au_nhash whlist; +- struct test_empty_arg arg; +- +- SiMustAnyLock(dentry->d_sb); +- +- rdhash = au_sbi(dentry->d_sb)->si_rdhash; +- if (!rdhash) +- rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, dentry)); +- err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS); +- if (unlikely(err)) +- goto out; +- +- arg.flags = 0; +- arg.whlist = &whlist; +- bstart = au_dbstart(dentry); +- if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)) +- au_fset_testempty(arg.flags, SHWH); +- arg.bindex = bstart; +- err = do_test_empty(dentry, &arg); +- if (unlikely(err)) +- goto out_whlist; +- +- au_fset_testempty(arg.flags, WHONLY); +- btail = au_dbtaildir(dentry); +- for (bindex = bstart + 1; !err && bindex <= btail; bindex++) { +- struct dentry *h_dentry; +- +- h_dentry = au_h_dptr(dentry, bindex); +- if (h_dentry && h_dentry->d_inode) { +- arg.bindex = bindex; +- err = do_test_empty(dentry, &arg); +- } +- } +- +-out_whlist: +- au_nhash_wh_free(&whlist); +-out: +- return err; +-} +- +-int au_test_empty(struct dentry *dentry, struct au_nhash *whlist) +-{ +- int err; +- struct test_empty_arg arg; +- aufs_bindex_t bindex, btail; +- +- err = 0; +- arg.whlist = whlist; +- arg.flags = AuTestEmpty_WHONLY; +- if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)) +- au_fset_testempty(arg.flags, SHWH); +- btail = au_dbtaildir(dentry); +- for (bindex = au_dbstart(dentry); !err && bindex <= btail; bindex++) { +- struct dentry *h_dentry; +- +- h_dentry = au_h_dptr(dentry, bindex); +- if (h_dentry && h_dentry->d_inode) { +- arg.bindex = bindex; +- err = sio_test_empty(dentry, &arg); +- } +- } +- +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-const struct file_operations aufs_dir_fop = { +- .owner = THIS_MODULE, +- .llseek = default_llseek, +- .read = generic_read_dir, +- .readdir = aufs_readdir, +- .unlocked_ioctl = aufs_ioctl_dir, +-#ifdef CONFIG_COMPAT +- .compat_ioctl = aufs_compat_ioctl_dir, +-#endif +- .open = aufs_open_dir, +- .release = aufs_release_dir, +- .flush = aufs_flush_dir, +- .fsync = aufs_fsync_dir +-}; +diff --git a/fs/aufs/dir.h b/fs/aufs/dir.h +deleted file mode 100644 +index fb237ba..0000000 +--- a/fs/aufs/dir.h ++++ /dev/null +@@ -1,137 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * directory operations +- */ +- +-#ifndef __AUFS_DIR_H__ +-#define __AUFS_DIR_H__ +- +-#ifdef __KERNEL__ +- +-#include +- +-/* ---------------------------------------------------------------------- */ +- +-/* need to be faster and smaller */ +- +-struct au_nhash { +- unsigned int nh_num; +- struct hlist_head *nh_head; +-}; +- +-struct au_vdir_destr { +- unsigned char len; +- unsigned char name[0]; +-} __packed; +- +-struct au_vdir_dehstr { +- struct hlist_node hash; +- struct au_vdir_destr *str; +-} ____cacheline_aligned_in_smp; +- +-struct au_vdir_de { +- ino_t de_ino; +- unsigned char de_type; +- /* caution: packed */ +- struct au_vdir_destr de_str; +-} __packed; +- +-struct au_vdir_wh { +- struct hlist_node wh_hash; +-#ifdef CONFIG_AUFS_SHWH +- ino_t wh_ino; +- aufs_bindex_t wh_bindex; +- unsigned char wh_type; +-#else +- aufs_bindex_t wh_bindex; +-#endif +- /* caution: packed */ +- struct au_vdir_destr wh_str; +-} __packed; +- +-union au_vdir_deblk_p { +- unsigned char *deblk; +- struct au_vdir_de *de; +-}; +- +-struct au_vdir { +- unsigned char **vd_deblk; +- unsigned long vd_nblk; +- struct { +- unsigned long ul; +- union au_vdir_deblk_p p; +- } vd_last; +- +- unsigned long vd_version; +- unsigned int vd_deblk_sz; +- unsigned long vd_jiffy; +-} ____cacheline_aligned_in_smp; +- +-/* ---------------------------------------------------------------------- */ +- +-/* dir.c */ +-extern const struct file_operations aufs_dir_fop; +-void au_add_nlink(struct inode *dir, struct inode *h_dir); +-void au_sub_nlink(struct inode *dir, struct inode *h_dir); +-loff_t au_dir_size(struct file *file, struct dentry *dentry); +-int au_test_empty_lower(struct dentry *dentry); +-int au_test_empty(struct dentry *dentry, struct au_nhash *whlist); +- +-/* vdir.c */ +-unsigned int au_rdhash_est(loff_t sz); +-int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp); +-void au_nhash_wh_free(struct au_nhash *whlist); +-int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt, +- int limit); +-int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen); +-int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino, +- unsigned int d_type, aufs_bindex_t bindex, +- unsigned char shwh); +-void au_vdir_free(struct au_vdir *vdir); +-int au_vdir_init(struct file *file); +-int au_vdir_fill_de(struct file *file, void *dirent, filldir_t filldir); +- +-/* ioctl.c */ +-long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg); +- +-#ifdef CONFIG_AUFS_RDU +-/* rdu.c */ +-long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg); +-#ifdef CONFIG_COMPAT +-long au_rdu_compat_ioctl(struct file *file, unsigned int cmd, +- unsigned long arg); +-#endif +-#else +-static inline long au_rdu_ioctl(struct file *file, unsigned int cmd, +- unsigned long arg) +-{ +- return -EINVAL; +-} +-#ifdef CONFIG_COMPAT +-static inline long au_rdu_compat_ioctl(struct file *file, unsigned int cmd, +- unsigned long arg) +-{ +- return -EINVAL; +-} +-#endif +-#endif +- +-#endif /* __KERNEL__ */ +-#endif /* __AUFS_DIR_H__ */ +diff --git a/fs/aufs/dynop.c b/fs/aufs/dynop.c +deleted file mode 100644 +index b425366..0000000 +--- a/fs/aufs/dynop.c ++++ /dev/null +@@ -1,379 +0,0 @@ +-/* +- * Copyright (C) 2010-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * dynamically customizable operations for regular files +- */ +- +-#include "aufs.h" +- +-#define DyPrSym(key) AuDbgSym(key->dk_op.dy_hop) +- +-/* +- * How large will these lists be? +- * Usually just a few elements, 20-30 at most for each, I guess. +- */ +-static struct au_splhead dynop[AuDyLast]; +- +-static struct au_dykey *dy_gfind_get(struct au_splhead *spl, const void *h_op) +-{ +- struct au_dykey *key, *tmp; +- struct list_head *head; +- +- key = NULL; +- head = &spl->head; +- rcu_read_lock(); +- list_for_each_entry_rcu(tmp, head, dk_list) +- if (tmp->dk_op.dy_hop == h_op) { +- key = tmp; +- kref_get(&key->dk_kref); +- break; +- } +- rcu_read_unlock(); +- +- return key; +-} +- +-static struct au_dykey *dy_bradd(struct au_branch *br, struct au_dykey *key) +-{ +- struct au_dykey **k, *found; +- const void *h_op = key->dk_op.dy_hop; +- int i; +- +- found = NULL; +- k = br->br_dykey; +- for (i = 0; i < AuBrDynOp; i++) +- if (k[i]) { +- if (k[i]->dk_op.dy_hop == h_op) { +- found = k[i]; +- break; +- } +- } else +- break; +- if (!found) { +- spin_lock(&br->br_dykey_lock); +- for (; i < AuBrDynOp; i++) +- if (k[i]) { +- if (k[i]->dk_op.dy_hop == h_op) { +- found = k[i]; +- break; +- } +- } else { +- k[i] = key; +- break; +- } +- spin_unlock(&br->br_dykey_lock); +- BUG_ON(i == AuBrDynOp); /* expand the array */ +- } +- +- return found; +-} +- +-/* kref_get() if @key is already added */ +-static struct au_dykey *dy_gadd(struct au_splhead *spl, struct au_dykey *key) +-{ +- struct au_dykey *tmp, *found; +- struct list_head *head; +- const void *h_op = key->dk_op.dy_hop; +- +- found = NULL; +- head = &spl->head; +- spin_lock(&spl->spin); +- list_for_each_entry(tmp, head, dk_list) +- if (tmp->dk_op.dy_hop == h_op) { +- kref_get(&tmp->dk_kref); +- found = tmp; +- break; +- } +- if (!found) +- list_add_rcu(&key->dk_list, head); +- spin_unlock(&spl->spin); +- +- if (!found) +- DyPrSym(key); +- return found; +-} +- +-static void dy_free_rcu(struct rcu_head *rcu) +-{ +- struct au_dykey *key; +- +- key = container_of(rcu, struct au_dykey, dk_rcu); +- DyPrSym(key); +- kfree(key); +-} +- +-static void dy_free(struct kref *kref) +-{ +- struct au_dykey *key; +- struct au_splhead *spl; +- +- key = container_of(kref, struct au_dykey, dk_kref); +- spl = dynop + key->dk_op.dy_type; +- au_spl_del_rcu(&key->dk_list, spl); +- call_rcu(&key->dk_rcu, dy_free_rcu); +-} +- +-void au_dy_put(struct au_dykey *key) +-{ +- kref_put(&key->dk_kref, dy_free); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-#define DyDbgSize(cnt, op) AuDebugOn(cnt != sizeof(op)/sizeof(void *)) +- +-#ifdef CONFIG_AUFS_DEBUG +-#define DyDbgDeclare(cnt) unsigned int cnt = 0 +-#define DyDbgInc(cnt) do { cnt++; } while (0) +-#else +-#define DyDbgDeclare(cnt) do {} while (0) +-#define DyDbgInc(cnt) do {} while (0) +-#endif +- +-#define DySet(func, dst, src, h_op, h_sb) do { \ +- DyDbgInc(cnt); \ +- if (h_op->func) { \ +- if (src.func) \ +- dst.func = src.func; \ +- else \ +- AuDbg("%s %s\n", au_sbtype(h_sb), #func); \ +- } \ +-} while (0) +- +-#define DySetForce(func, dst, src) do { \ +- AuDebugOn(!src.func); \ +- DyDbgInc(cnt); \ +- dst.func = src.func; \ +-} while (0) +- +-#define DySetAop(func) \ +- DySet(func, dyaop->da_op, aufs_aop, h_aop, h_sb) +-#define DySetAopForce(func) \ +- DySetForce(func, dyaop->da_op, aufs_aop) +- +-static void dy_aop(struct au_dykey *key, const void *h_op, +- struct super_block *h_sb __maybe_unused) +-{ +- struct au_dyaop *dyaop = (void *)key; +- const struct address_space_operations *h_aop = h_op; +- DyDbgDeclare(cnt); +- +- AuDbg("%s\n", au_sbtype(h_sb)); +- +- DySetAop(writepage); +- DySetAopForce(readpage); /* force */ +- DySetAop(writepages); +- DySetAop(set_page_dirty); +- DySetAop(readpages); +- DySetAop(write_begin); +- DySetAop(write_end); +- DySetAop(bmap); +- DySetAop(invalidatepage); +- DySetAop(releasepage); +- DySetAop(freepage); +- /* these two will be changed according to an aufs mount option */ +- DySetAop(direct_IO); +- DySetAop(get_xip_mem); +- DySetAop(migratepage); +- DySetAop(launder_page); +- DySetAop(is_partially_uptodate); +- DySetAop(error_remove_page); +- DySetAop(swap_activate); +- DySetAop(swap_deactivate); +- +- DyDbgSize(cnt, *h_aop); +- dyaop->da_get_xip_mem = h_aop->get_xip_mem; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static void dy_bug(struct kref *kref) +-{ +- BUG(); +-} +- +-static struct au_dykey *dy_get(struct au_dynop *op, struct au_branch *br) +-{ +- struct au_dykey *key, *old; +- struct au_splhead *spl; +- struct op { +- unsigned int sz; +- void (*set)(struct au_dykey *key, const void *h_op, +- struct super_block *h_sb __maybe_unused); +- }; +- static const struct op a[] = { +- [AuDy_AOP] = { +- .sz = sizeof(struct au_dyaop), +- .set = dy_aop +- } +- }; +- const struct op *p; +- +- spl = dynop + op->dy_type; +- key = dy_gfind_get(spl, op->dy_hop); +- if (key) +- goto out_add; /* success */ +- +- p = a + op->dy_type; +- key = kzalloc(p->sz, GFP_NOFS); +- if (unlikely(!key)) { +- key = ERR_PTR(-ENOMEM); +- goto out; +- } +- +- key->dk_op.dy_hop = op->dy_hop; +- kref_init(&key->dk_kref); +- p->set(key, op->dy_hop, br->br_mnt->mnt_sb); +- old = dy_gadd(spl, key); +- if (old) { +- kfree(key); +- key = old; +- } +- +-out_add: +- old = dy_bradd(br, key); +- if (old) +- /* its ref-count should never be zero here */ +- kref_put(&key->dk_kref, dy_bug); +-out: +- return key; +-} +- +-/* ---------------------------------------------------------------------- */ +-/* +- * Aufs prohibits O_DIRECT by defaut even if the branch supports it. +- * This behaviour is neccessary to return an error from open(O_DIRECT) instead +- * of the succeeding I/O. The dio mount option enables O_DIRECT and makes +- * open(O_DIRECT) always succeed, but the succeeding I/O may return an error. +- * See the aufs manual in detail. +- * +- * To keep this behaviour, aufs has to set NULL to ->get_xip_mem too, and the +- * performance of fadvise() and madvise() may be affected. +- */ +-static void dy_adx(struct au_dyaop *dyaop, int do_dx) +-{ +- if (!do_dx) { +- dyaop->da_op.direct_IO = NULL; +- dyaop->da_op.get_xip_mem = NULL; +- } else { +- dyaop->da_op.direct_IO = aufs_aop.direct_IO; +- dyaop->da_op.get_xip_mem = aufs_aop.get_xip_mem; +- if (!dyaop->da_get_xip_mem) +- dyaop->da_op.get_xip_mem = NULL; +- } +-} +- +-static struct au_dyaop *dy_aget(struct au_branch *br, +- const struct address_space_operations *h_aop, +- int do_dx) +-{ +- struct au_dyaop *dyaop; +- struct au_dynop op; +- +- op.dy_type = AuDy_AOP; +- op.dy_haop = h_aop; +- dyaop = (void *)dy_get(&op, br); +- if (IS_ERR(dyaop)) +- goto out; +- dy_adx(dyaop, do_dx); +- +-out: +- return dyaop; +-} +- +-int au_dy_iaop(struct inode *inode, aufs_bindex_t bindex, +- struct inode *h_inode) +-{ +- int err, do_dx; +- struct super_block *sb; +- struct au_branch *br; +- struct au_dyaop *dyaop; +- +- AuDebugOn(!S_ISREG(h_inode->i_mode)); +- IiMustWriteLock(inode); +- +- sb = inode->i_sb; +- br = au_sbr(sb, bindex); +- do_dx = !!au_opt_test(au_mntflags(sb), DIO); +- dyaop = dy_aget(br, h_inode->i_mapping->a_ops, do_dx); +- err = PTR_ERR(dyaop); +- if (IS_ERR(dyaop)) +- /* unnecessary to call dy_fput() */ +- goto out; +- +- err = 0; +- inode->i_mapping->a_ops = &dyaop->da_op; +- +-out: +- return err; +-} +- +-/* +- * Is it safe to replace a_ops during the inode/file is in operation? +- * Yes, I hope so. +- */ +-int au_dy_irefresh(struct inode *inode) +-{ +- int err; +- aufs_bindex_t bstart; +- struct inode *h_inode; +- +- err = 0; +- if (S_ISREG(inode->i_mode)) { +- bstart = au_ibstart(inode); +- h_inode = au_h_iptr(inode, bstart); +- err = au_dy_iaop(inode, bstart, h_inode); +- } +- return err; +-} +- +-void au_dy_arefresh(int do_dx) +-{ +- struct au_splhead *spl; +- struct list_head *head; +- struct au_dykey *key; +- +- spl = dynop + AuDy_AOP; +- head = &spl->head; +- spin_lock(&spl->spin); +- list_for_each_entry(key, head, dk_list) +- dy_adx((void *)key, do_dx); +- spin_unlock(&spl->spin); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-void __init au_dy_init(void) +-{ +- int i; +- +- /* make sure that 'struct au_dykey *' can be any type */ +- BUILD_BUG_ON(offsetof(struct au_dyaop, da_key)); +- +- for (i = 0; i < AuDyLast; i++) +- au_spl_init(dynop + i); +-} +- +-void au_dy_fin(void) +-{ +- int i; +- +- for (i = 0; i < AuDyLast; i++) +- WARN_ON(!list_empty(&dynop[i].head)); +-} +diff --git a/fs/aufs/dynop.h b/fs/aufs/dynop.h +deleted file mode 100644 +index 3f2c9aa..0000000 +--- a/fs/aufs/dynop.h ++++ /dev/null +@@ -1,76 +0,0 @@ +-/* +- * Copyright (C) 2010-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * dynamically customizable operations (for regular files only) +- */ +- +-#ifndef __AUFS_DYNOP_H__ +-#define __AUFS_DYNOP_H__ +- +-#ifdef __KERNEL__ +- +-#include "inode.h" +- +-enum {AuDy_AOP, AuDyLast}; +- +-struct au_dynop { +- int dy_type; +- union { +- const void *dy_hop; +- const struct address_space_operations *dy_haop; +- }; +-}; +- +-struct au_dykey { +- union { +- struct list_head dk_list; +- struct rcu_head dk_rcu; +- }; +- struct au_dynop dk_op; +- +- /* +- * during I am in the branch local array, kref is gotten. when the +- * branch is removed, kref is put. +- */ +- struct kref dk_kref; +-}; +- +-/* stop unioning since their sizes are very different from each other */ +-struct au_dyaop { +- struct au_dykey da_key; +- struct address_space_operations da_op; /* not const */ +- int (*da_get_xip_mem)(struct address_space *, pgoff_t, int, +- void **, unsigned long *); +-}; +- +-/* ---------------------------------------------------------------------- */ +- +-/* dynop.c */ +-struct au_branch; +-void au_dy_put(struct au_dykey *key); +-int au_dy_iaop(struct inode *inode, aufs_bindex_t bindex, +- struct inode *h_inode); +-int au_dy_irefresh(struct inode *inode); +-void au_dy_arefresh(int do_dio); +- +-void __init au_dy_init(void); +-void au_dy_fin(void); +- +-#endif /* __KERNEL__ */ +-#endif /* __AUFS_DYNOP_H__ */ +diff --git a/fs/aufs/export.c b/fs/aufs/export.c +deleted file mode 100644 +index 0579e38..0000000 +--- a/fs/aufs/export.c ++++ /dev/null +@@ -1,827 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * export via nfs +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include "../fs/mount.h" +-#include "aufs.h" +- +-union conv { +-#ifdef CONFIG_AUFS_INO_T_64 +- __u32 a[2]; +-#else +- __u32 a[1]; +-#endif +- ino_t ino; +-}; +- +-static ino_t decode_ino(__u32 *a) +-{ +- union conv u; +- +- BUILD_BUG_ON(sizeof(u.ino) != sizeof(u.a)); +- u.a[0] = a[0]; +-#ifdef CONFIG_AUFS_INO_T_64 +- u.a[1] = a[1]; +-#endif +- return u.ino; +-} +- +-static void encode_ino(__u32 *a, ino_t ino) +-{ +- union conv u; +- +- u.ino = ino; +- a[0] = u.a[0]; +-#ifdef CONFIG_AUFS_INO_T_64 +- a[1] = u.a[1]; +-#endif +-} +- +-/* NFS file handle */ +-enum { +- Fh_br_id, +- Fh_sigen, +-#ifdef CONFIG_AUFS_INO_T_64 +- /* support 64bit inode number */ +- Fh_ino1, +- Fh_ino2, +- Fh_dir_ino1, +- Fh_dir_ino2, +-#else +- Fh_ino1, +- Fh_dir_ino1, +-#endif +- Fh_igen, +- Fh_h_type, +- Fh_tail, +- +- Fh_ino = Fh_ino1, +- Fh_dir_ino = Fh_dir_ino1 +-}; +- +-static int au_test_anon(struct dentry *dentry) +-{ +- /* note: read d_flags without d_lock */ +- return !!(dentry->d_flags & DCACHE_DISCONNECTED); +-} +- +-int au_test_nfsd(void) +-{ +- int ret; +- struct task_struct *tsk = current; +- char comm[sizeof(tsk->comm)]; +- +- ret = 0; +- if (tsk->flags & PF_KTHREAD) { +- get_task_comm(comm, tsk); +- ret = !strcmp(comm, "nfsd"); +- } +- +- return ret; +-} +- +-/* ---------------------------------------------------------------------- */ +-/* inode generation external table */ +- +-void au_xigen_inc(struct inode *inode) +-{ +- loff_t pos; +- ssize_t sz; +- __u32 igen; +- struct super_block *sb; +- struct au_sbinfo *sbinfo; +- +- sb = inode->i_sb; +- AuDebugOn(!au_opt_test(au_mntflags(sb), XINO)); +- +- sbinfo = au_sbi(sb); +- pos = inode->i_ino; +- pos *= sizeof(igen); +- igen = inode->i_generation + 1; +- sz = xino_fwrite(sbinfo->si_xwrite, sbinfo->si_xigen, &igen, +- sizeof(igen), &pos); +- if (sz == sizeof(igen)) +- return; /* success */ +- +- if (unlikely(sz >= 0)) +- AuIOErr("xigen error (%zd)\n", sz); +-} +- +-int au_xigen_new(struct inode *inode) +-{ +- int err; +- loff_t pos; +- ssize_t sz; +- struct super_block *sb; +- struct au_sbinfo *sbinfo; +- struct file *file; +- +- err = 0; +- /* todo: dirty, at mount time */ +- if (inode->i_ino == AUFS_ROOT_INO) +- goto out; +- sb = inode->i_sb; +- SiMustAnyLock(sb); +- if (unlikely(!au_opt_test(au_mntflags(sb), XINO))) +- goto out; +- +- err = -EFBIG; +- pos = inode->i_ino; +- if (unlikely(au_loff_max / sizeof(inode->i_generation) - 1 < pos)) { +- AuIOErr1("too large i%lld\n", pos); +- goto out; +- } +- pos *= sizeof(inode->i_generation); +- +- err = 0; +- sbinfo = au_sbi(sb); +- file = sbinfo->si_xigen; +- BUG_ON(!file); +- +- if (i_size_read(file->f_dentry->d_inode) +- < pos + sizeof(inode->i_generation)) { +- inode->i_generation = atomic_inc_return(&sbinfo->si_xigen_next); +- sz = xino_fwrite(sbinfo->si_xwrite, file, &inode->i_generation, +- sizeof(inode->i_generation), &pos); +- } else +- sz = xino_fread(sbinfo->si_xread, file, &inode->i_generation, +- sizeof(inode->i_generation), &pos); +- if (sz == sizeof(inode->i_generation)) +- goto out; /* success */ +- +- err = sz; +- if (unlikely(sz >= 0)) { +- err = -EIO; +- AuIOErr("xigen error (%zd)\n", sz); +- } +- +-out: +- return err; +-} +- +-int au_xigen_set(struct super_block *sb, struct file *base) +-{ +- int err; +- struct au_sbinfo *sbinfo; +- struct file *file; +- +- SiMustWriteLock(sb); +- +- sbinfo = au_sbi(sb); +- file = au_xino_create2(base, sbinfo->si_xigen); +- err = PTR_ERR(file); +- if (IS_ERR(file)) +- goto out; +- err = 0; +- if (sbinfo->si_xigen) +- fput(sbinfo->si_xigen); +- sbinfo->si_xigen = file; +- +-out: +- return err; +-} +- +-void au_xigen_clr(struct super_block *sb) +-{ +- struct au_sbinfo *sbinfo; +- +- SiMustWriteLock(sb); +- +- sbinfo = au_sbi(sb); +- if (sbinfo->si_xigen) { +- fput(sbinfo->si_xigen); +- sbinfo->si_xigen = NULL; +- } +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static struct dentry *decode_by_ino(struct super_block *sb, ino_t ino, +- ino_t dir_ino) +-{ +- struct dentry *dentry, *d; +- struct inode *inode; +- unsigned int sigen; +- struct hlist_node *p; +- +- dentry = NULL; +- inode = ilookup(sb, ino); +- if (!inode) +- goto out; +- +- dentry = ERR_PTR(-ESTALE); +- sigen = au_sigen(sb); +- if (unlikely(is_bad_inode(inode) +- || IS_DEADDIR(inode) +- || sigen != au_iigen(inode, NULL))) +- goto out_iput; +- +- dentry = NULL; +- if (!dir_ino || S_ISDIR(inode->i_mode)) +- dentry = d_find_alias(inode); +- else { +- spin_lock(&inode->i_lock); +- hlist_for_each_entry(d, p, &inode->i_dentry, d_alias) { +- spin_lock(&d->d_lock); +- if (!au_test_anon(d) +- && d->d_parent->d_inode->i_ino == dir_ino) { +- dentry = dget_dlock(d); +- spin_unlock(&d->d_lock); +- break; +- } +- spin_unlock(&d->d_lock); +- } +- spin_unlock(&inode->i_lock); +- } +- if (unlikely(dentry && au_digen_test(dentry, sigen))) { +- /* need to refresh */ +- dput(dentry); +- dentry = NULL; +- } +- +-out_iput: +- iput(inode); +-out: +- AuTraceErrPtr(dentry); +- return dentry; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* todo: dirty? */ +-/* if exportfs_decode_fh() passed vfsmount*, we could be happy */ +- +-struct au_compare_mnt_args { +- /* input */ +- struct super_block *sb; +- +- /* output */ +- struct vfsmount *mnt; +-}; +- +-static int au_compare_mnt(struct vfsmount *mnt, void *arg) +-{ +- struct au_compare_mnt_args *a = arg; +- +- if (mnt->mnt_sb != a->sb) +- return 0; +- a->mnt = mntget(mnt); +- return 1; +-} +- +-static struct vfsmount *au_mnt_get(struct super_block *sb) +-{ +- int err; +- struct path root; +- struct au_compare_mnt_args args = { +- .sb = sb +- }; +- +- get_fs_root(current->fs, &root); +- br_read_lock(&vfsmount_lock); +- err = iterate_mounts(au_compare_mnt, &args, root.mnt); +- br_read_unlock(&vfsmount_lock); +- path_put(&root); +- AuDebugOn(!err); +- AuDebugOn(!args.mnt); +- return args.mnt; +-} +- +-struct au_nfsd_si_lock { +- unsigned int sigen; +- aufs_bindex_t bindex, br_id; +- unsigned char force_lock; +-}; +- +-static int si_nfsd_read_lock(struct super_block *sb, +- struct au_nfsd_si_lock *nsi_lock) +-{ +- int err; +- aufs_bindex_t bindex; +- +- si_read_lock(sb, AuLock_FLUSH); +- +- /* branch id may be wrapped around */ +- err = 0; +- bindex = au_br_index(sb, nsi_lock->br_id); +- if (bindex >= 0 && nsi_lock->sigen + AUFS_BRANCH_MAX > au_sigen(sb)) +- goto out; /* success */ +- +- err = -ESTALE; +- bindex = -1; +- if (!nsi_lock->force_lock) +- si_read_unlock(sb); +- +-out: +- nsi_lock->bindex = bindex; +- return err; +-} +- +-struct find_name_by_ino { +- int called, found; +- ino_t ino; +- char *name; +- int namelen; +-}; +- +-static int +-find_name_by_ino(void *arg, const char *name, int namelen, loff_t offset, +- u64 ino, unsigned int d_type) +-{ +- struct find_name_by_ino *a = arg; +- +- a->called++; +- if (a->ino != ino) +- return 0; +- +- memcpy(a->name, name, namelen); +- a->namelen = namelen; +- a->found = 1; +- return 1; +-} +- +-static struct dentry *au_lkup_by_ino(struct path *path, ino_t ino, +- struct au_nfsd_si_lock *nsi_lock) +-{ +- struct dentry *dentry, *parent; +- struct file *file; +- struct inode *dir; +- struct find_name_by_ino arg; +- int err; +- +- parent = path->dentry; +- if (nsi_lock) +- si_read_unlock(parent->d_sb); +- file = vfsub_dentry_open(path, au_dir_roflags); +- dentry = (void *)file; +- if (IS_ERR(file)) +- goto out; +- +- dentry = ERR_PTR(-ENOMEM); +- arg.name = (void *)__get_free_page(GFP_NOFS); +- if (unlikely(!arg.name)) +- goto out_file; +- arg.ino = ino; +- arg.found = 0; +- do { +- arg.called = 0; +- /* smp_mb(); */ +- err = vfsub_readdir(file, find_name_by_ino, &arg); +- } while (!err && !arg.found && arg.called); +- dentry = ERR_PTR(err); +- if (unlikely(err)) +- goto out_name; +- /* instead of ENOENT */ +- dentry = ERR_PTR(-ESTALE); +- if (!arg.found) +- goto out_name; +- +- /* do not call vfsub_lkup_one() */ +- dir = parent->d_inode; +- mutex_lock(&dir->i_mutex); +- dentry = vfsub_lookup_one_len(arg.name, parent, arg.namelen); +- mutex_unlock(&dir->i_mutex); +- AuTraceErrPtr(dentry); +- if (IS_ERR(dentry)) +- goto out_name; +- AuDebugOn(au_test_anon(dentry)); +- if (unlikely(!dentry->d_inode)) { +- dput(dentry); +- dentry = ERR_PTR(-ENOENT); +- } +- +-out_name: +- free_page((unsigned long)arg.name); +-out_file: +- fput(file); +-out: +- if (unlikely(nsi_lock +- && si_nfsd_read_lock(parent->d_sb, nsi_lock) < 0)) +- if (!IS_ERR(dentry)) { +- dput(dentry); +- dentry = ERR_PTR(-ESTALE); +- } +- AuTraceErrPtr(dentry); +- return dentry; +-} +- +-static struct dentry *decode_by_dir_ino(struct super_block *sb, ino_t ino, +- ino_t dir_ino, +- struct au_nfsd_si_lock *nsi_lock) +-{ +- struct dentry *dentry; +- struct path path; +- +- if (dir_ino != AUFS_ROOT_INO) { +- path.dentry = decode_by_ino(sb, dir_ino, 0); +- dentry = path.dentry; +- if (!path.dentry || IS_ERR(path.dentry)) +- goto out; +- AuDebugOn(au_test_anon(path.dentry)); +- } else +- path.dentry = dget(sb->s_root); +- +- path.mnt = au_mnt_get(sb); +- dentry = au_lkup_by_ino(&path, ino, nsi_lock); +- path_put(&path); +- +-out: +- AuTraceErrPtr(dentry); +- return dentry; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static int h_acceptable(void *expv, struct dentry *dentry) +-{ +- return 1; +-} +- +-static char *au_build_path(struct dentry *h_parent, struct path *h_rootpath, +- char *buf, int len, struct super_block *sb) +-{ +- char *p; +- int n; +- struct path path; +- +- p = d_path(h_rootpath, buf, len); +- if (IS_ERR(p)) +- goto out; +- n = strlen(p); +- +- path.mnt = h_rootpath->mnt; +- path.dentry = h_parent; +- p = d_path(&path, buf, len); +- if (IS_ERR(p)) +- goto out; +- if (n != 1) +- p += n; +- +- path.mnt = au_mnt_get(sb); +- path.dentry = sb->s_root; +- p = d_path(&path, buf, len - strlen(p)); +- mntput(path.mnt); +- if (IS_ERR(p)) +- goto out; +- if (n != 1) +- p[strlen(p)] = '/'; +- +-out: +- AuTraceErrPtr(p); +- return p; +-} +- +-static +-struct dentry *decode_by_path(struct super_block *sb, ino_t ino, __u32 *fh, +- int fh_len, struct au_nfsd_si_lock *nsi_lock) +-{ +- struct dentry *dentry, *h_parent, *root; +- struct super_block *h_sb; +- char *pathname, *p; +- struct vfsmount *h_mnt; +- struct au_branch *br; +- int err; +- struct path path; +- +- br = au_sbr(sb, nsi_lock->bindex); +- h_mnt = br->br_mnt; +- h_sb = h_mnt->mnt_sb; +- /* todo: call lower fh_to_dentry()? fh_to_parent()? */ +- h_parent = exportfs_decode_fh(h_mnt, (void *)(fh + Fh_tail), +- fh_len - Fh_tail, fh[Fh_h_type], +- h_acceptable, /*context*/NULL); +- dentry = h_parent; +- if (unlikely(!h_parent || IS_ERR(h_parent))) { +- AuWarn1("%s decode_fh failed, %ld\n", +- au_sbtype(h_sb), PTR_ERR(h_parent)); +- goto out; +- } +- dentry = NULL; +- if (unlikely(au_test_anon(h_parent))) { +- AuWarn1("%s decode_fh returned a disconnected dentry\n", +- au_sbtype(h_sb)); +- goto out_h_parent; +- } +- +- dentry = ERR_PTR(-ENOMEM); +- pathname = (void *)__get_free_page(GFP_NOFS); +- if (unlikely(!pathname)) +- goto out_h_parent; +- +- root = sb->s_root; +- path.mnt = h_mnt; +- di_read_lock_parent(root, !AuLock_IR); +- path.dentry = au_h_dptr(root, nsi_lock->bindex); +- di_read_unlock(root, !AuLock_IR); +- p = au_build_path(h_parent, &path, pathname, PAGE_SIZE, sb); +- dentry = (void *)p; +- if (IS_ERR(p)) +- goto out_pathname; +- +- si_read_unlock(sb); +- err = vfsub_kern_path(p, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); +- dentry = ERR_PTR(err); +- if (unlikely(err)) +- goto out_relock; +- +- dentry = ERR_PTR(-ENOENT); +- AuDebugOn(au_test_anon(path.dentry)); +- if (unlikely(!path.dentry->d_inode)) +- goto out_path; +- +- if (ino != path.dentry->d_inode->i_ino) +- dentry = au_lkup_by_ino(&path, ino, /*nsi_lock*/NULL); +- else +- dentry = dget(path.dentry); +- +-out_path: +- path_put(&path); +-out_relock: +- if (unlikely(si_nfsd_read_lock(sb, nsi_lock) < 0)) +- if (!IS_ERR(dentry)) { +- dput(dentry); +- dentry = ERR_PTR(-ESTALE); +- } +-out_pathname: +- free_page((unsigned long)pathname); +-out_h_parent: +- dput(h_parent); +-out: +- AuTraceErrPtr(dentry); +- return dentry; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static struct dentry * +-aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, +- int fh_type) +-{ +- struct dentry *dentry; +- __u32 *fh = fid->raw; +- struct au_branch *br; +- ino_t ino, dir_ino; +- struct au_nfsd_si_lock nsi_lock = { +- .force_lock = 0 +- }; +- +- dentry = ERR_PTR(-ESTALE); +- /* it should never happen, but the file handle is unreliable */ +- if (unlikely(fh_len < Fh_tail)) +- goto out; +- nsi_lock.sigen = fh[Fh_sigen]; +- nsi_lock.br_id = fh[Fh_br_id]; +- +- /* branch id may be wrapped around */ +- br = NULL; +- if (unlikely(si_nfsd_read_lock(sb, &nsi_lock))) +- goto out; +- nsi_lock.force_lock = 1; +- +- /* is this inode still cached? */ +- ino = decode_ino(fh + Fh_ino); +- /* it should never happen */ +- if (unlikely(ino == AUFS_ROOT_INO)) +- goto out; +- +- dir_ino = decode_ino(fh + Fh_dir_ino); +- dentry = decode_by_ino(sb, ino, dir_ino); +- if (IS_ERR(dentry)) +- goto out_unlock; +- if (dentry) +- goto accept; +- +- /* is the parent dir cached? */ +- br = au_sbr(sb, nsi_lock.bindex); +- atomic_inc(&br->br_count); +- dentry = decode_by_dir_ino(sb, ino, dir_ino, &nsi_lock); +- if (IS_ERR(dentry)) +- goto out_unlock; +- if (dentry) +- goto accept; +- +- /* lookup path */ +- dentry = decode_by_path(sb, ino, fh, fh_len, &nsi_lock); +- if (IS_ERR(dentry)) +- goto out_unlock; +- if (unlikely(!dentry)) +- /* todo?: make it ESTALE */ +- goto out_unlock; +- +-accept: +- if (!au_digen_test(dentry, au_sigen(sb)) +- && dentry->d_inode->i_generation == fh[Fh_igen]) +- goto out_unlock; /* success */ +- +- dput(dentry); +- dentry = ERR_PTR(-ESTALE); +-out_unlock: +- if (br) +- atomic_dec(&br->br_count); +- si_read_unlock(sb); +-out: +- AuTraceErrPtr(dentry); +- return dentry; +-} +- +-#if 0 /* reserved for future use */ +-/* support subtreecheck option */ +-static struct dentry *aufs_fh_to_parent(struct super_block *sb, struct fid *fid, +- int fh_len, int fh_type) +-{ +- struct dentry *parent; +- __u32 *fh = fid->raw; +- ino_t dir_ino; +- +- dir_ino = decode_ino(fh + Fh_dir_ino); +- parent = decode_by_ino(sb, dir_ino, 0); +- if (IS_ERR(parent)) +- goto out; +- if (!parent) +- parent = decode_by_path(sb, au_br_index(sb, fh[Fh_br_id]), +- dir_ino, fh, fh_len); +- +-out: +- AuTraceErrPtr(parent); +- return parent; +-} +-#endif +- +-/* ---------------------------------------------------------------------- */ +- +-static int aufs_encode_fh(struct inode *inode, __u32 *fh, int *max_len, +- struct inode *dir) +-{ +- int err; +- aufs_bindex_t bindex; +- struct super_block *sb, *h_sb; +- struct dentry *dentry, *parent, *h_parent; +- struct inode *h_dir; +- struct au_branch *br; +- +- err = -ENOSPC; +- if (unlikely(*max_len <= Fh_tail)) { +- AuWarn1("NFSv2 client (max_len %d)?\n", *max_len); +- goto out; +- } +- +- err = FILEID_ROOT; +- if (inode->i_ino == AUFS_ROOT_INO) { +- AuDebugOn(inode->i_ino != AUFS_ROOT_INO); +- goto out; +- } +- +- h_parent = NULL; +- sb = inode->i_sb; +- err = si_read_lock(sb, AuLock_FLUSH); +- if (unlikely(err)) +- goto out; +- +-#ifdef CONFIG_AUFS_DEBUG +- if (unlikely(!au_opt_test(au_mntflags(sb), XINO))) +- AuWarn1("NFS-exporting requires xino\n"); +-#endif +- err = -EIO; +- parent = NULL; +- ii_read_lock_child(inode); +- bindex = au_ibstart(inode); +- if (!dir) { +- dentry = d_find_alias(inode); +- if (unlikely(!dentry)) +- goto out_unlock; +- AuDebugOn(au_test_anon(dentry)); +- parent = dget_parent(dentry); +- dput(dentry); +- if (unlikely(!parent)) +- goto out_unlock; +- dir = parent->d_inode; +- } +- +- ii_read_lock_parent(dir); +- h_dir = au_h_iptr(dir, bindex); +- ii_read_unlock(dir); +- if (unlikely(!h_dir)) +- goto out_parent; +- h_parent = d_find_alias(h_dir); +- if (unlikely(!h_parent)) +- goto out_hparent; +- +- err = -EPERM; +- br = au_sbr(sb, bindex); +- h_sb = br->br_mnt->mnt_sb; +- if (unlikely(!h_sb->s_export_op)) { +- AuErr1("%s branch is not exportable\n", au_sbtype(h_sb)); +- goto out_hparent; +- } +- +- fh[Fh_br_id] = br->br_id; +- fh[Fh_sigen] = au_sigen(sb); +- encode_ino(fh + Fh_ino, inode->i_ino); +- encode_ino(fh + Fh_dir_ino, dir->i_ino); +- fh[Fh_igen] = inode->i_generation; +- +- *max_len -= Fh_tail; +- fh[Fh_h_type] = exportfs_encode_fh(h_parent, (void *)(fh + Fh_tail), +- max_len, +- /*connectable or subtreecheck*/0); +- err = fh[Fh_h_type]; +- *max_len += Fh_tail; +- /* todo: macros? */ +- if (err != FILEID_INVALID) +- err = 99; +- else +- AuWarn1("%s encode_fh failed\n", au_sbtype(h_sb)); +- +-out_hparent: +- dput(h_parent); +-out_parent: +- dput(parent); +-out_unlock: +- ii_read_unlock(inode); +- si_read_unlock(sb); +-out: +- if (unlikely(err < 0)) +- err = FILEID_INVALID; +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static int aufs_commit_metadata(struct inode *inode) +-{ +- int err; +- aufs_bindex_t bindex; +- struct super_block *sb; +- struct inode *h_inode; +- int (*f)(struct inode *inode); +- +- sb = inode->i_sb; +- si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); +- ii_write_lock_child(inode); +- bindex = au_ibstart(inode); +- AuDebugOn(bindex < 0); +- h_inode = au_h_iptr(inode, bindex); +- +- f = h_inode->i_sb->s_export_op->commit_metadata; +- if (f) +- err = f(h_inode); +- else { +- struct writeback_control wbc = { +- .sync_mode = WB_SYNC_ALL, +- .nr_to_write = 0 /* metadata only */ +- }; +- +- err = sync_inode(h_inode, &wbc); +- } +- +- au_cpup_attr_timesizes(inode); +- ii_write_unlock(inode); +- si_read_unlock(sb); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static struct export_operations aufs_export_op = { +- .fh_to_dentry = aufs_fh_to_dentry, +- /* .fh_to_parent = aufs_fh_to_parent, */ +- .encode_fh = aufs_encode_fh, +- .commit_metadata = aufs_commit_metadata +-}; +- +-void au_export_init(struct super_block *sb) +-{ +- struct au_sbinfo *sbinfo; +- __u32 u; +- +- sb->s_export_op = &aufs_export_op; +- sbinfo = au_sbi(sb); +- sbinfo->si_xigen = NULL; +- get_random_bytes(&u, sizeof(u)); +- BUILD_BUG_ON(sizeof(u) != sizeof(int)); +- atomic_set(&sbinfo->si_xigen_next, u); +-} +diff --git a/fs/aufs/f_op.c b/fs/aufs/f_op.c +deleted file mode 100644 +index 5c35454..0000000 +--- a/fs/aufs/f_op.c ++++ /dev/null +@@ -1,723 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * file and vm operations +- */ +- +-#include +-#include +-#include +-#include "aufs.h" +- +-int au_do_open_nondir(struct file *file, int flags) +-{ +- int err; +- aufs_bindex_t bindex; +- struct file *h_file; +- struct dentry *dentry; +- struct au_finfo *finfo; +- +- FiMustWriteLock(file); +- +- dentry = file->f_dentry; +- err = au_d_alive(dentry); +- if (unlikely(err)) +- goto out; +- +- finfo = au_fi(file); +- memset(&finfo->fi_htop, 0, sizeof(finfo->fi_htop)); +- atomic_set(&finfo->fi_mmapped, 0); +- bindex = au_dbstart(dentry); +- h_file = au_h_open(dentry, bindex, flags, file); +- if (IS_ERR(h_file)) +- err = PTR_ERR(h_file); +- else { +- au_set_fbstart(file, bindex); +- au_set_h_fptr(file, bindex, h_file); +- au_update_figen(file); +- /* todo: necessary? */ +- /* file->f_ra = h_file->f_ra; */ +- } +- +-out: +- return err; +-} +- +-static int aufs_open_nondir(struct inode *inode __maybe_unused, +- struct file *file) +-{ +- int err; +- struct super_block *sb; +- +- AuDbg("%.*s, f_flags 0x%x, f_mode 0x%x\n", +- AuDLNPair(file->f_dentry), vfsub_file_flags(file), +- file->f_mode); +- +- sb = file->f_dentry->d_sb; +- si_read_lock(sb, AuLock_FLUSH); +- err = au_do_open(file, au_do_open_nondir, /*fidir*/NULL); +- si_read_unlock(sb); +- return err; +-} +- +-int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file) +-{ +- struct au_finfo *finfo; +- aufs_bindex_t bindex; +- +- finfo = au_fi(file); +- bindex = finfo->fi_btop; +- if (bindex >= 0) +- au_set_h_fptr(file, bindex, NULL); +- +- au_finfo_fin(file); +- return 0; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static int au_do_flush_nondir(struct file *file, fl_owner_t id) +-{ +- int err; +- struct file *h_file; +- +- err = 0; +- h_file = au_hf_top(file); +- if (h_file) +- err = vfsub_flush(h_file, id); +- return err; +-} +- +-static int aufs_flush_nondir(struct file *file, fl_owner_t id) +-{ +- return au_do_flush(file, id, au_do_flush_nondir); +-} +- +-/* ---------------------------------------------------------------------- */ +-/* +- * read and write functions acquire [fdi]_rwsem once, but release before +- * mmap_sem. This is because to stop a race condition between mmap(2). +- * Releasing these aufs-rwsem should be safe, no branch-mamagement (by keeping +- * si_rwsem), no harmful copy-up should happen. Actually copy-up may happen in +- * read functions after [fdi]_rwsem are released, but it should be harmless. +- */ +- +-static ssize_t aufs_read(struct file *file, char __user *buf, size_t count, +- loff_t *ppos) +-{ +- ssize_t err; +- struct dentry *dentry; +- struct file *h_file; +- struct super_block *sb; +- +- dentry = file->f_dentry; +- sb = dentry->d_sb; +- si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); +- err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0); +- if (unlikely(err)) +- goto out; +- +- h_file = au_hf_top(file); +- get_file(h_file); +- di_read_unlock(dentry, AuLock_IR); +- fi_read_unlock(file); +- +- /* filedata may be obsoleted by concurrent copyup, but no problem */ +- err = vfsub_read_u(h_file, buf, count, ppos); +- /* todo: necessary? */ +- /* file->f_ra = h_file->f_ra; */ +- /* update without lock, I don't think it a problem */ +- fsstack_copy_attr_atime(dentry->d_inode, h_file->f_dentry->d_inode); +- fput(h_file); +- +-out: +- si_read_unlock(sb); +- return err; +-} +- +-/* +- * todo: very ugly +- * it locks both of i_mutex and si_rwsem for read in safe. +- * if the plink maintenance mode continues forever (that is the problem), +- * may loop forever. +- */ +-static void au_mtx_and_read_lock(struct inode *inode) +-{ +- int err; +- struct super_block *sb = inode->i_sb; +- +- while (1) { +- mutex_lock(&inode->i_mutex); +- err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); +- if (!err) +- break; +- mutex_unlock(&inode->i_mutex); +- si_read_lock(sb, AuLock_NOPLMW); +- si_read_unlock(sb); +- } +-} +- +-static ssize_t aufs_write(struct file *file, const char __user *ubuf, +- size_t count, loff_t *ppos) +-{ +- ssize_t err; +- struct au_pin pin; +- struct dentry *dentry; +- struct super_block *sb; +- struct inode *inode; +- struct file *h_file; +- char __user *buf = (char __user *)ubuf; +- +- dentry = file->f_dentry; +- sb = dentry->d_sb; +- inode = dentry->d_inode; +- au_mtx_and_read_lock(inode); +- +- err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); +- if (unlikely(err)) +- goto out; +- +- err = au_ready_to_write(file, -1, &pin); +- di_downgrade_lock(dentry, AuLock_IR); +- if (unlikely(err)) { +- di_read_unlock(dentry, AuLock_IR); +- fi_write_unlock(file); +- goto out; +- } +- +- h_file = au_hf_top(file); +- get_file(h_file); +- au_unpin(&pin); +- di_read_unlock(dentry, AuLock_IR); +- fi_write_unlock(file); +- +- err = vfsub_write_u(h_file, buf, count, ppos); +- ii_write_lock_child(inode); +- au_cpup_attr_timesizes(inode); +- inode->i_mode = h_file->f_dentry->d_inode->i_mode; +- ii_write_unlock(inode); +- fput(h_file); +- +-out: +- si_read_unlock(sb); +- mutex_unlock(&inode->i_mutex); +- return err; +-} +- +-static ssize_t au_do_aio(struct file *h_file, int rw, struct kiocb *kio, +- const struct iovec *iov, unsigned long nv, loff_t pos) +-{ +- ssize_t err; +- struct file *file; +- ssize_t (*func)(struct kiocb *, const struct iovec *, unsigned long, +- loff_t); +- +- err = security_file_permission(h_file, rw); +- if (unlikely(err)) +- goto out; +- +- err = -ENOSYS; +- func = NULL; +- if (rw == MAY_READ) +- func = h_file->f_op->aio_read; +- else if (rw == MAY_WRITE) +- func = h_file->f_op->aio_write; +- if (func) { +- file = kio->ki_filp; +- kio->ki_filp = h_file; +- lockdep_off(); +- err = func(kio, iov, nv, pos); +- lockdep_on(); +- kio->ki_filp = file; +- } else +- /* currently there is no such fs */ +- WARN_ON_ONCE(1); +- +-out: +- return err; +-} +- +-static ssize_t aufs_aio_read(struct kiocb *kio, const struct iovec *iov, +- unsigned long nv, loff_t pos) +-{ +- ssize_t err; +- struct file *file, *h_file; +- struct dentry *dentry; +- struct super_block *sb; +- +- file = kio->ki_filp; +- dentry = file->f_dentry; +- sb = dentry->d_sb; +- si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); +- err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0); +- if (unlikely(err)) +- goto out; +- +- h_file = au_hf_top(file); +- get_file(h_file); +- di_read_unlock(dentry, AuLock_IR); +- fi_read_unlock(file); +- +- err = au_do_aio(h_file, MAY_READ, kio, iov, nv, pos); +- /* todo: necessary? */ +- /* file->f_ra = h_file->f_ra; */ +- /* update without lock, I don't think it a problem */ +- fsstack_copy_attr_atime(dentry->d_inode, h_file->f_dentry->d_inode); +- fput(h_file); +- +-out: +- si_read_unlock(sb); +- return err; +-} +- +-static ssize_t aufs_aio_write(struct kiocb *kio, const struct iovec *iov, +- unsigned long nv, loff_t pos) +-{ +- ssize_t err; +- struct au_pin pin; +- struct dentry *dentry; +- struct inode *inode; +- struct file *file, *h_file; +- struct super_block *sb; +- +- file = kio->ki_filp; +- dentry = file->f_dentry; +- sb = dentry->d_sb; +- inode = dentry->d_inode; +- au_mtx_and_read_lock(inode); +- +- err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); +- if (unlikely(err)) +- goto out; +- +- err = au_ready_to_write(file, -1, &pin); +- di_downgrade_lock(dentry, AuLock_IR); +- if (unlikely(err)) { +- di_read_unlock(dentry, AuLock_IR); +- fi_write_unlock(file); +- goto out; +- } +- +- h_file = au_hf_top(file); +- get_file(h_file); +- au_unpin(&pin); +- di_read_unlock(dentry, AuLock_IR); +- fi_write_unlock(file); +- +- err = au_do_aio(h_file, MAY_WRITE, kio, iov, nv, pos); +- ii_write_lock_child(inode); +- au_cpup_attr_timesizes(inode); +- inode->i_mode = h_file->f_dentry->d_inode->i_mode; +- ii_write_unlock(inode); +- fput(h_file); +- +-out: +- si_read_unlock(sb); +- mutex_unlock(&inode->i_mutex); +- return err; +-} +- +-static ssize_t aufs_splice_read(struct file *file, loff_t *ppos, +- struct pipe_inode_info *pipe, size_t len, +- unsigned int flags) +-{ +- ssize_t err; +- struct file *h_file; +- struct dentry *dentry; +- struct super_block *sb; +- +- dentry = file->f_dentry; +- sb = dentry->d_sb; +- si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); +- err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0); +- if (unlikely(err)) +- goto out; +- +- err = -EINVAL; +- h_file = au_hf_top(file); +- get_file(h_file); +- if (au_test_loopback_kthread()) { +- au_warn_loopback(h_file->f_dentry->d_sb); +- if (file->f_mapping != h_file->f_mapping) { +- file->f_mapping = h_file->f_mapping; +- smp_mb(); /* unnecessary? */ +- } +- } +- di_read_unlock(dentry, AuLock_IR); +- fi_read_unlock(file); +- +- err = vfsub_splice_to(h_file, ppos, pipe, len, flags); +- /* todo: necessasry? */ +- /* file->f_ra = h_file->f_ra; */ +- /* update without lock, I don't think it a problem */ +- fsstack_copy_attr_atime(dentry->d_inode, h_file->f_dentry->d_inode); +- fput(h_file); +- +-out: +- si_read_unlock(sb); +- return err; +-} +- +-static ssize_t +-aufs_splice_write(struct pipe_inode_info *pipe, struct file *file, loff_t *ppos, +- size_t len, unsigned int flags) +-{ +- ssize_t err; +- struct au_pin pin; +- struct dentry *dentry; +- struct inode *inode; +- struct file *h_file; +- struct super_block *sb; +- +- dentry = file->f_dentry; +- sb = dentry->d_sb; +- inode = dentry->d_inode; +- au_mtx_and_read_lock(inode); +- +- err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); +- if (unlikely(err)) +- goto out; +- +- err = au_ready_to_write(file, -1, &pin); +- di_downgrade_lock(dentry, AuLock_IR); +- if (unlikely(err)) { +- di_read_unlock(dentry, AuLock_IR); +- fi_write_unlock(file); +- goto out; +- } +- +- h_file = au_hf_top(file); +- get_file(h_file); +- au_unpin(&pin); +- di_read_unlock(dentry, AuLock_IR); +- fi_write_unlock(file); +- +- err = vfsub_splice_from(pipe, h_file, ppos, len, flags); +- ii_write_lock_child(inode); +- au_cpup_attr_timesizes(inode); +- inode->i_mode = h_file->f_dentry->d_inode->i_mode; +- ii_write_unlock(inode); +- fput(h_file); +- +-out: +- si_read_unlock(sb); +- mutex_unlock(&inode->i_mutex); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* +- * The locking order around current->mmap_sem. +- * - in most and regular cases +- * file I/O syscall -- aufs_read() or something +- * -- si_rwsem for read -- mmap_sem +- * (Note that [fdi]i_rwsem are released before mmap_sem). +- * - in mmap case +- * mmap(2) -- mmap_sem -- aufs_mmap() -- si_rwsem for read -- [fdi]i_rwsem +- * This AB-BA order is definitly bad, but is not a problem since "si_rwsem for +- * read" allows muliple processes to acquire it and [fdi]i_rwsem are not held in +- * file I/O. Aufs needs to stop lockdep in aufs_mmap() though. +- * It means that when aufs acquires si_rwsem for write, the process should never +- * acquire mmap_sem. +- * +- * Actually aufs_readdir() holds [fdi]i_rwsem before mmap_sem, but this is not a +- * problem either since any directory is not able to be mmap-ed. +- * The similar scenario is applied to aufs_readlink() too. +- */ +- +-/* cf. linux/include/linux/mman.h: calc_vm_prot_bits() */ +-#define AuConv_VM_PROT(f, b) _calc_vm_trans(f, VM_##b, PROT_##b) +- +-static unsigned long au_arch_prot_conv(unsigned long flags) +-{ +- /* currently ppc64 only */ +-#ifdef CONFIG_PPC64 +- /* cf. linux/arch/powerpc/include/asm/mman.h */ +- AuDebugOn(arch_calc_vm_prot_bits(-1) != VM_SAO); +- return AuConv_VM_PROT(flags, SAO); +-#else +- AuDebugOn(arch_calc_vm_prot_bits(-1)); +- return 0; +-#endif +-} +- +-static unsigned long au_prot_conv(unsigned long flags) +-{ +- return AuConv_VM_PROT(flags, READ) +- | AuConv_VM_PROT(flags, WRITE) +- | AuConv_VM_PROT(flags, EXEC) +- | au_arch_prot_conv(flags); +-} +- +-/* cf. linux/include/linux/mman.h: calc_vm_flag_bits() */ +-#define AuConv_VM_MAP(f, b) _calc_vm_trans(f, VM_##b, MAP_##b) +- +-static unsigned long au_flag_conv(unsigned long flags) +-{ +- return AuConv_VM_MAP(flags, GROWSDOWN) +- | AuConv_VM_MAP(flags, DENYWRITE) +- | AuConv_VM_MAP(flags, LOCKED); +-} +- +-static int aufs_mmap(struct file *file, struct vm_area_struct *vma) +-{ +- int err; +- aufs_bindex_t bstart; +- const unsigned char wlock +- = (file->f_mode & FMODE_WRITE) && (vma->vm_flags & VM_SHARED); +- struct dentry *dentry; +- struct super_block *sb; +- struct file *h_file; +- struct au_branch *br; +- struct au_pin pin; +- +- AuDbgVmRegion(file, vma); +- +- dentry = file->f_dentry; +- sb = dentry->d_sb; +- lockdep_off(); +- si_read_lock(sb, AuLock_NOPLMW); +- err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); +- if (unlikely(err)) +- goto out; +- +- if (wlock) { +- err = au_ready_to_write(file, -1, &pin); +- di_write_unlock(dentry); +- if (unlikely(err)) { +- fi_write_unlock(file); +- goto out; +- } +- au_unpin(&pin); +- } else +- di_write_unlock(dentry); +- +- bstart = au_fbstart(file); +- br = au_sbr(sb, bstart); +- h_file = au_hf_top(file); +- get_file(h_file); +- au_set_mmapped(file); +- fi_write_unlock(file); +- lockdep_on(); +- +- au_vm_file_reset(vma, h_file); +- err = security_mmap_file(h_file, au_prot_conv(vma->vm_flags), +- au_flag_conv(vma->vm_flags)); +- if (!err) +- err = h_file->f_op->mmap(h_file, vma); +- if (unlikely(err)) +- goto out_reset; +- +- au_vm_prfile_set(vma, file); +- /* update without lock, I don't think it a problem */ +- fsstack_copy_attr_atime(file->f_dentry->d_inode, +- h_file->f_dentry->d_inode); +- goto out_fput; /* success */ +- +-out_reset: +- au_unset_mmapped(file); +- au_vm_file_reset(vma, file); +-out_fput: +- fput(h_file); +- lockdep_off(); +-out: +- si_read_unlock(sb); +- lockdep_on(); +- AuTraceErr(err); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static int aufs_fsync_nondir(struct file *file, loff_t start, loff_t end, +- int datasync) +-{ +- int err; +- struct au_pin pin; +- struct dentry *dentry; +- struct inode *inode; +- struct file *h_file; +- struct super_block *sb; +- +- dentry = file->f_dentry; +- inode = dentry->d_inode; +- sb = dentry->d_sb; +- mutex_lock(&inode->i_mutex); +- err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); +- if (unlikely(err)) +- goto out; +- +- err = 0; /* -EBADF; */ /* posix? */ +- if (unlikely(!(file->f_mode & FMODE_WRITE))) +- goto out_si; +- err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); +- if (unlikely(err)) +- goto out_si; +- +- err = au_ready_to_write(file, -1, &pin); +- di_downgrade_lock(dentry, AuLock_IR); +- if (unlikely(err)) +- goto out_unlock; +- au_unpin(&pin); +- +- err = -EINVAL; +- h_file = au_hf_top(file); +- err = vfsub_fsync(h_file, &h_file->f_path, datasync); +- au_cpup_attr_timesizes(inode); +- +-out_unlock: +- di_read_unlock(dentry, AuLock_IR); +- fi_write_unlock(file); +-out_si: +- si_read_unlock(sb); +-out: +- mutex_unlock(&inode->i_mutex); +- return err; +-} +- +-/* no one supports this operation, currently */ +-#if 0 +-static int aufs_aio_fsync_nondir(struct kiocb *kio, int datasync) +-{ +- int err; +- struct au_pin pin; +- struct dentry *dentry; +- struct inode *inode; +- struct file *file, *h_file; +- +- file = kio->ki_filp; +- dentry = file->f_dentry; +- inode = dentry->d_inode; +- au_mtx_and_read_lock(inode); +- +- err = 0; /* -EBADF; */ /* posix? */ +- if (unlikely(!(file->f_mode & FMODE_WRITE))) +- goto out; +- err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); +- if (unlikely(err)) +- goto out; +- +- err = au_ready_to_write(file, -1, &pin); +- di_downgrade_lock(dentry, AuLock_IR); +- if (unlikely(err)) +- goto out_unlock; +- au_unpin(&pin); +- +- err = -ENOSYS; +- h_file = au_hf_top(file); +- if (h_file->f_op && h_file->f_op->aio_fsync) { +- struct dentry *h_d; +- struct mutex *h_mtx; +- +- h_d = h_file->f_dentry; +- h_mtx = &h_d->d_inode->i_mutex; +- if (!is_sync_kiocb(kio)) { +- get_file(h_file); +- fput(file); +- } +- kio->ki_filp = h_file; +- err = h_file->f_op->aio_fsync(kio, datasync); +- mutex_lock_nested(h_mtx, AuLsc_I_CHILD); +- if (!err) +- vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); +- /*ignore*/ +- au_cpup_attr_timesizes(inode); +- mutex_unlock(h_mtx); +- } +- +-out_unlock: +- di_read_unlock(dentry, AuLock_IR); +- fi_write_unlock(file); +-out: +- si_read_unlock(inode->sb); +- mutex_unlock(&inode->i_mutex); +- return err; +-} +-#endif +- +-static int aufs_fasync(int fd, struct file *file, int flag) +-{ +- int err; +- struct file *h_file; +- struct dentry *dentry; +- struct super_block *sb; +- +- dentry = file->f_dentry; +- sb = dentry->d_sb; +- si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); +- err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0); +- if (unlikely(err)) +- goto out; +- +- h_file = au_hf_top(file); +- if (h_file->f_op && h_file->f_op->fasync) +- err = h_file->f_op->fasync(fd, h_file, flag); +- +- di_read_unlock(dentry, AuLock_IR); +- fi_read_unlock(file); +- +-out: +- si_read_unlock(sb); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* no one supports this operation, currently */ +-#if 0 +-static ssize_t aufs_sendpage(struct file *file, struct page *page, int offset, +- size_t len, loff_t *pos , int more) +-{ +-} +-#endif +- +-/* ---------------------------------------------------------------------- */ +- +-const struct file_operations aufs_file_fop = { +- .owner = THIS_MODULE, +- +- .llseek = default_llseek, +- +- .read = aufs_read, +- .write = aufs_write, +- .aio_read = aufs_aio_read, +- .aio_write = aufs_aio_write, +-#ifdef CONFIG_AUFS_POLL +- .poll = aufs_poll, +-#endif +- .unlocked_ioctl = aufs_ioctl_nondir, +-#ifdef CONFIG_COMPAT +- .compat_ioctl = aufs_ioctl_nondir, /* same */ +-#endif +- .mmap = aufs_mmap, +- .open = aufs_open_nondir, +- .flush = aufs_flush_nondir, +- .release = aufs_release_nondir, +- .fsync = aufs_fsync_nondir, +- /* .aio_fsync = aufs_aio_fsync_nondir, */ +- .fasync = aufs_fasync, +- /* .sendpage = aufs_sendpage, */ +- .splice_write = aufs_splice_write, +- .splice_read = aufs_splice_read, +-#if 0 +- .aio_splice_write = aufs_aio_splice_write, +- .aio_splice_read = aufs_aio_splice_read +-#endif +-}; +diff --git a/fs/aufs/f_op_sp.c b/fs/aufs/f_op_sp.c +deleted file mode 100644 +index e2eb612..0000000 +--- a/fs/aufs/f_op_sp.c ++++ /dev/null +@@ -1,295 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * file operations for special files. +- * while they exist in aufs virtually, +- * their file I/O is handled out of aufs. +- */ +- +-#include "aufs.h" +- +-static ssize_t aufs_aio_read_sp(struct kiocb *kio, const struct iovec *iov, +- unsigned long nv, loff_t pos) +-{ +- ssize_t err; +- aufs_bindex_t bstart; +- unsigned char wbr; +- struct file *file, *h_file; +- struct super_block *sb; +- +- file = kio->ki_filp; +- sb = file->f_dentry->d_sb; +- si_read_lock(sb, AuLock_FLUSH); +- fi_read_lock(file); +- bstart = au_fbstart(file); +- h_file = au_hf_top(file); +- fi_read_unlock(file); +- wbr = !!au_br_writable(au_sbr(sb, bstart)->br_perm); +- si_read_unlock(sb); +- +- /* do not change the file in kio */ +- AuDebugOn(!h_file->f_op || !h_file->f_op->aio_read); +- err = h_file->f_op->aio_read(kio, iov, nv, pos); +- if (err > 0 && wbr) +- file_accessed(h_file); +- +- return err; +-} +- +-static ssize_t aufs_aio_write_sp(struct kiocb *kio, const struct iovec *iov, +- unsigned long nv, loff_t pos) +-{ +- ssize_t err; +- aufs_bindex_t bstart; +- unsigned char wbr; +- struct super_block *sb; +- struct file *file, *h_file; +- +- file = kio->ki_filp; +- sb = file->f_dentry->d_sb; +- si_read_lock(sb, AuLock_FLUSH); +- fi_read_lock(file); +- bstart = au_fbstart(file); +- h_file = au_hf_top(file); +- fi_read_unlock(file); +- wbr = !!au_br_writable(au_sbr(sb, bstart)->br_perm); +- si_read_unlock(sb); +- +- /* do not change the file in kio */ +- AuDebugOn(!h_file->f_op || !h_file->f_op->aio_write); +- err = h_file->f_op->aio_write(kio, iov, nv, pos); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static int aufs_release_sp(struct inode *inode, struct file *file) +-{ +- int err; +- struct file *h_file; +- +- fi_read_lock(file); +- h_file = au_hf_top(file); +- fi_read_unlock(file); +- /* close this fifo in aufs */ +- err = h_file->f_op->release(inode, file); /* ignore */ +- aufs_release_nondir(inode, file); /* ignore */ +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* currently, support only FIFO */ +-enum { +- AuSp_FIFO, AuSp_FIFO_R, AuSp_FIFO_W, AuSp_FIFO_RW, +- /* AuSp_SOCK, AuSp_CHR, AuSp_BLK, */ +- AuSp_Last +-}; +-static int aufs_open_sp(struct inode *inode, struct file *file); +-static struct au_sp_fop { +- int done; +- struct file_operations fop; /* not 'const' */ +- spinlock_t spin; +-} au_sp_fop[AuSp_Last] = { +- [AuSp_FIFO] = { +- .fop = { +- .owner = THIS_MODULE, +- .open = aufs_open_sp +- } +- } +-}; +- +-static void au_init_fop_sp(struct file *file) +-{ +- struct au_sp_fop *p; +- int i; +- struct file *h_file; +- +- p = au_sp_fop; +- if (unlikely(!p->done)) { +- /* initialize first time only */ +- static DEFINE_SPINLOCK(spin); +- +- spin_lock(&spin); +- if (!p->done) { +- BUILD_BUG_ON(sizeof(au_sp_fop)/sizeof(*au_sp_fop) +- != AuSp_Last); +- for (i = 0; i < AuSp_Last; i++) +- spin_lock_init(&p[i].spin); +- p->done = 1; +- } +- spin_unlock(&spin); +- } +- +- switch (file->f_mode & (FMODE_READ | FMODE_WRITE)) { +- case FMODE_READ: +- i = AuSp_FIFO_R; +- break; +- case FMODE_WRITE: +- i = AuSp_FIFO_W; +- break; +- case FMODE_READ | FMODE_WRITE: +- i = AuSp_FIFO_RW; +- break; +- default: +- BUG(); +- } +- +- p += i; +- if (unlikely(!p->done)) { +- /* initialize first time only */ +- h_file = au_hf_top(file); +- spin_lock(&p->spin); +- if (!p->done) { +- p->fop = *h_file->f_op; +- p->fop.owner = THIS_MODULE; +- if (p->fop.aio_read) +- p->fop.aio_read = aufs_aio_read_sp; +- if (p->fop.aio_write) +- p->fop.aio_write = aufs_aio_write_sp; +- p->fop.release = aufs_release_sp; +- p->done = 1; +- } +- spin_unlock(&p->spin); +- } +- file->f_op = &p->fop; +-} +- +-static int au_cpup_sp(struct dentry *dentry) +-{ +- int err; +- aufs_bindex_t bcpup; +- struct au_pin pin; +- struct au_wr_dir_args wr_dir_args = { +- .force_btgt = -1, +- .flags = 0 +- }; +- +- AuDbg("%.*s\n", AuDLNPair(dentry)); +- +- di_read_unlock(dentry, AuLock_IR); +- di_write_lock_child(dentry); +- err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args); +- if (unlikely(err < 0)) +- goto out; +- bcpup = err; +- err = 0; +- if (bcpup == au_dbstart(dentry)) +- goto out; /* success */ +- +- err = au_pin(&pin, dentry, bcpup, au_opt_udba(dentry->d_sb), +- AuPin_MNT_WRITE); +- if (!err) { +- err = au_sio_cpup_simple(dentry, bcpup, -1, AuCpup_DTIME); +- au_unpin(&pin); +- } +- +-out: +- di_downgrade_lock(dentry, AuLock_IR); +- return err; +-} +- +-static int au_do_open_sp(struct file *file, int flags) +-{ +- int err; +- struct dentry *dentry; +- struct super_block *sb; +- struct file *h_file; +- struct inode *h_inode; +- +- dentry = file->f_dentry; +- AuDbg("%.*s\n", AuDLNPair(dentry)); +- +- /* +- * try copying-up. +- * operate on the ro branch is not an error. +- */ +- au_cpup_sp(dentry); /* ignore */ +- +- /* prepare h_file */ +- err = au_do_open_nondir(file, vfsub_file_flags(file)); +- if (unlikely(err)) +- goto out; +- +- sb = dentry->d_sb; +- h_file = au_hf_top(file); +- h_inode = h_file->f_dentry->d_inode; +- di_read_unlock(dentry, AuLock_IR); +- fi_write_unlock(file); +- si_read_unlock(sb); +- /* open this fifo in aufs */ +- err = h_inode->i_fop->open(file->f_dentry->d_inode, file); +- si_noflush_read_lock(sb); +- fi_write_lock(file); +- di_read_lock_child(dentry, AuLock_IR); +- if (!err) +- au_init_fop_sp(file); +- +-out: +- return err; +-} +- +-static int aufs_open_sp(struct inode *inode, struct file *file) +-{ +- int err; +- struct super_block *sb; +- +- sb = file->f_dentry->d_sb; +- si_read_lock(sb, AuLock_FLUSH); +- err = au_do_open(file, au_do_open_sp, /*fidir*/NULL); +- si_read_unlock(sb); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-void au_init_special_fop(struct inode *inode, umode_t mode, dev_t rdev) +-{ +- init_special_inode(inode, mode, rdev); +- +- switch (mode & S_IFMT) { +- case S_IFIFO: +- inode->i_fop = &au_sp_fop[AuSp_FIFO].fop; +- /*FALLTHROUGH*/ +- case S_IFCHR: +- case S_IFBLK: +- case S_IFSOCK: +- break; +- default: +- AuDebugOn(1); +- } +-} +- +-int au_special_file(umode_t mode) +-{ +- int ret; +- +- ret = 0; +- switch (mode & S_IFMT) { +- case S_IFIFO: +-#if 0 +- case S_IFCHR: +- case S_IFBLK: +- case S_IFSOCK: +-#endif +- ret = 1; +- } +- +- return ret; +-} +diff --git a/fs/aufs/file.c b/fs/aufs/file.c +deleted file mode 100644 +index 5cffdc1..0000000 +--- a/fs/aufs/file.c ++++ /dev/null +@@ -1,683 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * handling file/dir, and address_space operation +- */ +- +-#ifdef CONFIG_AUFS_DEBUG +-#include +-#endif +-#include +-#include "aufs.h" +- +-/* drop flags for writing */ +-unsigned int au_file_roflags(unsigned int flags) +-{ +- flags &= ~(O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_TRUNC); +- flags |= O_RDONLY | O_NOATIME; +- return flags; +-} +- +-/* common functions to regular file and dir */ +-struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, +- struct file *file) +-{ +- struct file *h_file; +- struct dentry *h_dentry; +- struct inode *h_inode; +- struct super_block *sb; +- struct au_branch *br; +- struct path h_path; +- int err, exec_flag; +- +- /* a race condition can happen between open and unlink/rmdir */ +- h_file = ERR_PTR(-ENOENT); +- h_dentry = au_h_dptr(dentry, bindex); +- if (au_test_nfsd() && !h_dentry) +- goto out; +- h_inode = h_dentry->d_inode; +- if (au_test_nfsd() && !h_inode) +- goto out; +- spin_lock(&h_dentry->d_lock); +- err = (!d_unhashed(dentry) && d_unlinked(h_dentry)) +- || !h_inode +- /* || !dentry->d_inode->i_nlink */ +- ; +- spin_unlock(&h_dentry->d_lock); +- if (unlikely(err)) +- goto out; +- +- sb = dentry->d_sb; +- br = au_sbr(sb, bindex); +- h_file = ERR_PTR(-EACCES); +- exec_flag = flags & __FMODE_EXEC; +- if (exec_flag && (br->br_mnt->mnt_flags & MNT_NOEXEC)) +- goto out; +- +- /* drop flags for writing */ +- if (au_test_ro(sb, bindex, dentry->d_inode)) +- flags = au_file_roflags(flags); +- flags &= ~O_CREAT; +- atomic_inc(&br->br_count); +- h_path.dentry = h_dentry; +- h_path.mnt = br->br_mnt; +- if (!au_special_file(h_inode->i_mode)) +- h_file = vfsub_dentry_open(&h_path, flags); +- else { +- /* this block depends upon the configuration */ +- di_read_unlock(dentry, AuLock_IR); +- fi_write_unlock(file); +- si_read_unlock(sb); +- h_file = vfsub_dentry_open(&h_path, flags); +- si_noflush_read_lock(sb); +- fi_write_lock(file); +- di_read_lock_child(dentry, AuLock_IR); +- } +- if (IS_ERR(h_file)) +- goto out_br; +- +- if (exec_flag) { +- err = deny_write_access(h_file); +- if (unlikely(err)) { +- fput(h_file); +- h_file = ERR_PTR(err); +- goto out_br; +- } +- } +- fsnotify_open(h_file); +- goto out; /* success */ +- +-out_br: +- atomic_dec(&br->br_count); +-out: +- return h_file; +-} +- +-int au_do_open(struct file *file, int (*open)(struct file *file, int flags), +- struct au_fidir *fidir) +-{ +- int err; +- struct dentry *dentry; +- +- err = au_finfo_init(file, fidir); +- if (unlikely(err)) +- goto out; +- +- dentry = file->f_dentry; +- di_read_lock_child(dentry, AuLock_IR); +- err = open(file, vfsub_file_flags(file)); +- di_read_unlock(dentry, AuLock_IR); +- +- fi_write_unlock(file); +- if (unlikely(err)) { +- au_fi(file)->fi_hdir = NULL; +- au_finfo_fin(file); +- } +- +-out: +- return err; +-} +- +-int au_reopen_nondir(struct file *file) +-{ +- int err; +- aufs_bindex_t bstart; +- struct dentry *dentry; +- struct file *h_file, *h_file_tmp; +- +- dentry = file->f_dentry; +- AuDebugOn(au_special_file(dentry->d_inode->i_mode)); +- bstart = au_dbstart(dentry); +- h_file_tmp = NULL; +- if (au_fbstart(file) == bstart) { +- h_file = au_hf_top(file); +- if (file->f_mode == h_file->f_mode) +- return 0; /* success */ +- h_file_tmp = h_file; +- get_file(h_file_tmp); +- au_set_h_fptr(file, bstart, NULL); +- } +- AuDebugOn(au_fi(file)->fi_hdir); +- AuDebugOn(au_fbstart(file) < bstart); +- +- h_file = au_h_open(dentry, bstart, vfsub_file_flags(file) & ~O_TRUNC, +- file); +- err = PTR_ERR(h_file); +- if (IS_ERR(h_file)) +- goto out; /* todo: close all? */ +- +- err = 0; +- au_set_fbstart(file, bstart); +- au_set_h_fptr(file, bstart, h_file); +- au_update_figen(file); +- /* todo: necessary? */ +- /* file->f_ra = h_file->f_ra; */ +- +-out: +- if (h_file_tmp) +- fput(h_file_tmp); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static int au_reopen_wh(struct file *file, aufs_bindex_t btgt, +- struct dentry *hi_wh) +-{ +- int err; +- aufs_bindex_t bstart; +- struct au_dinfo *dinfo; +- struct dentry *h_dentry; +- struct au_hdentry *hdp; +- +- dinfo = au_di(file->f_dentry); +- AuRwMustWriteLock(&dinfo->di_rwsem); +- +- bstart = dinfo->di_bstart; +- dinfo->di_bstart = btgt; +- hdp = dinfo->di_hdentry; +- h_dentry = hdp[0 + btgt].hd_dentry; +- hdp[0 + btgt].hd_dentry = hi_wh; +- err = au_reopen_nondir(file); +- hdp[0 + btgt].hd_dentry = h_dentry; +- dinfo->di_bstart = bstart; +- +- return err; +-} +- +-static int au_ready_to_write_wh(struct file *file, loff_t len, +- aufs_bindex_t bcpup) +-{ +- int err; +- struct inode *inode, *h_inode; +- struct dentry *dentry, *h_dentry, *hi_wh; +- +- dentry = file->f_dentry; +- au_update_dbstart(dentry); +- inode = dentry->d_inode; +- h_inode = NULL; +- if (au_dbstart(dentry) <= bcpup && au_dbend(dentry) >= bcpup) { +- h_dentry = au_h_dptr(dentry, bcpup); +- if (h_dentry) +- h_inode = h_dentry->d_inode; +- } +- hi_wh = au_hi_wh(inode, bcpup); +- if (!hi_wh && !h_inode) +- err = au_sio_cpup_wh(dentry, bcpup, len, file); +- else +- /* already copied-up after unlink */ +- err = au_reopen_wh(file, bcpup, hi_wh); +- +- if (!err +- && inode->i_nlink > 1 +- && au_opt_test(au_mntflags(dentry->d_sb), PLINK)) +- au_plink_append(inode, bcpup, au_h_dptr(dentry, bcpup)); +- +- return err; +-} +- +-/* +- * prepare the @file for writing. +- */ +-int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin) +-{ +- int err; +- aufs_bindex_t bstart, bcpup, dbstart; +- struct dentry *dentry, *parent, *h_dentry; +- struct inode *h_inode, *inode; +- struct super_block *sb; +- struct file *h_file; +- +- dentry = file->f_dentry; +- sb = dentry->d_sb; +- inode = dentry->d_inode; +- AuDebugOn(au_special_file(inode->i_mode)); +- bstart = au_fbstart(file); +- err = au_test_ro(sb, bstart, inode); +- if (!err && (au_hf_top(file)->f_mode & FMODE_WRITE)) { +- err = au_pin(pin, dentry, bstart, AuOpt_UDBA_NONE, /*flags*/0); +- goto out; +- } +- +- /* need to cpup or reopen */ +- parent = dget_parent(dentry); +- di_write_lock_parent(parent); +- err = AuWbrCopyup(au_sbi(sb), dentry); +- bcpup = err; +- if (unlikely(err < 0)) +- goto out_dgrade; +- err = 0; +- +- if (!d_unhashed(dentry) && !au_h_dptr(parent, bcpup)) { +- err = au_cpup_dirs(dentry, bcpup); +- if (unlikely(err)) +- goto out_dgrade; +- } +- +- err = au_pin(pin, dentry, bcpup, AuOpt_UDBA_NONE, +- AuPin_DI_LOCKED | AuPin_MNT_WRITE); +- if (unlikely(err)) +- goto out_dgrade; +- +- h_dentry = au_hf_top(file)->f_dentry; +- h_inode = h_dentry->d_inode; +- dbstart = au_dbstart(dentry); +- if (dbstart <= bcpup) { +- h_dentry = au_h_dptr(dentry, bcpup); +- AuDebugOn(!h_dentry); +- h_inode = h_dentry->d_inode; +- AuDebugOn(!h_inode); +- bstart = bcpup; +- } +- +- if (dbstart <= bcpup /* just reopen */ +- || !d_unhashed(dentry) /* copyup and reopen */ +- ) { +- mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); +- h_file = au_h_open_pre(dentry, bstart); +- if (IS_ERR(h_file)) { +- err = PTR_ERR(h_file); +- h_file = NULL; +- } else { +- di_downgrade_lock(parent, AuLock_IR); +- if (dbstart > bcpup) +- err = au_sio_cpup_simple(dentry, bcpup, len, +- AuCpup_DTIME); +- if (!err) +- err = au_reopen_nondir(file); +- } +- mutex_unlock(&h_inode->i_mutex); +- au_h_open_post(dentry, bstart, h_file); +- } else { /* copyup as wh and reopen */ +- /* +- * since writable hfsplus branch is not supported, +- * h_open_pre/post() are unnecessary. +- */ +- mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); +- err = au_ready_to_write_wh(file, len, bcpup); +- di_downgrade_lock(parent, AuLock_IR); +- mutex_unlock(&h_inode->i_mutex); +- } +- +- if (!err) { +- au_pin_set_parent_lflag(pin, /*lflag*/0); +- goto out_dput; /* success */ +- } +- au_unpin(pin); +- goto out_unlock; +- +-out_dgrade: +- di_downgrade_lock(parent, AuLock_IR); +-out_unlock: +- di_read_unlock(parent, AuLock_IR); +-out_dput: +- dput(parent); +-out: +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-int au_do_flush(struct file *file, fl_owner_t id, +- int (*flush)(struct file *file, fl_owner_t id)) +-{ +- int err; +- struct dentry *dentry; +- struct super_block *sb; +- struct inode *inode; +- +- dentry = file->f_dentry; +- sb = dentry->d_sb; +- inode = dentry->d_inode; +- si_noflush_read_lock(sb); +- fi_read_lock(file); +- ii_read_lock_child(inode); +- +- err = flush(file, id); +- au_cpup_attr_timesizes(inode); +- +- ii_read_unlock(inode); +- fi_read_unlock(file); +- si_read_unlock(sb); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static int au_file_refresh_by_inode(struct file *file, int *need_reopen) +-{ +- int err; +- aufs_bindex_t bstart; +- struct au_pin pin; +- struct au_finfo *finfo; +- struct dentry *dentry, *parent, *hi_wh; +- struct inode *inode; +- struct super_block *sb; +- +- FiMustWriteLock(file); +- +- err = 0; +- finfo = au_fi(file); +- dentry = file->f_dentry; +- sb = dentry->d_sb; +- inode = dentry->d_inode; +- bstart = au_ibstart(inode); +- if (bstart == finfo->fi_btop || IS_ROOT(dentry)) +- goto out; +- +- parent = dget_parent(dentry); +- if (au_test_ro(sb, bstart, inode)) { +- di_read_lock_parent(parent, !AuLock_IR); +- err = AuWbrCopyup(au_sbi(sb), dentry); +- bstart = err; +- di_read_unlock(parent, !AuLock_IR); +- if (unlikely(err < 0)) +- goto out_parent; +- err = 0; +- } +- +- di_read_lock_parent(parent, AuLock_IR); +- hi_wh = au_hi_wh(inode, bstart); +- if (!S_ISDIR(inode->i_mode) +- && au_opt_test(au_mntflags(sb), PLINK) +- && au_plink_test(inode) +- && !d_unhashed(dentry)) { +- err = au_test_and_cpup_dirs(dentry, bstart); +- if (unlikely(err)) +- goto out_unlock; +- +- /* always superio. */ +- err = au_pin(&pin, dentry, bstart, AuOpt_UDBA_NONE, +- AuPin_DI_LOCKED | AuPin_MNT_WRITE); +- if (!err) +- err = au_sio_cpup_simple(dentry, bstart, -1, +- AuCpup_DTIME); +- au_unpin(&pin); +- } else if (hi_wh) { +- /* already copied-up after unlink */ +- err = au_reopen_wh(file, bstart, hi_wh); +- *need_reopen = 0; +- } +- +-out_unlock: +- di_read_unlock(parent, AuLock_IR); +-out_parent: +- dput(parent); +-out: +- return err; +-} +- +-static void au_do_refresh_dir(struct file *file) +-{ +- aufs_bindex_t bindex, bend, new_bindex, brid; +- struct au_hfile *p, tmp, *q; +- struct au_finfo *finfo; +- struct super_block *sb; +- struct au_fidir *fidir; +- +- FiMustWriteLock(file); +- +- sb = file->f_dentry->d_sb; +- finfo = au_fi(file); +- fidir = finfo->fi_hdir; +- AuDebugOn(!fidir); +- p = fidir->fd_hfile + finfo->fi_btop; +- brid = p->hf_br->br_id; +- bend = fidir->fd_bbot; +- for (bindex = finfo->fi_btop; bindex <= bend; bindex++, p++) { +- if (!p->hf_file) +- continue; +- +- new_bindex = au_br_index(sb, p->hf_br->br_id); +- if (new_bindex == bindex) +- continue; +- if (new_bindex < 0) { +- au_set_h_fptr(file, bindex, NULL); +- continue; +- } +- +- /* swap two lower inode, and loop again */ +- q = fidir->fd_hfile + new_bindex; +- tmp = *q; +- *q = *p; +- *p = tmp; +- if (tmp.hf_file) { +- bindex--; +- p--; +- } +- } +- +- p = fidir->fd_hfile; +- if (!au_test_mmapped(file) && !d_unlinked(file->f_dentry)) { +- bend = au_sbend(sb); +- for (finfo->fi_btop = 0; finfo->fi_btop <= bend; +- finfo->fi_btop++, p++) +- if (p->hf_file) { +- if (p->hf_file->f_dentry +- && p->hf_file->f_dentry->d_inode) +- break; +- else +- au_hfput(p, file); +- } +- } else { +- bend = au_br_index(sb, brid); +- for (finfo->fi_btop = 0; finfo->fi_btop < bend; +- finfo->fi_btop++, p++) +- if (p->hf_file) +- au_hfput(p, file); +- bend = au_sbend(sb); +- } +- +- p = fidir->fd_hfile + bend; +- for (fidir->fd_bbot = bend; fidir->fd_bbot >= finfo->fi_btop; +- fidir->fd_bbot--, p--) +- if (p->hf_file) { +- if (p->hf_file->f_dentry +- && p->hf_file->f_dentry->d_inode) +- break; +- else +- au_hfput(p, file); +- } +- AuDebugOn(fidir->fd_bbot < finfo->fi_btop); +-} +- +-/* +- * after branch manipulating, refresh the file. +- */ +-static int refresh_file(struct file *file, int (*reopen)(struct file *file)) +-{ +- int err, need_reopen; +- aufs_bindex_t bend, bindex; +- struct dentry *dentry; +- struct au_finfo *finfo; +- struct au_hfile *hfile; +- +- dentry = file->f_dentry; +- finfo = au_fi(file); +- if (!finfo->fi_hdir) { +- hfile = &finfo->fi_htop; +- AuDebugOn(!hfile->hf_file); +- bindex = au_br_index(dentry->d_sb, hfile->hf_br->br_id); +- AuDebugOn(bindex < 0); +- if (bindex != finfo->fi_btop) +- au_set_fbstart(file, bindex); +- } else { +- err = au_fidir_realloc(finfo, au_sbend(dentry->d_sb) + 1); +- if (unlikely(err)) +- goto out; +- au_do_refresh_dir(file); +- } +- +- err = 0; +- need_reopen = 1; +- if (!au_test_mmapped(file)) +- err = au_file_refresh_by_inode(file, &need_reopen); +- if (!err && need_reopen && !d_unlinked(dentry)) +- err = reopen(file); +- if (!err) { +- au_update_figen(file); +- goto out; /* success */ +- } +- +- /* error, close all lower files */ +- if (finfo->fi_hdir) { +- bend = au_fbend_dir(file); +- for (bindex = au_fbstart(file); bindex <= bend; bindex++) +- au_set_h_fptr(file, bindex, NULL); +- } +- +-out: +- return err; +-} +- +-/* common function to regular file and dir */ +-int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file), +- int wlock) +-{ +- int err; +- unsigned int sigen, figen; +- aufs_bindex_t bstart; +- unsigned char pseudo_link; +- struct dentry *dentry; +- struct inode *inode; +- +- err = 0; +- dentry = file->f_dentry; +- inode = dentry->d_inode; +- AuDebugOn(au_special_file(inode->i_mode)); +- sigen = au_sigen(dentry->d_sb); +- fi_write_lock(file); +- figen = au_figen(file); +- di_write_lock_child(dentry); +- bstart = au_dbstart(dentry); +- pseudo_link = (bstart != au_ibstart(inode)); +- if (sigen == figen && !pseudo_link && au_fbstart(file) == bstart) { +- if (!wlock) { +- di_downgrade_lock(dentry, AuLock_IR); +- fi_downgrade_lock(file); +- } +- goto out; /* success */ +- } +- +- AuDbg("sigen %d, figen %d\n", sigen, figen); +- if (au_digen_test(dentry, sigen)) { +- err = au_reval_dpath(dentry, sigen); +- AuDebugOn(!err && au_digen_test(dentry, sigen)); +- } +- +- if (!err) +- err = refresh_file(file, reopen); +- if (!err) { +- if (!wlock) { +- di_downgrade_lock(dentry, AuLock_IR); +- fi_downgrade_lock(file); +- } +- } else { +- di_write_unlock(dentry); +- fi_write_unlock(file); +- } +- +-out: +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* cf. aufs_nopage() */ +-/* for madvise(2) */ +-static int aufs_readpage(struct file *file __maybe_unused, struct page *page) +-{ +- unlock_page(page); +- return 0; +-} +- +-/* it will never be called, but necessary to support O_DIRECT */ +-static ssize_t aufs_direct_IO(int rw, struct kiocb *iocb, +- const struct iovec *iov, loff_t offset, +- unsigned long nr_segs) +-{ BUG(); return 0; } +- +-/* +- * it will never be called, but madvise and fadvise behaves differently +- * when get_xip_mem is defined +- */ +-static int aufs_get_xip_mem(struct address_space *mapping, pgoff_t pgoff, +- int create, void **kmem, unsigned long *pfn) +-{ BUG(); return 0; } +- +-/* they will never be called. */ +-#ifdef CONFIG_AUFS_DEBUG +-static int aufs_write_begin(struct file *file, struct address_space *mapping, +- loff_t pos, unsigned len, unsigned flags, +- struct page **pagep, void **fsdata) +-{ AuUnsupport(); return 0; } +-static int aufs_write_end(struct file *file, struct address_space *mapping, +- loff_t pos, unsigned len, unsigned copied, +- struct page *page, void *fsdata) +-{ AuUnsupport(); return 0; } +-static int aufs_writepage(struct page *page, struct writeback_control *wbc) +-{ AuUnsupport(); return 0; } +- +-static int aufs_set_page_dirty(struct page *page) +-{ AuUnsupport(); return 0; } +-static void aufs_invalidatepage(struct page *page, unsigned long offset) +-{ AuUnsupport(); } +-static int aufs_releasepage(struct page *page, gfp_t gfp) +-{ AuUnsupport(); return 0; } +-static int aufs_migratepage(struct address_space *mapping, struct page *newpage, +- struct page *page, enum migrate_mode mode) +-{ AuUnsupport(); return 0; } +-static int aufs_launder_page(struct page *page) +-{ AuUnsupport(); return 0; } +-static int aufs_is_partially_uptodate(struct page *page, +- read_descriptor_t *desc, +- unsigned long from) +-{ AuUnsupport(); return 0; } +-static int aufs_error_remove_page(struct address_space *mapping, +- struct page *page) +-{ AuUnsupport(); return 0; } +-static int aufs_swap_activate(struct swap_info_struct *sis, struct file *file, +- sector_t *span) +-{ AuUnsupport(); return 0; } +-static void aufs_swap_deactivate(struct file *file) +-{ AuUnsupport(); } +-#endif /* CONFIG_AUFS_DEBUG */ +- +-const struct address_space_operations aufs_aop = { +- .readpage = aufs_readpage, +- .direct_IO = aufs_direct_IO, +- .get_xip_mem = aufs_get_xip_mem, +-#ifdef CONFIG_AUFS_DEBUG +- .writepage = aufs_writepage, +- /* no writepages, because of writepage */ +- .set_page_dirty = aufs_set_page_dirty, +- /* no readpages, because of readpage */ +- .write_begin = aufs_write_begin, +- .write_end = aufs_write_end, +- /* no bmap, no block device */ +- .invalidatepage = aufs_invalidatepage, +- .releasepage = aufs_releasepage, +- .migratepage = aufs_migratepage, +- .launder_page = aufs_launder_page, +- .is_partially_uptodate = aufs_is_partially_uptodate, +- .error_remove_page = aufs_error_remove_page, +- .swap_activate = aufs_swap_activate, +- .swap_deactivate = aufs_swap_deactivate +-#endif /* CONFIG_AUFS_DEBUG */ +-}; +diff --git a/fs/aufs/file.h b/fs/aufs/file.h +deleted file mode 100644 +index afd27de..0000000 +--- a/fs/aufs/file.h ++++ /dev/null +@@ -1,298 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * file operations +- */ +- +-#ifndef __AUFS_FILE_H__ +-#define __AUFS_FILE_H__ +- +-#ifdef __KERNEL__ +- +-#include +-#include +-#include +-#include "rwsem.h" +- +-struct au_branch; +-struct au_hfile { +- struct file *hf_file; +- struct au_branch *hf_br; +-}; +- +-struct au_vdir; +-struct au_fidir { +- aufs_bindex_t fd_bbot; +- aufs_bindex_t fd_nent; +- struct au_vdir *fd_vdir_cache; +- struct au_hfile fd_hfile[]; +-}; +- +-static inline int au_fidir_sz(int nent) +-{ +- AuDebugOn(nent < 0); +- return sizeof(struct au_fidir) + sizeof(struct au_hfile) * nent; +-} +- +-struct au_finfo { +- atomic_t fi_generation; +- +- struct au_rwsem fi_rwsem; +- aufs_bindex_t fi_btop; +- +- /* do not union them */ +- struct { /* for non-dir */ +- struct au_hfile fi_htop; +- atomic_t fi_mmapped; +- }; +- struct au_fidir *fi_hdir; /* for dir only */ +-} ____cacheline_aligned_in_smp; +- +-/* ---------------------------------------------------------------------- */ +- +-/* file.c */ +-extern const struct address_space_operations aufs_aop; +-unsigned int au_file_roflags(unsigned int flags); +-struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, +- struct file *file); +-int au_do_open(struct file *file, int (*open)(struct file *file, int flags), +- struct au_fidir *fidir); +-int au_reopen_nondir(struct file *file); +-struct au_pin; +-int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin); +-int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file), +- int wlock); +-int au_do_flush(struct file *file, fl_owner_t id, +- int (*flush)(struct file *file, fl_owner_t id)); +- +-/* poll.c */ +-#ifdef CONFIG_AUFS_POLL +-unsigned int aufs_poll(struct file *file, poll_table *wait); +-#endif +- +-#ifdef CONFIG_AUFS_BR_HFSPLUS +-/* hfsplus.c */ +-struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex); +-void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex, +- struct file *h_file); +-#else +-static inline +-struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex) +-{ +- return NULL; +-} +- +-AuStubVoid(au_h_open_post, struct dentry *dentry, aufs_bindex_t bindex, +- struct file *h_file); +-#endif +- +-/* f_op.c */ +-extern const struct file_operations aufs_file_fop; +-int au_do_open_nondir(struct file *file, int flags); +-int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file); +- +-#ifdef CONFIG_AUFS_SP_IATTR +-/* f_op_sp.c */ +-int au_special_file(umode_t mode); +-void au_init_special_fop(struct inode *inode, umode_t mode, dev_t rdev); +-#else +-AuStubInt0(au_special_file, umode_t mode) +-static inline void au_init_special_fop(struct inode *inode, umode_t mode, +- dev_t rdev) +-{ +- init_special_inode(inode, mode, rdev); +-} +-#endif +- +-/* finfo.c */ +-void au_hfput(struct au_hfile *hf, struct file *file); +-void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, +- struct file *h_file); +- +-void au_update_figen(struct file *file); +-struct au_fidir *au_fidir_alloc(struct super_block *sb); +-int au_fidir_realloc(struct au_finfo *finfo, int nbr); +- +-void au_fi_init_once(void *_fi); +-void au_finfo_fin(struct file *file); +-int au_finfo_init(struct file *file, struct au_fidir *fidir); +- +-/* ioctl.c */ +-long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg); +-#ifdef CONFIG_COMPAT +-long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd, +- unsigned long arg); +-#endif +- +-/* ---------------------------------------------------------------------- */ +- +-static inline struct au_finfo *au_fi(struct file *file) +-{ +- return file->private_data; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* +- * fi_read_lock, fi_write_lock, +- * fi_read_unlock, fi_write_unlock, fi_downgrade_lock +- */ +-AuSimpleRwsemFuncs(fi, struct file *f, &au_fi(f)->fi_rwsem); +- +-#define FiMustNoWaiters(f) AuRwMustNoWaiters(&au_fi(f)->fi_rwsem) +-#define FiMustAnyLock(f) AuRwMustAnyLock(&au_fi(f)->fi_rwsem) +-#define FiMustWriteLock(f) AuRwMustWriteLock(&au_fi(f)->fi_rwsem) +- +-/* ---------------------------------------------------------------------- */ +- +-/* todo: hard/soft set? */ +-static inline aufs_bindex_t au_fbstart(struct file *file) +-{ +- FiMustAnyLock(file); +- return au_fi(file)->fi_btop; +-} +- +-static inline aufs_bindex_t au_fbend_dir(struct file *file) +-{ +- FiMustAnyLock(file); +- AuDebugOn(!au_fi(file)->fi_hdir); +- return au_fi(file)->fi_hdir->fd_bbot; +-} +- +-static inline struct au_vdir *au_fvdir_cache(struct file *file) +-{ +- FiMustAnyLock(file); +- AuDebugOn(!au_fi(file)->fi_hdir); +- return au_fi(file)->fi_hdir->fd_vdir_cache; +-} +- +-static inline void au_set_fbstart(struct file *file, aufs_bindex_t bindex) +-{ +- FiMustWriteLock(file); +- au_fi(file)->fi_btop = bindex; +-} +- +-static inline void au_set_fbend_dir(struct file *file, aufs_bindex_t bindex) +-{ +- FiMustWriteLock(file); +- AuDebugOn(!au_fi(file)->fi_hdir); +- au_fi(file)->fi_hdir->fd_bbot = bindex; +-} +- +-static inline void au_set_fvdir_cache(struct file *file, +- struct au_vdir *vdir_cache) +-{ +- FiMustWriteLock(file); +- AuDebugOn(!au_fi(file)->fi_hdir); +- au_fi(file)->fi_hdir->fd_vdir_cache = vdir_cache; +-} +- +-static inline struct file *au_hf_top(struct file *file) +-{ +- FiMustAnyLock(file); +- AuDebugOn(au_fi(file)->fi_hdir); +- return au_fi(file)->fi_htop.hf_file; +-} +- +-static inline struct file *au_hf_dir(struct file *file, aufs_bindex_t bindex) +-{ +- FiMustAnyLock(file); +- AuDebugOn(!au_fi(file)->fi_hdir); +- return au_fi(file)->fi_hdir->fd_hfile[0 + bindex].hf_file; +-} +- +-/* todo: memory barrier? */ +-static inline unsigned int au_figen(struct file *f) +-{ +- return atomic_read(&au_fi(f)->fi_generation); +-} +- +-static inline void au_set_mmapped(struct file *f) +-{ +- if (atomic_inc_return(&au_fi(f)->fi_mmapped)) +- return; +- pr_warn("fi_mmapped wrapped around\n"); +- while (!atomic_inc_return(&au_fi(f)->fi_mmapped)) +- ; +-} +- +-static inline void au_unset_mmapped(struct file *f) +-{ +- atomic_dec(&au_fi(f)->fi_mmapped); +-} +- +-static inline int au_test_mmapped(struct file *f) +-{ +- return atomic_read(&au_fi(f)->fi_mmapped); +-} +- +-/* customize vma->vm_file */ +- +-static inline void au_do_vm_file_reset(struct vm_area_struct *vma, +- struct file *file) +-{ +- struct file *f; +- +- f = vma->vm_file; +- get_file(file); +- vma->vm_file = file; +- fput(f); +-} +- +-#ifdef CONFIG_MMU +-#define AuDbgVmRegion(file, vma) do {} while (0) +- +-static inline void au_vm_file_reset(struct vm_area_struct *vma, +- struct file *file) +-{ +- au_do_vm_file_reset(vma, file); +-} +-#else +-#define AuDbgVmRegion(file, vma) \ +- AuDebugOn((vma)->vm_region && (vma)->vm_region->vm_file != (file)) +- +-static inline void au_vm_file_reset(struct vm_area_struct *vma, +- struct file *file) +-{ +- struct file *f; +- +- au_do_vm_file_reset(vma, file); +- f = vma->vm_region->vm_file; +- get_file(file); +- vma->vm_region->vm_file = file; +- fput(f); +-} +-#endif /* CONFIG_MMU */ +- +-/* handle vma->vm_prfile */ +-static inline void au_vm_prfile_set(struct vm_area_struct *vma, +- struct file *file) +-{ +-#ifdef CONFIG_AUFS_PROC_MAP +- get_file(file); +- vma->vm_prfile = file; +-#ifndef CONFIG_MMU +- get_file(file); +- vma->vm_region->vm_prfile = file; +-#endif +-#endif +-} +- +-#endif /* __KERNEL__ */ +-#endif /* __AUFS_FILE_H__ */ +diff --git a/fs/aufs/finfo.c b/fs/aufs/finfo.c +deleted file mode 100644 +index 2111355..0000000 +--- a/fs/aufs/finfo.c ++++ /dev/null +@@ -1,157 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * file private data +- */ +- +-#include "aufs.h" +- +-void au_hfput(struct au_hfile *hf, struct file *file) +-{ +- /* todo: direct access f_flags */ +- if (vfsub_file_flags(file) & __FMODE_EXEC) +- allow_write_access(hf->hf_file); +- fput(hf->hf_file); +- hf->hf_file = NULL; +- atomic_dec(&hf->hf_br->br_count); +- hf->hf_br = NULL; +-} +- +-void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, struct file *val) +-{ +- struct au_finfo *finfo = au_fi(file); +- struct au_hfile *hf; +- struct au_fidir *fidir; +- +- fidir = finfo->fi_hdir; +- if (!fidir) { +- AuDebugOn(finfo->fi_btop != bindex); +- hf = &finfo->fi_htop; +- } else +- hf = fidir->fd_hfile + bindex; +- +- if (hf && hf->hf_file) +- au_hfput(hf, file); +- if (val) { +- FiMustWriteLock(file); +- hf->hf_file = val; +- hf->hf_br = au_sbr(file->f_dentry->d_sb, bindex); +- } +-} +- +-void au_update_figen(struct file *file) +-{ +- atomic_set(&au_fi(file)->fi_generation, au_digen(file->f_dentry)); +- /* smp_mb(); */ /* atomic_set */ +-} +- +-/* ---------------------------------------------------------------------- */ +- +-struct au_fidir *au_fidir_alloc(struct super_block *sb) +-{ +- struct au_fidir *fidir; +- int nbr; +- +- nbr = au_sbend(sb) + 1; +- if (nbr < 2) +- nbr = 2; /* initial allocate for 2 branches */ +- fidir = kzalloc(au_fidir_sz(nbr), GFP_NOFS); +- if (fidir) { +- fidir->fd_bbot = -1; +- fidir->fd_nent = nbr; +- fidir->fd_vdir_cache = NULL; +- } +- +- return fidir; +-} +- +-int au_fidir_realloc(struct au_finfo *finfo, int nbr) +-{ +- int err; +- struct au_fidir *fidir, *p; +- +- AuRwMustWriteLock(&finfo->fi_rwsem); +- fidir = finfo->fi_hdir; +- AuDebugOn(!fidir); +- +- err = -ENOMEM; +- p = au_kzrealloc(fidir, au_fidir_sz(fidir->fd_nent), au_fidir_sz(nbr), +- GFP_NOFS); +- if (p) { +- p->fd_nent = nbr; +- finfo->fi_hdir = p; +- err = 0; +- } +- +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-void au_finfo_fin(struct file *file) +-{ +- struct au_finfo *finfo; +- +- au_nfiles_dec(file->f_dentry->d_sb); +- +- finfo = au_fi(file); +- AuDebugOn(finfo->fi_hdir); +- AuRwDestroy(&finfo->fi_rwsem); +- au_cache_free_finfo(finfo); +-} +- +-void au_fi_init_once(void *_finfo) +-{ +- struct au_finfo *finfo = _finfo; +- static struct lock_class_key aufs_fi; +- +- au_rw_init(&finfo->fi_rwsem); +- au_rw_class(&finfo->fi_rwsem, &aufs_fi); +-} +- +-int au_finfo_init(struct file *file, struct au_fidir *fidir) +-{ +- int err; +- struct au_finfo *finfo; +- struct dentry *dentry; +- +- err = -ENOMEM; +- dentry = file->f_dentry; +- finfo = au_cache_alloc_finfo(); +- if (unlikely(!finfo)) +- goto out; +- +- err = 0; +- au_nfiles_inc(dentry->d_sb); +- /* verbose coding for lock class name */ +- if (!fidir) +- au_rw_class(&finfo->fi_rwsem, au_lc_key + AuLcNonDir_FIINFO); +- else +- au_rw_class(&finfo->fi_rwsem, au_lc_key + AuLcDir_FIINFO); +- au_rw_write_lock(&finfo->fi_rwsem); +- finfo->fi_btop = -1; +- finfo->fi_hdir = fidir; +- atomic_set(&finfo->fi_generation, au_digen(dentry)); +- /* smp_mb(); */ /* atomic_set */ +- +- file->private_data = finfo; +- +-out: +- return err; +-} +diff --git a/fs/aufs/fstype.h b/fs/aufs/fstype.h +deleted file mode 100644 +index b1dd94f..0000000 +--- a/fs/aufs/fstype.h ++++ /dev/null +@@ -1,481 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * judging filesystem type +- */ +- +-#ifndef __AUFS_FSTYPE_H__ +-#define __AUFS_FSTYPE_H__ +- +-#ifdef __KERNEL__ +- +-#include +-#include +-#include +- +-static inline int au_test_aufs(struct super_block *sb) +-{ +- return sb->s_magic == AUFS_SUPER_MAGIC; +-} +- +-static inline const char *au_sbtype(struct super_block *sb) +-{ +- return sb->s_type->name; +-} +- +-static inline int au_test_iso9660(struct super_block *sb __maybe_unused) +-{ +-#if defined(CONFIG_ROMFS_FS) || defined(CONFIG_ROMFS_FS_MODULE) +- return sb->s_magic == ROMFS_MAGIC; +-#else +- return 0; +-#endif +-} +- +-static inline int au_test_romfs(struct super_block *sb __maybe_unused) +-{ +-#if defined(CONFIG_ISO9660_FS) || defined(CONFIG_ISO9660_FS_MODULE) +- return sb->s_magic == ISOFS_SUPER_MAGIC; +-#else +- return 0; +-#endif +-} +- +-static inline int au_test_cramfs(struct super_block *sb __maybe_unused) +-{ +-#if defined(CONFIG_CRAMFS) || defined(CONFIG_CRAMFS_MODULE) +- return sb->s_magic == CRAMFS_MAGIC; +-#endif +- return 0; +-} +- +-static inline int au_test_nfs(struct super_block *sb __maybe_unused) +-{ +-#if defined(CONFIG_NFS_FS) || defined(CONFIG_NFS_FS_MODULE) +- return sb->s_magic == NFS_SUPER_MAGIC; +-#else +- return 0; +-#endif +-} +- +-static inline int au_test_fuse(struct super_block *sb __maybe_unused) +-{ +-#if defined(CONFIG_FUSE_FS) || defined(CONFIG_FUSE_FS_MODULE) +- return sb->s_magic == FUSE_SUPER_MAGIC; +-#else +- return 0; +-#endif +-} +- +-static inline int au_test_xfs(struct super_block *sb __maybe_unused) +-{ +-#if defined(CONFIG_XFS_FS) || defined(CONFIG_XFS_FS_MODULE) +- return sb->s_magic == XFS_SB_MAGIC; +-#else +- return 0; +-#endif +-} +- +-static inline int au_test_tmpfs(struct super_block *sb __maybe_unused) +-{ +-#ifdef CONFIG_TMPFS +- return sb->s_magic == TMPFS_MAGIC; +-#else +- return 0; +-#endif +-} +- +-static inline int au_test_ecryptfs(struct super_block *sb __maybe_unused) +-{ +-#if defined(CONFIG_ECRYPT_FS) || defined(CONFIG_ECRYPT_FS_MODULE) +- return !strcmp(au_sbtype(sb), "ecryptfs"); +-#else +- return 0; +-#endif +-} +- +-static inline int au_test_smbfs(struct super_block *sb __maybe_unused) +-{ +-#if defined(CONFIG_SMB_FS) || defined(CONFIG_SMB_FS_MODULE) +- return sb->s_magic == SMB_SUPER_MAGIC; +-#else +- return 0; +-#endif +-} +- +-static inline int au_test_ocfs2(struct super_block *sb __maybe_unused) +-{ +-#if defined(CONFIG_OCFS2_FS) || defined(CONFIG_OCFS2_FS_MODULE) +- return sb->s_magic == OCFS2_SUPER_MAGIC; +-#else +- return 0; +-#endif +-} +- +-static inline int au_test_ocfs2_dlmfs(struct super_block *sb __maybe_unused) +-{ +-#if defined(CONFIG_OCFS2_FS_O2CB) || defined(CONFIG_OCFS2_FS_O2CB_MODULE) +- return sb->s_magic == DLMFS_MAGIC; +-#else +- return 0; +-#endif +-} +- +-static inline int au_test_coda(struct super_block *sb __maybe_unused) +-{ +-#if defined(CONFIG_CODA_FS) || defined(CONFIG_CODA_FS_MODULE) +- return sb->s_magic == CODA_SUPER_MAGIC; +-#else +- return 0; +-#endif +-} +- +-static inline int au_test_v9fs(struct super_block *sb __maybe_unused) +-{ +-#if defined(CONFIG_9P_FS) || defined(CONFIG_9P_FS_MODULE) +- return sb->s_magic == V9FS_MAGIC; +-#else +- return 0; +-#endif +-} +- +-static inline int au_test_ext4(struct super_block *sb __maybe_unused) +-{ +-#if defined(CONFIG_EXT4DEV_FS) || defined(CONFIG_EXT4DEV_FS_MODULE) +- return sb->s_magic == EXT4_SUPER_MAGIC; +-#else +- return 0; +-#endif +-} +- +-static inline int au_test_sysv(struct super_block *sb __maybe_unused) +-{ +-#if defined(CONFIG_SYSV_FS) || defined(CONFIG_SYSV_FS_MODULE) +- return !strcmp(au_sbtype(sb), "sysv"); +-#else +- return 0; +-#endif +-} +- +-static inline int au_test_ramfs(struct super_block *sb) +-{ +- return sb->s_magic == RAMFS_MAGIC; +-} +- +-static inline int au_test_ubifs(struct super_block *sb __maybe_unused) +-{ +-#if defined(CONFIG_UBIFS_FS) || defined(CONFIG_UBIFS_FS_MODULE) +- return sb->s_magic == UBIFS_SUPER_MAGIC; +-#else +- return 0; +-#endif +-} +- +-static inline int au_test_procfs(struct super_block *sb __maybe_unused) +-{ +-#ifdef CONFIG_PROC_FS +- return sb->s_magic == PROC_SUPER_MAGIC; +-#else +- return 0; +-#endif +-} +- +-static inline int au_test_sysfs(struct super_block *sb __maybe_unused) +-{ +-#ifdef CONFIG_SYSFS +- return sb->s_magic == SYSFS_MAGIC; +-#else +- return 0; +-#endif +-} +- +-static inline int au_test_configfs(struct super_block *sb __maybe_unused) +-{ +-#if defined(CONFIG_CONFIGFS_FS) || defined(CONFIG_CONFIGFS_FS_MODULE) +- return sb->s_magic == CONFIGFS_MAGIC; +-#else +- return 0; +-#endif +-} +- +-static inline int au_test_minix(struct super_block *sb __maybe_unused) +-{ +-#if defined(CONFIG_MINIX_FS) || defined(CONFIG_MINIX_FS_MODULE) +- return sb->s_magic == MINIX3_SUPER_MAGIC +- || sb->s_magic == MINIX2_SUPER_MAGIC +- || sb->s_magic == MINIX2_SUPER_MAGIC2 +- || sb->s_magic == MINIX_SUPER_MAGIC +- || sb->s_magic == MINIX_SUPER_MAGIC2; +-#else +- return 0; +-#endif +-} +- +-static inline int au_test_cifs(struct super_block *sb __maybe_unused) +-{ +-#if defined(CONFIG_CIFS_FS) || defined(CONFIGCIFS_FS_MODULE) +- return sb->s_magic == CIFS_MAGIC_NUMBER; +-#else +- return 0; +-#endif +-} +- +-static inline int au_test_fat(struct super_block *sb __maybe_unused) +-{ +-#if defined(CONFIG_FAT_FS) || defined(CONFIG_FAT_FS_MODULE) +- return sb->s_magic == MSDOS_SUPER_MAGIC; +-#else +- return 0; +-#endif +-} +- +-static inline int au_test_msdos(struct super_block *sb) +-{ +- return au_test_fat(sb); +-} +- +-static inline int au_test_vfat(struct super_block *sb) +-{ +- return au_test_fat(sb); +-} +- +-static inline int au_test_securityfs(struct super_block *sb __maybe_unused) +-{ +-#ifdef CONFIG_SECURITYFS +- return sb->s_magic == SECURITYFS_MAGIC; +-#else +- return 0; +-#endif +-} +- +-static inline int au_test_squashfs(struct super_block *sb __maybe_unused) +-{ +-#if defined(CONFIG_SQUASHFS) || defined(CONFIG_SQUASHFS_MODULE) +- return sb->s_magic == SQUASHFS_MAGIC; +-#else +- return 0; +-#endif +-} +- +-static inline int au_test_btrfs(struct super_block *sb __maybe_unused) +-{ +-#if defined(CONFIG_BTRFS_FS) || defined(CONFIG_BTRFS_FS_MODULE) +- return sb->s_magic == BTRFS_SUPER_MAGIC; +-#else +- return 0; +-#endif +-} +- +-static inline int au_test_xenfs(struct super_block *sb __maybe_unused) +-{ +-#if defined(CONFIG_XENFS) || defined(CONFIG_XENFS_MODULE) +- return sb->s_magic == XENFS_SUPER_MAGIC; +-#else +- return 0; +-#endif +-} +- +-static inline int au_test_debugfs(struct super_block *sb __maybe_unused) +-{ +-#ifdef CONFIG_DEBUG_FS +- return sb->s_magic == DEBUGFS_MAGIC; +-#else +- return 0; +-#endif +-} +- +-static inline int au_test_nilfs(struct super_block *sb __maybe_unused) +-{ +-#if defined(CONFIG_NILFS) || defined(CONFIG_NILFS_MODULE) +- return sb->s_magic == NILFS_SUPER_MAGIC; +-#else +- return 0; +-#endif +-} +- +-static inline int au_test_hfsplus(struct super_block *sb __maybe_unused) +-{ +-#if defined(CONFIG_HFSPLUS_FS) || defined(CONFIG_HFSPLUS_FS_MODULE) +- return sb->s_magic == HFSPLUS_SUPER_MAGIC; +-#else +- return 0; +-#endif +-} +- +-/* ---------------------------------------------------------------------- */ +-/* +- * they can't be an aufs branch. +- */ +-static inline int au_test_fs_unsuppoted(struct super_block *sb) +-{ +- return +-#ifndef CONFIG_AUFS_BR_RAMFS +- au_test_ramfs(sb) || +-#endif +- au_test_procfs(sb) +- || au_test_sysfs(sb) +- || au_test_configfs(sb) +- || au_test_debugfs(sb) +- || au_test_securityfs(sb) +- || au_test_xenfs(sb) +- || au_test_ecryptfs(sb) +- /* || !strcmp(au_sbtype(sb), "unionfs") */ +- || au_test_aufs(sb); /* will be supported in next version */ +-} +- +-static inline int au_test_fs_remote(struct super_block *sb) +-{ +- return !au_test_tmpfs(sb) +-#ifdef CONFIG_AUFS_BR_RAMFS +- && !au_test_ramfs(sb) +-#endif +- && !(sb->s_type->fs_flags & FS_REQUIRES_DEV); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* +- * Note: these functions (below) are created after reading ->getattr() in all +- * filesystems under linux/fs. it means we have to do so in every update... +- */ +- +-/* +- * some filesystems require getattr to refresh the inode attributes before +- * referencing. +- * in most cases, we can rely on the inode attribute in NFS (or every remote fs) +- * and leave the work for d_revalidate() +- */ +-static inline int au_test_fs_refresh_iattr(struct super_block *sb) +-{ +- return au_test_nfs(sb) +- || au_test_fuse(sb) +- /* || au_test_smbfs(sb) */ /* untested */ +- /* || au_test_ocfs2(sb) */ /* untested */ +- /* || au_test_btrfs(sb) */ /* untested */ +- /* || au_test_coda(sb) */ /* untested */ +- /* || au_test_v9fs(sb) */ /* untested */ +- ; +-} +- +-/* +- * filesystems which don't maintain i_size or i_blocks. +- */ +-static inline int au_test_fs_bad_iattr_size(struct super_block *sb) +-{ +- return au_test_xfs(sb) +- || au_test_btrfs(sb) +- || au_test_ubifs(sb) +- || au_test_hfsplus(sb) /* maintained, but incorrect */ +- /* || au_test_ext4(sb) */ /* untested */ +- /* || au_test_ocfs2(sb) */ /* untested */ +- /* || au_test_ocfs2_dlmfs(sb) */ /* untested */ +- /* || au_test_sysv(sb) */ /* untested */ +- /* || au_test_minix(sb) */ /* untested */ +- ; +-} +- +-/* +- * filesystems which don't store the correct value in some of their inode +- * attributes. +- */ +-static inline int au_test_fs_bad_iattr(struct super_block *sb) +-{ +- return au_test_fs_bad_iattr_size(sb) +- /* || au_test_cifs(sb) */ /* untested */ +- || au_test_fat(sb) +- || au_test_msdos(sb) +- || au_test_vfat(sb); +-} +- +-/* they don't check i_nlink in link(2) */ +-static inline int au_test_fs_no_limit_nlink(struct super_block *sb) +-{ +- return au_test_tmpfs(sb) +-#ifdef CONFIG_AUFS_BR_RAMFS +- || au_test_ramfs(sb) +-#endif +- || au_test_ubifs(sb) +- || au_test_btrfs(sb) +- || au_test_hfsplus(sb); +-} +- +-/* +- * filesystems which sets S_NOATIME and S_NOCMTIME. +- */ +-static inline int au_test_fs_notime(struct super_block *sb) +-{ +- return au_test_nfs(sb) +- || au_test_fuse(sb) +- || au_test_ubifs(sb) +- /* || au_test_cifs(sb) */ /* untested */ +- ; +-} +- +-/* +- * filesystems which requires replacing i_mapping. +- */ +-static inline int au_test_fs_bad_mapping(struct super_block *sb) +-{ +- return au_test_fuse(sb) +- || au_test_ubifs(sb); +-} +- +-/* temporary support for i#1 in cramfs */ +-static inline int au_test_fs_unique_ino(struct inode *inode) +-{ +- if (au_test_cramfs(inode->i_sb)) +- return inode->i_ino != 1; +- return 1; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* +- * the filesystem where the xino files placed must support i/o after unlink and +- * maintain i_size and i_blocks. +- */ +-static inline int au_test_fs_bad_xino(struct super_block *sb) +-{ +- return au_test_fs_remote(sb) +- || au_test_fs_bad_iattr_size(sb) +- /* don't want unnecessary work for xino */ +- || au_test_aufs(sb) +- || au_test_ecryptfs(sb) +- || au_test_nilfs(sb); +-} +- +-static inline int au_test_fs_trunc_xino(struct super_block *sb) +-{ +- return au_test_tmpfs(sb) +- || au_test_ramfs(sb); +-} +- +-/* +- * test if the @sb is real-readonly. +- */ +-static inline int au_test_fs_rr(struct super_block *sb) +-{ +- return au_test_squashfs(sb) +- || au_test_iso9660(sb) +- || au_test_cramfs(sb) +- || au_test_romfs(sb); +-} +- +-#endif /* __KERNEL__ */ +-#endif /* __AUFS_FSTYPE_H__ */ +diff --git a/fs/aufs/hfsnotify.c b/fs/aufs/hfsnotify.c +deleted file mode 100644 +index 22b34cd0e..0000000 +--- a/fs/aufs/hfsnotify.c ++++ /dev/null +@@ -1,296 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * fsnotify for the lower directories +- */ +- +-#include "aufs.h" +- +-/* FS_IN_IGNORED is unnecessary */ +-static const __u32 AuHfsnMask = (FS_MOVED_TO | FS_MOVED_FROM | FS_DELETE +- | FS_CREATE | FS_EVENT_ON_CHILD); +-static DECLARE_WAIT_QUEUE_HEAD(au_hfsn_wq); +-static __cacheline_aligned_in_smp atomic64_t au_hfsn_ifree = ATOMIC64_INIT(0); +- +-static void au_hfsn_free_mark(struct fsnotify_mark *mark) +-{ +- struct au_hnotify *hn = container_of(mark, struct au_hnotify, +- hn_mark); +- AuDbg("here\n"); +- au_cache_free_hnotify(hn); +- smp_mb__before_atomic_dec(); +- if (atomic64_dec_and_test(&au_hfsn_ifree)) +- wake_up(&au_hfsn_wq); +-} +- +-static int au_hfsn_alloc(struct au_hinode *hinode) +-{ +- int err; +- struct au_hnotify *hn; +- struct super_block *sb; +- struct au_branch *br; +- struct fsnotify_mark *mark; +- aufs_bindex_t bindex; +- +- hn = hinode->hi_notify; +- sb = hn->hn_aufs_inode->i_sb; +- bindex = au_br_index(sb, hinode->hi_id); +- br = au_sbr(sb, bindex); +- AuDebugOn(!br->br_hfsn); +- +- mark = &hn->hn_mark; +- fsnotify_init_mark(mark, au_hfsn_free_mark); +- mark->mask = AuHfsnMask; +- /* +- * by udba rename or rmdir, aufs assign a new inode to the known +- * h_inode, so specify 1 to allow dups. +- */ +- err = fsnotify_add_mark(mark, br->br_hfsn->hfsn_group, hinode->hi_inode, +- /*mnt*/NULL, /*allow_dups*/1); +- /* even if err */ +- fsnotify_put_mark(mark); +- +- return err; +-} +- +-static int au_hfsn_free(struct au_hinode *hinode, struct au_hnotify *hn) +-{ +- struct fsnotify_mark *mark; +- unsigned long long ull; +- struct fsnotify_group *group; +- +- ull = atomic64_inc_return(&au_hfsn_ifree); +- BUG_ON(!ull); +- +- mark = &hn->hn_mark; +- spin_lock(&mark->lock); +- group = mark->group; +- fsnotify_get_group(group); +- spin_unlock(&mark->lock); +- fsnotify_destroy_mark(mark, group); +- fsnotify_put_group(group); +- +- /* free hn by myself */ +- return 0; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static void au_hfsn_ctl(struct au_hinode *hinode, int do_set) +-{ +- struct fsnotify_mark *mark; +- +- mark = &hinode->hi_notify->hn_mark; +- spin_lock(&mark->lock); +- if (do_set) { +- AuDebugOn(mark->mask & AuHfsnMask); +- mark->mask |= AuHfsnMask; +- } else { +- AuDebugOn(!(mark->mask & AuHfsnMask)); +- mark->mask &= ~AuHfsnMask; +- } +- spin_unlock(&mark->lock); +- /* fsnotify_recalc_inode_mask(hinode->hi_inode); */ +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* #define AuDbgHnotify */ +-#ifdef AuDbgHnotify +-static char *au_hfsn_name(u32 mask) +-{ +-#ifdef CONFIG_AUFS_DEBUG +-#define test_ret(flag) \ +- do { \ +- if (mask & flag) \ +- return #flag; \ +- } while (0) +- test_ret(FS_ACCESS); +- test_ret(FS_MODIFY); +- test_ret(FS_ATTRIB); +- test_ret(FS_CLOSE_WRITE); +- test_ret(FS_CLOSE_NOWRITE); +- test_ret(FS_OPEN); +- test_ret(FS_MOVED_FROM); +- test_ret(FS_MOVED_TO); +- test_ret(FS_CREATE); +- test_ret(FS_DELETE); +- test_ret(FS_DELETE_SELF); +- test_ret(FS_MOVE_SELF); +- test_ret(FS_UNMOUNT); +- test_ret(FS_Q_OVERFLOW); +- test_ret(FS_IN_IGNORED); +- test_ret(FS_IN_ISDIR); +- test_ret(FS_IN_ONESHOT); +- test_ret(FS_EVENT_ON_CHILD); +- return ""; +-#undef test_ret +-#else +- return "??"; +-#endif +-} +-#endif +- +-/* ---------------------------------------------------------------------- */ +- +-static void au_hfsn_free_group(struct fsnotify_group *group) +-{ +- struct au_br_hfsnotify *hfsn = group->private; +- +- AuDbg("here\n"); +- kfree(hfsn); +-} +- +-static int au_hfsn_handle_event(struct fsnotify_group *group, +- struct fsnotify_mark *inode_mark, +- struct fsnotify_mark *vfsmount_mark, +- struct fsnotify_event *event) +-{ +- int err; +- struct au_hnotify *hnotify; +- struct inode *h_dir, *h_inode; +- __u32 mask; +- struct qstr h_child_qstr = QSTR_INIT(event->file_name, event->name_len); +- +- AuDebugOn(event->data_type != FSNOTIFY_EVENT_INODE); +- +- err = 0; +- /* if FS_UNMOUNT happens, there must be another bug */ +- mask = event->mask; +- AuDebugOn(mask & FS_UNMOUNT); +- if (mask & (FS_IN_IGNORED | FS_UNMOUNT)) +- goto out; +- +- h_dir = event->to_tell; +- h_inode = event->inode; +-#ifdef AuDbgHnotify +- au_debug(1); +- if (1 || h_child_qstr.len != sizeof(AUFS_XINO_FNAME) - 1 +- || strncmp(h_child_qstr.name, AUFS_XINO_FNAME, h_child_qstr.len)) { +- AuDbg("i%lu, mask 0x%x %s, hcname %.*s, hi%lu\n", +- h_dir->i_ino, mask, au_hfsn_name(mask), +- AuLNPair(&h_child_qstr), h_inode ? h_inode->i_ino : 0); +- /* WARN_ON(1); */ +- } +- au_debug(0); +-#endif +- +- AuDebugOn(!inode_mark); +- hnotify = container_of(inode_mark, struct au_hnotify, hn_mark); +- err = au_hnotify(h_dir, hnotify, mask, &h_child_qstr, h_inode); +- +-out: +- return err; +-} +- +-/* isn't it waste to ask every registered 'group'? */ +-/* copied from linux/fs/notify/inotify/inotify_fsnotiry.c */ +-/* it should be exported to modules */ +-static bool au_hfsn_should_send_event(struct fsnotify_group *group, +- struct inode *h_inode, +- struct fsnotify_mark *inode_mark, +- struct fsnotify_mark *vfsmount_mark, +- __u32 mask, void *data, int data_type) +-{ +- mask = (mask & ~FS_EVENT_ON_CHILD); +- return inode_mark->mask & mask; +-} +- +-static struct fsnotify_ops au_hfsn_ops = { +- .should_send_event = au_hfsn_should_send_event, +- .handle_event = au_hfsn_handle_event, +- .free_group_priv = au_hfsn_free_group +-}; +- +-/* ---------------------------------------------------------------------- */ +- +-static void au_hfsn_fin_br(struct au_branch *br) +-{ +- struct au_br_hfsnotify *hfsn; +- +- hfsn = br->br_hfsn; +- if (hfsn) +- fsnotify_put_group(hfsn->hfsn_group); +-} +- +-static int au_hfsn_init_br(struct au_branch *br, int perm) +-{ +- int err; +- struct fsnotify_group *group; +- struct au_br_hfsnotify *hfsn; +- +- err = 0; +- br->br_hfsn = NULL; +- if (!au_br_hnotifyable(perm)) +- goto out; +- +- err = -ENOMEM; +- hfsn = kmalloc(sizeof(*hfsn), GFP_NOFS); +- if (unlikely(!hfsn)) +- goto out; +- +- err = 0; +- group = fsnotify_alloc_group(&au_hfsn_ops); +- if (IS_ERR(group)) { +- err = PTR_ERR(group); +- pr_err("fsnotify_alloc_group() failed, %d\n", err); +- goto out_hfsn; +- } +- +- group->private = hfsn; +- hfsn->hfsn_group = group; +- br->br_hfsn = hfsn; +- goto out; /* success */ +- +-out_hfsn: +- kfree(hfsn); +-out: +- return err; +-} +- +-static int au_hfsn_reset_br(unsigned int udba, struct au_branch *br, int perm) +-{ +- int err; +- +- err = 0; +- if (!br->br_hfsn) +- err = au_hfsn_init_br(br, perm); +- +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static void au_hfsn_fin(void) +-{ +- AuDbg("au_hfsn_ifree %lld\n", (long long)atomic64_read(&au_hfsn_ifree)); +- wait_event(au_hfsn_wq, !atomic64_read(&au_hfsn_ifree)); +-} +- +-const struct au_hnotify_op au_hnotify_op = { +- .ctl = au_hfsn_ctl, +- .alloc = au_hfsn_alloc, +- .free = au_hfsn_free, +- +- .fin = au_hfsn_fin, +- +- .reset_br = au_hfsn_reset_br, +- .fin_br = au_hfsn_fin_br, +- .init_br = au_hfsn_init_br +-}; +diff --git a/fs/aufs/hfsplus.c b/fs/aufs/hfsplus.c +deleted file mode 100644 +index 3586c24..0000000 +--- a/fs/aufs/hfsplus.c ++++ /dev/null +@@ -1,57 +0,0 @@ +-/* +- * Copyright (C) 2010-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * special support for filesystems which aqucires an inode mutex +- * at final closing a file, eg, hfsplus. +- * +- * This trick is very simple and stupid, just to open the file before really +- * neceeary open to tell hfsplus that this is not the final closing. +- * The caller should call au_h_open_pre() after acquiring the inode mutex, +- * and au_h_open_post() after releasing it. +- */ +- +-#include "aufs.h" +- +-struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex) +-{ +- struct file *h_file; +- struct dentry *h_dentry; +- +- h_dentry = au_h_dptr(dentry, bindex); +- AuDebugOn(!h_dentry); +- AuDebugOn(!h_dentry->d_inode); +- IMustLock(h_dentry->d_inode); +- +- h_file = NULL; +- if (au_test_hfsplus(h_dentry->d_sb) +- && S_ISREG(h_dentry->d_inode->i_mode)) +- h_file = au_h_open(dentry, bindex, +- O_RDONLY | O_NOATIME | O_LARGEFILE, +- /*file*/NULL); +- return h_file; +-} +- +-void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex, +- struct file *h_file) +-{ +- if (h_file) { +- fput(h_file); +- au_sbr_put(dentry->d_sb, bindex); +- } +-} +diff --git a/fs/aufs/hnotify.c b/fs/aufs/hnotify.c +deleted file mode 100644 +index 699c7e8..0000000 +--- a/fs/aufs/hnotify.c ++++ /dev/null +@@ -1,713 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * abstraction to notify the direct changes on lower directories +- */ +- +-#include "aufs.h" +- +-int au_hn_alloc(struct au_hinode *hinode, struct inode *inode) +-{ +- int err; +- struct au_hnotify *hn; +- +- err = -ENOMEM; +- hn = au_cache_alloc_hnotify(); +- if (hn) { +- hn->hn_aufs_inode = inode; +- hinode->hi_notify = hn; +- err = au_hnotify_op.alloc(hinode); +- AuTraceErr(err); +- if (unlikely(err)) { +- hinode->hi_notify = NULL; +- au_cache_free_hnotify(hn); +- /* +- * The upper dir was removed by udba, but the same named +- * dir left. In this case, aufs assignes a new inode +- * number and set the monitor again. +- * For the lower dir, the old monitnor is still left. +- */ +- if (err == -EEXIST) +- err = 0; +- } +- } +- +- AuTraceErr(err); +- return err; +-} +- +-void au_hn_free(struct au_hinode *hinode) +-{ +- struct au_hnotify *hn; +- +- hn = hinode->hi_notify; +- if (hn) { +- hinode->hi_notify = NULL; +- if (au_hnotify_op.free(hinode, hn)) +- au_cache_free_hnotify(hn); +- } +-} +- +-/* ---------------------------------------------------------------------- */ +- +-void au_hn_ctl(struct au_hinode *hinode, int do_set) +-{ +- if (hinode->hi_notify) +- au_hnotify_op.ctl(hinode, do_set); +-} +- +-void au_hn_reset(struct inode *inode, unsigned int flags) +-{ +- aufs_bindex_t bindex, bend; +- struct inode *hi; +- struct dentry *iwhdentry; +- +- bend = au_ibend(inode); +- for (bindex = au_ibstart(inode); bindex <= bend; bindex++) { +- hi = au_h_iptr(inode, bindex); +- if (!hi) +- continue; +- +- /* mutex_lock_nested(&hi->i_mutex, AuLsc_I_CHILD); */ +- iwhdentry = au_hi_wh(inode, bindex); +- if (iwhdentry) +- dget(iwhdentry); +- au_igrab(hi); +- au_set_h_iptr(inode, bindex, NULL, 0); +- au_set_h_iptr(inode, bindex, au_igrab(hi), +- flags & ~AuHi_XINO); +- iput(hi); +- dput(iwhdentry); +- /* mutex_unlock(&hi->i_mutex); */ +- } +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static int hn_xino(struct inode *inode, struct inode *h_inode) +-{ +- int err; +- aufs_bindex_t bindex, bend, bfound, bstart; +- struct inode *h_i; +- +- err = 0; +- if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { +- pr_warn("branch root dir was changed\n"); +- goto out; +- } +- +- bfound = -1; +- bend = au_ibend(inode); +- bstart = au_ibstart(inode); +-#if 0 /* reserved for future use */ +- if (bindex == bend) { +- /* keep this ino in rename case */ +- goto out; +- } +-#endif +- for (bindex = bstart; bindex <= bend; bindex++) +- if (au_h_iptr(inode, bindex) == h_inode) { +- bfound = bindex; +- break; +- } +- if (bfound < 0) +- goto out; +- +- for (bindex = bstart; bindex <= bend; bindex++) { +- h_i = au_h_iptr(inode, bindex); +- if (!h_i) +- continue; +- +- err = au_xino_write(inode->i_sb, bindex, h_i->i_ino, /*ino*/0); +- /* ignore this error */ +- /* bad action? */ +- } +- +- /* children inode number will be broken */ +- +-out: +- AuTraceErr(err); +- return err; +-} +- +-static int hn_gen_tree(struct dentry *dentry) +-{ +- int err, i, j, ndentry; +- struct au_dcsub_pages dpages; +- struct au_dpage *dpage; +- struct dentry **dentries; +- +- err = au_dpages_init(&dpages, GFP_NOFS); +- if (unlikely(err)) +- goto out; +- err = au_dcsub_pages(&dpages, dentry, NULL, NULL); +- if (unlikely(err)) +- goto out_dpages; +- +- for (i = 0; i < dpages.ndpage; i++) { +- dpage = dpages.dpages + i; +- dentries = dpage->dentries; +- ndentry = dpage->ndentry; +- for (j = 0; j < ndentry; j++) { +- struct dentry *d; +- +- d = dentries[j]; +- if (IS_ROOT(d)) +- continue; +- +- au_digen_dec(d); +- if (d->d_inode) +- /* todo: reset children xino? +- cached children only? */ +- au_iigen_dec(d->d_inode); +- } +- } +- +-out_dpages: +- au_dpages_free(&dpages); +- +-#if 0 +- /* discard children */ +- dentry_unhash(dentry); +- dput(dentry); +-#endif +-out: +- return err; +-} +- +-/* +- * return 0 if processed. +- */ +-static int hn_gen_by_inode(char *name, unsigned int nlen, struct inode *inode, +- const unsigned int isdir) +-{ +- int err; +- struct dentry *d; +- struct qstr *dname; +- struct hlist_node *p; +- +- err = 1; +- if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { +- pr_warn("branch root dir was changed\n"); +- err = 0; +- goto out; +- } +- +- if (!isdir) { +- AuDebugOn(!name); +- au_iigen_dec(inode); +- spin_lock(&inode->i_lock); +- hlist_for_each_entry(d, p, &inode->i_dentry, d_alias) { +- spin_lock(&d->d_lock); +- dname = &d->d_name; +- if (dname->len != nlen +- && memcmp(dname->name, name, nlen)) { +- spin_unlock(&d->d_lock); +- continue; +- } +- err = 0; +- au_digen_dec(d); +- spin_unlock(&d->d_lock); +- break; +- } +- spin_unlock(&inode->i_lock); +- } else { +- au_fset_si(au_sbi(inode->i_sb), FAILED_REFRESH_DIR); +- d = d_find_alias(inode); +- if (!d) { +- au_iigen_dec(inode); +- goto out; +- } +- +- spin_lock(&d->d_lock); +- dname = &d->d_name; +- if (dname->len == nlen && !memcmp(dname->name, name, nlen)) { +- spin_unlock(&d->d_lock); +- err = hn_gen_tree(d); +- spin_lock(&d->d_lock); +- } +- spin_unlock(&d->d_lock); +- dput(d); +- } +- +-out: +- AuTraceErr(err); +- return err; +-} +- +-static int hn_gen_by_name(struct dentry *dentry, const unsigned int isdir) +-{ +- int err; +- struct inode *inode; +- +- inode = dentry->d_inode; +- if (IS_ROOT(dentry) +- /* || (inode && inode->i_ino == AUFS_ROOT_INO) */ +- ) { +- pr_warn("branch root dir was changed\n"); +- return 0; +- } +- +- err = 0; +- if (!isdir) { +- au_digen_dec(dentry); +- if (inode) +- au_iigen_dec(inode); +- } else { +- au_fset_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR); +- if (inode) +- err = hn_gen_tree(dentry); +- } +- +- AuTraceErr(err); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* hnotify job flags */ +-#define AuHnJob_XINO0 1 +-#define AuHnJob_GEN (1 << 1) +-#define AuHnJob_DIRENT (1 << 2) +-#define AuHnJob_ISDIR (1 << 3) +-#define AuHnJob_TRYXINO0 (1 << 4) +-#define AuHnJob_MNTPNT (1 << 5) +-#define au_ftest_hnjob(flags, name) ((flags) & AuHnJob_##name) +-#define au_fset_hnjob(flags, name) \ +- do { (flags) |= AuHnJob_##name; } while (0) +-#define au_fclr_hnjob(flags, name) \ +- do { (flags) &= ~AuHnJob_##name; } while (0) +- +-enum { +- AuHn_CHILD, +- AuHn_PARENT, +- AuHnLast +-}; +- +-struct au_hnotify_args { +- struct inode *h_dir, *dir, *h_child_inode; +- u32 mask; +- unsigned int flags[AuHnLast]; +- unsigned int h_child_nlen; +- char h_child_name[]; +-}; +- +-struct hn_job_args { +- unsigned int flags; +- struct inode *inode, *h_inode, *dir, *h_dir; +- struct dentry *dentry; +- char *h_name; +- int h_nlen; +-}; +- +-static int hn_job(struct hn_job_args *a) +-{ +- const unsigned int isdir = au_ftest_hnjob(a->flags, ISDIR); +- +- /* reset xino */ +- if (au_ftest_hnjob(a->flags, XINO0) && a->inode) +- hn_xino(a->inode, a->h_inode); /* ignore this error */ +- +- if (au_ftest_hnjob(a->flags, TRYXINO0) +- && a->inode +- && a->h_inode) { +- mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD); +- if (!a->h_inode->i_nlink) +- hn_xino(a->inode, a->h_inode); /* ignore this error */ +- mutex_unlock(&a->h_inode->i_mutex); +- } +- +- /* make the generation obsolete */ +- if (au_ftest_hnjob(a->flags, GEN)) { +- int err = -1; +- if (a->inode) +- err = hn_gen_by_inode(a->h_name, a->h_nlen, a->inode, +- isdir); +- if (err && a->dentry) +- hn_gen_by_name(a->dentry, isdir); +- /* ignore this error */ +- } +- +- /* make dir entries obsolete */ +- if (au_ftest_hnjob(a->flags, DIRENT) && a->inode) { +- struct au_vdir *vdir; +- +- vdir = au_ivdir(a->inode); +- if (vdir) +- vdir->vd_jiffy = 0; +- /* IMustLock(a->inode); */ +- /* a->inode->i_version++; */ +- } +- +- /* can do nothing but warn */ +- if (au_ftest_hnjob(a->flags, MNTPNT) +- && a->dentry +- && d_mountpoint(a->dentry)) +- pr_warn("mount-point %.*s is removed or renamed\n", +- AuDLNPair(a->dentry)); +- +- return 0; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static struct dentry *lookup_wlock_by_name(char *name, unsigned int nlen, +- struct inode *dir) +-{ +- struct dentry *dentry, *d, *parent; +- struct qstr *dname; +- +- parent = d_find_alias(dir); +- if (!parent) +- return NULL; +- +- dentry = NULL; +- spin_lock(&parent->d_lock); +- list_for_each_entry(d, &parent->d_subdirs, d_u.d_child) { +- /* AuDbg("%.*s\n", AuDLNPair(d)); */ +- spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED); +- dname = &d->d_name; +- if (dname->len != nlen || memcmp(dname->name, name, nlen)) +- goto cont_unlock; +- if (au_di(d)) +- au_digen_dec(d); +- else +- goto cont_unlock; +- if (d->d_count) { +- dentry = dget_dlock(d); +- spin_unlock(&d->d_lock); +- break; +- } +- +- cont_unlock: +- spin_unlock(&d->d_lock); +- } +- spin_unlock(&parent->d_lock); +- dput(parent); +- +- if (dentry) +- di_write_lock_child(dentry); +- +- return dentry; +-} +- +-static struct inode *lookup_wlock_by_ino(struct super_block *sb, +- aufs_bindex_t bindex, ino_t h_ino) +-{ +- struct inode *inode; +- ino_t ino; +- int err; +- +- inode = NULL; +- err = au_xino_read(sb, bindex, h_ino, &ino); +- if (!err && ino) +- inode = ilookup(sb, ino); +- if (!inode) +- goto out; +- +- if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { +- pr_warn("wrong root branch\n"); +- iput(inode); +- inode = NULL; +- goto out; +- } +- +- ii_write_lock_child(inode); +- +-out: +- return inode; +-} +- +-static void au_hn_bh(void *_args) +-{ +- struct au_hnotify_args *a = _args; +- struct super_block *sb; +- aufs_bindex_t bindex, bend, bfound; +- unsigned char xino, try_iput; +- int err; +- struct inode *inode; +- ino_t h_ino; +- struct hn_job_args args; +- struct dentry *dentry; +- struct au_sbinfo *sbinfo; +- +- AuDebugOn(!_args); +- AuDebugOn(!a->h_dir); +- AuDebugOn(!a->dir); +- AuDebugOn(!a->mask); +- AuDbg("mask 0x%x, i%lu, hi%lu, hci%lu\n", +- a->mask, a->dir->i_ino, a->h_dir->i_ino, +- a->h_child_inode ? a->h_child_inode->i_ino : 0); +- +- inode = NULL; +- dentry = NULL; +- /* +- * do not lock a->dir->i_mutex here +- * because of d_revalidate() may cause a deadlock. +- */ +- sb = a->dir->i_sb; +- AuDebugOn(!sb); +- sbinfo = au_sbi(sb); +- AuDebugOn(!sbinfo); +- si_write_lock(sb, AuLock_NOPLMW); +- +- ii_read_lock_parent(a->dir); +- bfound = -1; +- bend = au_ibend(a->dir); +- for (bindex = au_ibstart(a->dir); bindex <= bend; bindex++) +- if (au_h_iptr(a->dir, bindex) == a->h_dir) { +- bfound = bindex; +- break; +- } +- ii_read_unlock(a->dir); +- if (unlikely(bfound < 0)) +- goto out; +- +- xino = !!au_opt_test(au_mntflags(sb), XINO); +- h_ino = 0; +- if (a->h_child_inode) +- h_ino = a->h_child_inode->i_ino; +- +- if (a->h_child_nlen +- && (au_ftest_hnjob(a->flags[AuHn_CHILD], GEN) +- || au_ftest_hnjob(a->flags[AuHn_CHILD], MNTPNT))) +- dentry = lookup_wlock_by_name(a->h_child_name, a->h_child_nlen, +- a->dir); +- try_iput = 0; +- if (dentry) +- inode = dentry->d_inode; +- if (xino && !inode && h_ino +- && (au_ftest_hnjob(a->flags[AuHn_CHILD], XINO0) +- || au_ftest_hnjob(a->flags[AuHn_CHILD], TRYXINO0) +- || au_ftest_hnjob(a->flags[AuHn_CHILD], GEN))) { +- inode = lookup_wlock_by_ino(sb, bfound, h_ino); +- try_iput = 1; +- } +- +- args.flags = a->flags[AuHn_CHILD]; +- args.dentry = dentry; +- args.inode = inode; +- args.h_inode = a->h_child_inode; +- args.dir = a->dir; +- args.h_dir = a->h_dir; +- args.h_name = a->h_child_name; +- args.h_nlen = a->h_child_nlen; +- err = hn_job(&args); +- if (dentry) { +- if (au_di(dentry)) +- di_write_unlock(dentry); +- dput(dentry); +- } +- if (inode && try_iput) { +- ii_write_unlock(inode); +- iput(inode); +- } +- +- ii_write_lock_parent(a->dir); +- args.flags = a->flags[AuHn_PARENT]; +- args.dentry = NULL; +- args.inode = a->dir; +- args.h_inode = a->h_dir; +- args.dir = NULL; +- args.h_dir = NULL; +- args.h_name = NULL; +- args.h_nlen = 0; +- err = hn_job(&args); +- ii_write_unlock(a->dir); +- +-out: +- iput(a->h_child_inode); +- iput(a->h_dir); +- iput(a->dir); +- si_write_unlock(sb); +- au_nwt_done(&sbinfo->si_nowait); +- kfree(a); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask, +- struct qstr *h_child_qstr, struct inode *h_child_inode) +-{ +- int err, len; +- unsigned int flags[AuHnLast], f; +- unsigned char isdir, isroot, wh; +- struct inode *dir; +- struct au_hnotify_args *args; +- char *p, *h_child_name; +- +- err = 0; +- AuDebugOn(!hnotify || !hnotify->hn_aufs_inode); +- dir = igrab(hnotify->hn_aufs_inode); +- if (!dir) +- goto out; +- +- isroot = (dir->i_ino == AUFS_ROOT_INO); +- wh = 0; +- h_child_name = (void *)h_child_qstr->name; +- len = h_child_qstr->len; +- if (h_child_name) { +- if (len > AUFS_WH_PFX_LEN +- && !memcmp(h_child_name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { +- h_child_name += AUFS_WH_PFX_LEN; +- len -= AUFS_WH_PFX_LEN; +- wh = 1; +- } +- } +- +- isdir = 0; +- if (h_child_inode) +- isdir = !!S_ISDIR(h_child_inode->i_mode); +- flags[AuHn_PARENT] = AuHnJob_ISDIR; +- flags[AuHn_CHILD] = 0; +- if (isdir) +- flags[AuHn_CHILD] = AuHnJob_ISDIR; +- au_fset_hnjob(flags[AuHn_PARENT], DIRENT); +- au_fset_hnjob(flags[AuHn_CHILD], GEN); +- switch (mask & FS_EVENTS_POSS_ON_CHILD) { +- case FS_MOVED_FROM: +- case FS_MOVED_TO: +- au_fset_hnjob(flags[AuHn_CHILD], XINO0); +- au_fset_hnjob(flags[AuHn_CHILD], MNTPNT); +- /*FALLTHROUGH*/ +- case FS_CREATE: +- AuDebugOn(!h_child_name || !h_child_inode); +- break; +- +- case FS_DELETE: +- /* +- * aufs never be able to get this child inode. +- * revalidation should be in d_revalidate() +- * by checking i_nlink, i_generation or d_unhashed(). +- */ +- AuDebugOn(!h_child_name); +- au_fset_hnjob(flags[AuHn_CHILD], TRYXINO0); +- au_fset_hnjob(flags[AuHn_CHILD], MNTPNT); +- break; +- +- default: +- AuDebugOn(1); +- } +- +- if (wh) +- h_child_inode = NULL; +- +- err = -ENOMEM; +- /* iput() and kfree() will be called in au_hnotify() */ +- args = kmalloc(sizeof(*args) + len + 1, GFP_NOFS); +- if (unlikely(!args)) { +- AuErr1("no memory\n"); +- iput(dir); +- goto out; +- } +- args->flags[AuHn_PARENT] = flags[AuHn_PARENT]; +- args->flags[AuHn_CHILD] = flags[AuHn_CHILD]; +- args->mask = mask; +- args->dir = dir; +- args->h_dir = igrab(h_dir); +- if (h_child_inode) +- h_child_inode = igrab(h_child_inode); /* can be NULL */ +- args->h_child_inode = h_child_inode; +- args->h_child_nlen = len; +- if (len) { +- p = (void *)args; +- p += sizeof(*args); +- memcpy(p, h_child_name, len); +- p[len] = 0; +- } +- +- f = 0; +- if (!dir->i_nlink) +- f = AuWkq_NEST; +- err = au_wkq_nowait(au_hn_bh, args, dir->i_sb, f); +- if (unlikely(err)) { +- pr_err("wkq %d\n", err); +- iput(args->h_child_inode); +- iput(args->h_dir); +- iput(args->dir); +- kfree(args); +- } +- +-out: +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-int au_hnotify_reset_br(unsigned int udba, struct au_branch *br, int perm) +-{ +- int err; +- +- AuDebugOn(!(udba & AuOptMask_UDBA)); +- +- err = 0; +- if (au_hnotify_op.reset_br) +- err = au_hnotify_op.reset_br(udba, br, perm); +- +- return err; +-} +- +-int au_hnotify_init_br(struct au_branch *br, int perm) +-{ +- int err; +- +- err = 0; +- if (au_hnotify_op.init_br) +- err = au_hnotify_op.init_br(br, perm); +- +- return err; +-} +- +-void au_hnotify_fin_br(struct au_branch *br) +-{ +- if (au_hnotify_op.fin_br) +- au_hnotify_op.fin_br(br); +-} +- +-static void au_hn_destroy_cache(void) +-{ +- kmem_cache_destroy(au_cachep[AuCache_HNOTIFY]); +- au_cachep[AuCache_HNOTIFY] = NULL; +-} +- +-int __init au_hnotify_init(void) +-{ +- int err; +- +- err = -ENOMEM; +- au_cachep[AuCache_HNOTIFY] = AuCache(au_hnotify); +- if (au_cachep[AuCache_HNOTIFY]) { +- err = 0; +- if (au_hnotify_op.init) +- err = au_hnotify_op.init(); +- if (unlikely(err)) +- au_hn_destroy_cache(); +- } +- AuTraceErr(err); +- return err; +-} +- +-void au_hnotify_fin(void) +-{ +- if (au_hnotify_op.fin) +- au_hnotify_op.fin(); +- /* cf. au_cache_fin() */ +- if (au_cachep[AuCache_HNOTIFY]) +- au_hn_destroy_cache(); +-} +diff --git a/fs/aufs/i_op.c b/fs/aufs/i_op.c +deleted file mode 100644 +index abd68c5..0000000 +--- a/fs/aufs/i_op.c ++++ /dev/null +@@ -1,1030 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * inode operations (except add/del/rename) +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include "aufs.h" +- +-static int h_permission(struct inode *h_inode, int mask, +- struct vfsmount *h_mnt, int brperm) +-{ +- int err; +- const unsigned char write_mask = !!(mask & (MAY_WRITE | MAY_APPEND)); +- +- err = -EACCES; +- if ((write_mask && IS_IMMUTABLE(h_inode)) +- || ((mask & MAY_EXEC) +- && S_ISREG(h_inode->i_mode) +- && ((h_mnt->mnt_flags & MNT_NOEXEC) +- || !(h_inode->i_mode & S_IXUGO)))) +- goto out; +- +- /* +- * - skip the lower fs test in the case of write to ro branch. +- * - nfs dir permission write check is optimized, but a policy for +- * link/rename requires a real check. +- */ +- if ((write_mask && !au_br_writable(brperm)) +- || (au_test_nfs(h_inode->i_sb) && S_ISDIR(h_inode->i_mode) +- && write_mask && !(mask & MAY_READ)) +- || !h_inode->i_op->permission) { +- /* AuLabel(generic_permission); */ +- err = generic_permission(h_inode, mask); +- } else { +- /* AuLabel(h_inode->permission); */ +- err = h_inode->i_op->permission(h_inode, mask); +- AuTraceErr(err); +- } +- +- if (!err) +- err = devcgroup_inode_permission(h_inode, mask); +- if (!err) +- err = security_inode_permission(h_inode, mask); +- +-#if 0 +- if (!err) { +- /* todo: do we need to call ima_path_check()? */ +- struct path h_path = { +- .dentry = +- .mnt = h_mnt +- }; +- err = ima_path_check(&h_path, +- mask & (MAY_READ | MAY_WRITE | MAY_EXEC), +- IMA_COUNT_LEAVE); +- } +-#endif +- +-out: +- return err; +-} +- +-static int aufs_permission(struct inode *inode, int mask) +-{ +- int err; +- aufs_bindex_t bindex, bend; +- const unsigned char isdir = !!S_ISDIR(inode->i_mode), +- write_mask = !!(mask & (MAY_WRITE | MAY_APPEND)); +- struct inode *h_inode; +- struct super_block *sb; +- struct au_branch *br; +- +- /* todo: support rcu-walk? */ +- if (mask & MAY_NOT_BLOCK) +- return -ECHILD; +- +- sb = inode->i_sb; +- si_read_lock(sb, AuLock_FLUSH); +- ii_read_lock_child(inode); +-#if 0 +- err = au_iigen_test(inode, au_sigen(sb)); +- if (unlikely(err)) +- goto out; +-#endif +- +- if (!isdir || write_mask) { +- err = au_busy_or_stale(); +- h_inode = au_h_iptr(inode, au_ibstart(inode)); +- if (unlikely(!h_inode +- || (h_inode->i_mode & S_IFMT) +- != (inode->i_mode & S_IFMT))) +- goto out; +- +- err = 0; +- bindex = au_ibstart(inode); +- br = au_sbr(sb, bindex); +- err = h_permission(h_inode, mask, br->br_mnt, br->br_perm); +- if (write_mask +- && !err +- && !special_file(h_inode->i_mode)) { +- /* test whether the upper writable branch exists */ +- err = -EROFS; +- for (; bindex >= 0; bindex--) +- if (!au_br_rdonly(au_sbr(sb, bindex))) { +- err = 0; +- break; +- } +- } +- goto out; +- } +- +- /* non-write to dir */ +- err = 0; +- bend = au_ibend(inode); +- for (bindex = au_ibstart(inode); !err && bindex <= bend; bindex++) { +- h_inode = au_h_iptr(inode, bindex); +- if (h_inode) { +- err = au_busy_or_stale(); +- if (unlikely(!S_ISDIR(h_inode->i_mode))) +- break; +- +- br = au_sbr(sb, bindex); +- err = h_permission(h_inode, mask, br->br_mnt, +- br->br_perm); +- } +- } +- +-out: +- ii_read_unlock(inode); +- si_read_unlock(sb); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static struct dentry *aufs_lookup(struct inode *dir, struct dentry *dentry, +- unsigned int flags) +-{ +- struct dentry *ret, *parent; +- struct inode *inode; +- struct super_block *sb; +- int err, npositive; +- +- IMustLock(dir); +- +- /* todo: support rcu-walk? */ +- ret = ERR_PTR(-ECHILD); +- if (flags & LOOKUP_RCU) +- goto out; +- +- ret = ERR_PTR(-ENAMETOOLONG); +- if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) +- goto out; +- +- sb = dir->i_sb; +- err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); +- ret = ERR_PTR(err); +- if (unlikely(err)) +- goto out; +- +- err = au_di_init(dentry); +- ret = ERR_PTR(err); +- if (unlikely(err)) +- goto out_si; +- +- inode = NULL; +- npositive = 0; /* suppress a warning */ +- parent = dentry->d_parent; /* dir inode is locked */ +- di_read_lock_parent(parent, AuLock_IR); +- err = au_alive_dir(parent); +- if (!err) +- err = au_digen_test(parent, au_sigen(sb)); +- if (!err) { +- npositive = au_lkup_dentry(dentry, au_dbstart(parent), +- /*type*/0); +- err = npositive; +- } +- di_read_unlock(parent, AuLock_IR); +- ret = ERR_PTR(err); +- if (unlikely(err < 0)) +- goto out_unlock; +- +- if (npositive) { +- inode = au_new_inode(dentry, /*must_new*/0); +- ret = (void *)inode; +- } +- if (IS_ERR(inode)) { +- inode = NULL; +- goto out_unlock; +- } +- +- ret = d_splice_alias(inode, dentry); +-#if 0 +- if (unlikely(d_need_lookup(dentry))) { +- spin_lock(&dentry->d_lock); +- dentry->d_flags &= ~DCACHE_NEED_LOOKUP; +- spin_unlock(&dentry->d_lock); +- } else +-#endif +- if (unlikely(IS_ERR(ret) && inode)) { +- ii_write_unlock(inode); +- iput(inode); +- inode = NULL; +- } +- +-out_unlock: +- di_write_unlock(dentry); +- if (inode) { +- /* verbose coding for lock class name */ +- if (unlikely(S_ISLNK(inode->i_mode))) +- au_rw_class(&au_di(dentry)->di_rwsem, +- au_lc_key + AuLcSymlink_DIINFO); +- else if (unlikely(S_ISDIR(inode->i_mode))) +- au_rw_class(&au_di(dentry)->di_rwsem, +- au_lc_key + AuLcDir_DIINFO); +- else /* likely */ +- au_rw_class(&au_di(dentry)->di_rwsem, +- au_lc_key + AuLcNonDir_DIINFO); +- } +-out_si: +- si_read_unlock(sb); +-out: +- return ret; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static int au_wr_dir_cpup(struct dentry *dentry, struct dentry *parent, +- const unsigned char add_entry, aufs_bindex_t bcpup, +- aufs_bindex_t bstart) +-{ +- int err; +- struct dentry *h_parent; +- struct inode *h_dir; +- +- if (add_entry) +- IMustLock(parent->d_inode); +- else +- di_write_lock_parent(parent); +- +- err = 0; +- if (!au_h_dptr(parent, bcpup)) { +- if (bstart < bcpup) +- err = au_cpdown_dirs(dentry, bcpup); +- else +- err = au_cpup_dirs(dentry, bcpup); +- } +- if (!err && add_entry) { +- h_parent = au_h_dptr(parent, bcpup); +- h_dir = h_parent->d_inode; +- mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT); +- err = au_lkup_neg(dentry, bcpup); +- /* todo: no unlock here */ +- mutex_unlock(&h_dir->i_mutex); +- +- AuDbg("bcpup %d\n", bcpup); +- if (!err) { +- if (!dentry->d_inode) +- au_set_h_dptr(dentry, bstart, NULL); +- au_update_dbrange(dentry, /*do_put_zero*/0); +- } +- } +- +- if (!add_entry) +- di_write_unlock(parent); +- if (!err) +- err = bcpup; /* success */ +- +- AuTraceErr(err); +- return err; +-} +- +-/* +- * decide the branch and the parent dir where we will create a new entry. +- * returns new bindex or an error. +- * copyup the parent dir if needed. +- */ +-int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry, +- struct au_wr_dir_args *args) +-{ +- int err; +- aufs_bindex_t bcpup, bstart, src_bstart; +- const unsigned char add_entry = !!au_ftest_wrdir(args->flags, +- ADD_ENTRY); +- struct super_block *sb; +- struct dentry *parent; +- struct au_sbinfo *sbinfo; +- +- sb = dentry->d_sb; +- sbinfo = au_sbi(sb); +- parent = dget_parent(dentry); +- bstart = au_dbstart(dentry); +- bcpup = bstart; +- if (args->force_btgt < 0) { +- if (src_dentry) { +- src_bstart = au_dbstart(src_dentry); +- if (src_bstart < bstart) +- bcpup = src_bstart; +- } else if (add_entry) { +- err = AuWbrCreate(sbinfo, dentry, +- au_ftest_wrdir(args->flags, ISDIR)); +- bcpup = err; +- } +- +- if (bcpup < 0 || au_test_ro(sb, bcpup, dentry->d_inode)) { +- if (add_entry) +- err = AuWbrCopyup(sbinfo, dentry); +- else { +- if (!IS_ROOT(dentry)) { +- di_read_lock_parent(parent, !AuLock_IR); +- err = AuWbrCopyup(sbinfo, dentry); +- di_read_unlock(parent, !AuLock_IR); +- } else +- err = AuWbrCopyup(sbinfo, dentry); +- } +- bcpup = err; +- if (unlikely(err < 0)) +- goto out; +- } +- } else { +- bcpup = args->force_btgt; +- AuDebugOn(au_test_ro(sb, bcpup, dentry->d_inode)); +- } +- +- AuDbg("bstart %d, bcpup %d\n", bstart, bcpup); +- err = bcpup; +- if (bcpup == bstart) +- goto out; /* success */ +- +- /* copyup the new parent into the branch we process */ +- err = au_wr_dir_cpup(dentry, parent, add_entry, bcpup, bstart); +- if (err >= 0) { +- if (!dentry->d_inode) { +- au_set_h_dptr(dentry, bstart, NULL); +- au_set_dbstart(dentry, bcpup); +- au_set_dbend(dentry, bcpup); +- } +- AuDebugOn(add_entry && !au_h_dptr(dentry, bcpup)); +- } +- +-out: +- dput(parent); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-struct dentry *au_pinned_h_parent(struct au_pin *pin) +-{ +- if (pin && pin->parent) +- return au_h_dptr(pin->parent, pin->bindex); +- return NULL; +-} +- +-void au_unpin(struct au_pin *p) +-{ +- if (p->h_mnt && au_ftest_pin(p->flags, MNT_WRITE)) +- vfsub_mnt_drop_write(p->h_mnt); +- if (!p->hdir) +- return; +- +- au_hn_imtx_unlock(p->hdir); +- if (!au_ftest_pin(p->flags, DI_LOCKED)) +- di_read_unlock(p->parent, AuLock_IR); +- iput(p->hdir->hi_inode); +- dput(p->parent); +- p->parent = NULL; +- p->hdir = NULL; +- p->h_mnt = NULL; +-} +- +-int au_do_pin(struct au_pin *p) +-{ +- int err; +- struct super_block *sb; +- struct dentry *h_dentry, *h_parent; +- struct au_branch *br; +- struct inode *h_dir; +- +- err = 0; +- sb = p->dentry->d_sb; +- br = au_sbr(sb, p->bindex); +- if (IS_ROOT(p->dentry)) { +- if (au_ftest_pin(p->flags, MNT_WRITE)) { +- p->h_mnt = br->br_mnt; +- err = vfsub_mnt_want_write(p->h_mnt); +- if (unlikely(err)) { +- au_fclr_pin(p->flags, MNT_WRITE); +- goto out_err; +- } +- } +- goto out; +- } +- +- h_dentry = NULL; +- if (p->bindex <= au_dbend(p->dentry)) +- h_dentry = au_h_dptr(p->dentry, p->bindex); +- +- p->parent = dget_parent(p->dentry); +- if (!au_ftest_pin(p->flags, DI_LOCKED)) +- di_read_lock(p->parent, AuLock_IR, p->lsc_di); +- +- h_dir = NULL; +- h_parent = au_h_dptr(p->parent, p->bindex); +- p->hdir = au_hi(p->parent->d_inode, p->bindex); +- if (p->hdir) +- h_dir = p->hdir->hi_inode; +- +- /* +- * udba case, or +- * if DI_LOCKED is not set, then p->parent may be different +- * and h_parent can be NULL. +- */ +- if (unlikely(!p->hdir || !h_dir || !h_parent)) { +- err = -EBUSY; +- if (!au_ftest_pin(p->flags, DI_LOCKED)) +- di_read_unlock(p->parent, AuLock_IR); +- dput(p->parent); +- p->parent = NULL; +- goto out_err; +- } +- +- au_igrab(h_dir); +- au_hn_imtx_lock_nested(p->hdir, p->lsc_hi); +- +- if (unlikely(p->hdir->hi_inode != h_parent->d_inode)) { +- err = -EBUSY; +- goto out_unpin; +- } +- if (h_dentry) { +- err = au_h_verify(h_dentry, p->udba, h_dir, h_parent, br); +- if (unlikely(err)) { +- au_fclr_pin(p->flags, MNT_WRITE); +- goto out_unpin; +- } +- } +- +- if (au_ftest_pin(p->flags, MNT_WRITE)) { +- p->h_mnt = br->br_mnt; +- err = vfsub_mnt_want_write(p->h_mnt); +- if (unlikely(err)) { +- au_fclr_pin(p->flags, MNT_WRITE); +- goto out_unpin; +- } +- } +- goto out; /* success */ +- +-out_unpin: +- au_unpin(p); +-out_err: +- pr_err("err %d\n", err); +- err = au_busy_or_stale(); +-out: +- return err; +-} +- +-void au_pin_init(struct au_pin *p, struct dentry *dentry, +- aufs_bindex_t bindex, int lsc_di, int lsc_hi, +- unsigned int udba, unsigned char flags) +-{ +- p->dentry = dentry; +- p->udba = udba; +- p->lsc_di = lsc_di; +- p->lsc_hi = lsc_hi; +- p->flags = flags; +- p->bindex = bindex; +- +- p->parent = NULL; +- p->hdir = NULL; +- p->h_mnt = NULL; +-} +- +-int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex, +- unsigned int udba, unsigned char flags) +-{ +- au_pin_init(pin, dentry, bindex, AuLsc_DI_PARENT, AuLsc_I_PARENT2, +- udba, flags); +- return au_do_pin(pin); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* +- * ->setattr() and ->getattr() are called in various cases. +- * chmod, stat: dentry is revalidated. +- * fchmod, fstat: file and dentry are not revalidated, additionally they may be +- * unhashed. +- * for ->setattr(), ia->ia_file is passed from ftruncate only. +- */ +-/* todo: consolidate with do_refresh() and simple_reval_dpath() */ +-static int au_reval_for_attr(struct dentry *dentry, unsigned int sigen) +-{ +- int err; +- struct inode *inode; +- struct dentry *parent; +- +- err = 0; +- inode = dentry->d_inode; +- if (au_digen_test(dentry, sigen)) { +- parent = dget_parent(dentry); +- di_read_lock_parent(parent, AuLock_IR); +- err = au_refresh_dentry(dentry, parent); +- di_read_unlock(parent, AuLock_IR); +- dput(parent); +- } +- +- AuTraceErr(err); +- return err; +-} +- +-#define AuIcpup_DID_CPUP 1 +-#define au_ftest_icpup(flags, name) ((flags) & AuIcpup_##name) +-#define au_fset_icpup(flags, name) \ +- do { (flags) |= AuIcpup_##name; } while (0) +-#define au_fclr_icpup(flags, name) \ +- do { (flags) &= ~AuIcpup_##name; } while (0) +- +-struct au_icpup_args { +- unsigned char flags; +- unsigned char pin_flags; +- aufs_bindex_t btgt; +- unsigned int udba; +- struct au_pin pin; +- struct path h_path; +- struct inode *h_inode; +-}; +- +-static int au_pin_and_icpup(struct dentry *dentry, struct iattr *ia, +- struct au_icpup_args *a) +-{ +- int err; +- loff_t sz; +- aufs_bindex_t bstart, ibstart; +- struct dentry *hi_wh, *parent; +- struct inode *inode; +- struct file *h_file; +- struct au_wr_dir_args wr_dir_args = { +- .force_btgt = -1, +- .flags = 0 +- }; +- +- bstart = au_dbstart(dentry); +- inode = dentry->d_inode; +- if (S_ISDIR(inode->i_mode)) +- au_fset_wrdir(wr_dir_args.flags, ISDIR); +- /* plink or hi_wh() case */ +- ibstart = au_ibstart(inode); +- if (bstart != ibstart && !au_test_ro(inode->i_sb, ibstart, inode)) +- wr_dir_args.force_btgt = ibstart; +- err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args); +- if (unlikely(err < 0)) +- goto out; +- a->btgt = err; +- if (err != bstart) +- au_fset_icpup(a->flags, DID_CPUP); +- +- err = 0; +- a->pin_flags = AuPin_MNT_WRITE; +- parent = NULL; +- if (!IS_ROOT(dentry)) { +- au_fset_pin(a->pin_flags, DI_LOCKED); +- parent = dget_parent(dentry); +- di_write_lock_parent(parent); +- } +- +- err = au_pin(&a->pin, dentry, a->btgt, a->udba, a->pin_flags); +- if (unlikely(err)) +- goto out_parent; +- +- a->h_path.dentry = au_h_dptr(dentry, bstart); +- a->h_inode = a->h_path.dentry->d_inode; +- mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD); +- sz = -1; +- if ((ia->ia_valid & ATTR_SIZE) && ia->ia_size < i_size_read(a->h_inode)) +- sz = ia->ia_size; +- +- h_file = NULL; +- hi_wh = NULL; +- if (au_ftest_icpup(a->flags, DID_CPUP) && d_unlinked(dentry)) { +- hi_wh = au_hi_wh(inode, a->btgt); +- if (!hi_wh) { +- err = au_sio_cpup_wh(dentry, a->btgt, sz, /*file*/NULL); +- if (unlikely(err)) +- goto out_unlock; +- hi_wh = au_hi_wh(inode, a->btgt); +- /* todo: revalidate hi_wh? */ +- } +- } +- +- if (parent) { +- au_pin_set_parent_lflag(&a->pin, /*lflag*/0); +- di_downgrade_lock(parent, AuLock_IR); +- dput(parent); +- parent = NULL; +- } +- if (!au_ftest_icpup(a->flags, DID_CPUP)) +- goto out; /* success */ +- +- if (!d_unhashed(dentry)) { +- h_file = au_h_open_pre(dentry, bstart); +- if (IS_ERR(h_file)) { +- err = PTR_ERR(h_file); +- h_file = NULL; +- } else +- err = au_sio_cpup_simple(dentry, a->btgt, sz, +- AuCpup_DTIME); +- if (!err) +- a->h_path.dentry = au_h_dptr(dentry, a->btgt); +- } else if (!hi_wh) +- a->h_path.dentry = au_h_dptr(dentry, a->btgt); +- else +- a->h_path.dentry = hi_wh; /* do not dget here */ +- +-out_unlock: +- mutex_unlock(&a->h_inode->i_mutex); +- au_h_open_post(dentry, bstart, h_file); +- a->h_inode = a->h_path.dentry->d_inode; +- if (!err) { +- mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD); +- goto out; /* success */ +- } +- +- au_unpin(&a->pin); +-out_parent: +- if (parent) { +- di_write_unlock(parent); +- dput(parent); +- } +-out: +- return err; +-} +- +-static int aufs_setattr(struct dentry *dentry, struct iattr *ia) +-{ +- int err; +- struct inode *inode; +- struct super_block *sb; +- struct file *file; +- struct au_icpup_args *a; +- +- inode = dentry->d_inode; +- IMustLock(inode); +- +- err = -ENOMEM; +- a = kzalloc(sizeof(*a), GFP_NOFS); +- if (unlikely(!a)) +- goto out; +- +- if (ia->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) +- ia->ia_valid &= ~ATTR_MODE; +- +- file = NULL; +- sb = dentry->d_sb; +- err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); +- if (unlikely(err)) +- goto out_kfree; +- +- if (ia->ia_valid & ATTR_FILE) { +- /* currently ftruncate(2) only */ +- AuDebugOn(!S_ISREG(inode->i_mode)); +- file = ia->ia_file; +- err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); +- if (unlikely(err)) +- goto out_si; +- ia->ia_file = au_hf_top(file); +- a->udba = AuOpt_UDBA_NONE; +- } else { +- /* fchmod() doesn't pass ia_file */ +- a->udba = au_opt_udba(sb); +- di_write_lock_child(dentry); +- /* no d_unlinked(), to set UDBA_NONE for root */ +- if (d_unhashed(dentry)) +- a->udba = AuOpt_UDBA_NONE; +- if (a->udba != AuOpt_UDBA_NONE) { +- AuDebugOn(IS_ROOT(dentry)); +- err = au_reval_for_attr(dentry, au_sigen(sb)); +- if (unlikely(err)) +- goto out_dentry; +- } +- } +- +- err = au_pin_and_icpup(dentry, ia, a); +- if (unlikely(err < 0)) +- goto out_dentry; +- if (au_ftest_icpup(a->flags, DID_CPUP)) { +- ia->ia_file = NULL; +- ia->ia_valid &= ~ATTR_FILE; +- } +- +- a->h_path.mnt = au_sbr_mnt(sb, a->btgt); +- if ((ia->ia_valid & (ATTR_MODE | ATTR_CTIME)) +- == (ATTR_MODE | ATTR_CTIME)) { +- err = security_path_chmod(&a->h_path, ia->ia_mode); +- if (unlikely(err)) +- goto out_unlock; +- } else if ((ia->ia_valid & (ATTR_UID | ATTR_GID)) +- && (ia->ia_valid & ATTR_CTIME)) { +- err = security_path_chown(&a->h_path, vfsub_ia_uid(ia), +- vfsub_ia_gid(ia)); +- if (unlikely(err)) +- goto out_unlock; +- } +- +- if (ia->ia_valid & ATTR_SIZE) { +- struct file *f; +- +- if (ia->ia_size < i_size_read(inode)) +- /* unmap only */ +- truncate_setsize(inode, ia->ia_size); +- +- f = NULL; +- if (ia->ia_valid & ATTR_FILE) +- f = ia->ia_file; +- mutex_unlock(&a->h_inode->i_mutex); +- err = vfsub_trunc(&a->h_path, ia->ia_size, ia->ia_valid, f); +- mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD); +- } else +- err = vfsub_notify_change(&a->h_path, ia); +- if (!err) +- au_cpup_attr_changeable(inode); +- +-out_unlock: +- mutex_unlock(&a->h_inode->i_mutex); +- au_unpin(&a->pin); +- if (unlikely(err)) +- au_update_dbstart(dentry); +-out_dentry: +- di_write_unlock(dentry); +- if (file) { +- fi_write_unlock(file); +- ia->ia_file = file; +- ia->ia_valid |= ATTR_FILE; +- } +-out_si: +- si_read_unlock(sb); +-out_kfree: +- kfree(a); +-out: +- AuTraceErr(err); +- return err; +-} +- +-static void au_refresh_iattr(struct inode *inode, struct kstat *st, +- unsigned int nlink) +-{ +- unsigned int n; +- +- inode->i_mode = st->mode; +- i_uid_write(inode, st->uid); +- i_gid_write(inode, st->gid); +- inode->i_atime = st->atime; +- inode->i_mtime = st->mtime; +- inode->i_ctime = st->ctime; +- +- au_cpup_attr_nlink(inode, /*force*/0); +- if (S_ISDIR(inode->i_mode)) { +- n = inode->i_nlink; +- n -= nlink; +- n += st->nlink; +- /* 0 can happen */ +- set_nlink(inode, n); +- } +- +- spin_lock(&inode->i_lock); +- inode->i_blocks = st->blocks; +- i_size_write(inode, st->size); +- spin_unlock(&inode->i_lock); +-} +- +-static int aufs_getattr(struct vfsmount *mnt __maybe_unused, +- struct dentry *dentry, struct kstat *st) +-{ +- int err; +- unsigned int mnt_flags; +- aufs_bindex_t bindex; +- unsigned char udba_none, positive; +- struct super_block *sb, *h_sb; +- struct inode *inode; +- struct vfsmount *h_mnt; +- struct dentry *h_dentry; +- +- sb = dentry->d_sb; +- inode = dentry->d_inode; +- err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); +- if (unlikely(err)) +- goto out; +- mnt_flags = au_mntflags(sb); +- udba_none = !!au_opt_test(mnt_flags, UDBA_NONE); +- +- /* support fstat(2) */ +- if (!d_unlinked(dentry) && !udba_none) { +- unsigned int sigen = au_sigen(sb); +- err = au_digen_test(dentry, sigen); +- if (!err) { +- di_read_lock_child(dentry, AuLock_IR); +- err = au_dbrange_test(dentry); +- if (unlikely(err)) +- goto out_unlock; +- } else { +- AuDebugOn(IS_ROOT(dentry)); +- di_write_lock_child(dentry); +- err = au_dbrange_test(dentry); +- if (!err) +- err = au_reval_for_attr(dentry, sigen); +- di_downgrade_lock(dentry, AuLock_IR); +- if (unlikely(err)) +- goto out_unlock; +- } +- } else +- di_read_lock_child(dentry, AuLock_IR); +- +- bindex = au_ibstart(inode); +- h_mnt = au_sbr_mnt(sb, bindex); +- h_sb = h_mnt->mnt_sb; +- if (!au_test_fs_bad_iattr(h_sb) && udba_none) +- goto out_fill; /* success */ +- +- h_dentry = NULL; +- if (au_dbstart(dentry) == bindex) +- h_dentry = dget(au_h_dptr(dentry, bindex)); +- else if (au_opt_test(mnt_flags, PLINK) && au_plink_test(inode)) { +- h_dentry = au_plink_lkup(inode, bindex); +- if (IS_ERR(h_dentry)) +- goto out_fill; /* pretending success */ +- } +- /* illegally overlapped or something */ +- if (unlikely(!h_dentry)) +- goto out_fill; /* pretending success */ +- +- positive = !!h_dentry->d_inode; +- if (positive) +- err = vfs_getattr(h_mnt, h_dentry, st); +- dput(h_dentry); +- if (!err) { +- if (positive) +- au_refresh_iattr(inode, st, h_dentry->d_inode->i_nlink); +- goto out_fill; /* success */ +- } +- AuTraceErr(err); +- goto out_unlock; +- +-out_fill: +- generic_fillattr(inode, st); +-out_unlock: +- di_read_unlock(dentry, AuLock_IR); +- si_read_unlock(sb); +-out: +- AuTraceErr(err); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static int h_readlink(struct dentry *dentry, int bindex, char __user *buf, +- int bufsiz) +-{ +- int err; +- struct super_block *sb; +- struct dentry *h_dentry; +- +- err = -EINVAL; +- h_dentry = au_h_dptr(dentry, bindex); +- if (unlikely(!h_dentry->d_inode->i_op->readlink)) +- goto out; +- +- err = security_inode_readlink(h_dentry); +- if (unlikely(err)) +- goto out; +- +- sb = dentry->d_sb; +- if (!au_test_ro(sb, bindex, dentry->d_inode)) { +- vfsub_touch_atime(au_sbr_mnt(sb, bindex), h_dentry); +- fsstack_copy_attr_atime(dentry->d_inode, h_dentry->d_inode); +- } +- err = h_dentry->d_inode->i_op->readlink(h_dentry, buf, bufsiz); +- +-out: +- return err; +-} +- +-static int aufs_readlink(struct dentry *dentry, char __user *buf, int bufsiz) +-{ +- int err; +- +- err = aufs_read_lock(dentry, AuLock_IR | AuLock_GEN); +- if (unlikely(err)) +- goto out; +- err = au_d_hashed_positive(dentry); +- if (!err) +- err = h_readlink(dentry, au_dbstart(dentry), buf, bufsiz); +- aufs_read_unlock(dentry, AuLock_IR); +- +-out: +- return err; +-} +- +-static void *aufs_follow_link(struct dentry *dentry, struct nameidata *nd) +-{ +- int err; +- mm_segment_t old_fs; +- union { +- char *k; +- char __user *u; +- } buf; +- +- err = -ENOMEM; +- buf.k = (void *)__get_free_page(GFP_NOFS); +- if (unlikely(!buf.k)) +- goto out; +- +- err = aufs_read_lock(dentry, AuLock_IR | AuLock_GEN); +- if (unlikely(err)) +- goto out_name; +- +- err = au_d_hashed_positive(dentry); +- if (!err) { +- old_fs = get_fs(); +- set_fs(KERNEL_DS); +- err = h_readlink(dentry, au_dbstart(dentry), buf.u, PATH_MAX); +- set_fs(old_fs); +- } +- aufs_read_unlock(dentry, AuLock_IR); +- +- if (err >= 0) { +- buf.k[err] = 0; +- /* will be freed by put_link */ +- nd_set_link(nd, buf.k); +- return NULL; /* success */ +- } +- +-out_name: +- free_page((unsigned long)buf.k); +-out: +- AuTraceErr(err); +- return ERR_PTR(err); +-} +- +-static void aufs_put_link(struct dentry *dentry __maybe_unused, +- struct nameidata *nd, void *cookie __maybe_unused) +-{ +- char *p; +- +- p = nd_get_link(nd); +- if (!IS_ERR_OR_NULL(p)) +- free_page((unsigned long)p); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static int aufs_update_time(struct inode *inode, struct timespec *ts, int flags) +-{ +- int err; +- struct super_block *sb; +- struct inode *h_inode; +- +- sb = inode->i_sb; +- /* mmap_sem might be acquired already, cf. aufs_mmap() */ +- lockdep_off(); +- si_read_lock(sb, AuLock_FLUSH); +- ii_write_lock_child(inode); +- lockdep_on(); +- h_inode = au_h_iptr(inode, au_ibstart(inode)); +- err = vfsub_update_time(h_inode, ts, flags); +- lockdep_off(); +- ii_write_unlock(inode); +- si_read_unlock(sb); +- lockdep_on(); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-struct inode_operations aufs_symlink_iop = { +- .permission = aufs_permission, +- .setattr = aufs_setattr, +- .getattr = aufs_getattr, +- +- .readlink = aufs_readlink, +- .follow_link = aufs_follow_link, +- .put_link = aufs_put_link, +- +- /* .update_time = aufs_update_time */ +-}; +- +-struct inode_operations aufs_dir_iop = { +- .create = aufs_create, +- .lookup = aufs_lookup, +- .link = aufs_link, +- .unlink = aufs_unlink, +- .symlink = aufs_symlink, +- .mkdir = aufs_mkdir, +- .rmdir = aufs_rmdir, +- .mknod = aufs_mknod, +- .rename = aufs_rename, +- +- .permission = aufs_permission, +- .setattr = aufs_setattr, +- .getattr = aufs_getattr, +- +- .update_time = aufs_update_time +- /* no support for atomic_open() */ +-}; +- +-struct inode_operations aufs_iop = { +- .permission = aufs_permission, +- .setattr = aufs_setattr, +- .getattr = aufs_getattr, +- +- .update_time = aufs_update_time +-}; +diff --git a/fs/aufs/i_op_add.c b/fs/aufs/i_op_add.c +deleted file mode 100644 +index 8677dd5..0000000 +--- a/fs/aufs/i_op_add.c ++++ /dev/null +@@ -1,713 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * inode operations (add entry) +- */ +- +-#include "aufs.h" +- +-/* +- * final procedure of adding a new entry, except link(2). +- * remove whiteout, instantiate, copyup the parent dir's times and size +- * and update version. +- * if it failed, re-create the removed whiteout. +- */ +-static int epilog(struct inode *dir, aufs_bindex_t bindex, +- struct dentry *wh_dentry, struct dentry *dentry) +-{ +- int err, rerr; +- aufs_bindex_t bwh; +- struct path h_path; +- struct inode *inode, *h_dir; +- struct dentry *wh; +- +- bwh = -1; +- if (wh_dentry) { +- h_dir = wh_dentry->d_parent->d_inode; /* dir inode is locked */ +- IMustLock(h_dir); +- AuDebugOn(au_h_iptr(dir, bindex) != h_dir); +- bwh = au_dbwh(dentry); +- h_path.dentry = wh_dentry; +- h_path.mnt = au_sbr_mnt(dir->i_sb, bindex); +- err = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path, +- dentry); +- if (unlikely(err)) +- goto out; +- } +- +- inode = au_new_inode(dentry, /*must_new*/1); +- if (!IS_ERR(inode)) { +- d_instantiate(dentry, inode); +- dir = dentry->d_parent->d_inode; /* dir inode is locked */ +- IMustLock(dir); +- if (au_ibstart(dir) == au_dbstart(dentry)) +- au_cpup_attr_timesizes(dir); +- dir->i_version++; +- return 0; /* success */ +- } +- +- err = PTR_ERR(inode); +- if (!wh_dentry) +- goto out; +- +- /* revert */ +- /* dir inode is locked */ +- wh = au_wh_create(dentry, bwh, wh_dentry->d_parent); +- rerr = PTR_ERR(wh); +- if (IS_ERR(wh)) { +- AuIOErr("%.*s reverting whiteout failed(%d, %d)\n", +- AuDLNPair(dentry), err, rerr); +- err = -EIO; +- } else +- dput(wh); +- +-out: +- return err; +-} +- +-static int au_d_may_add(struct dentry *dentry) +-{ +- int err; +- +- err = 0; +- if (unlikely(d_unhashed(dentry))) +- err = -ENOENT; +- if (unlikely(dentry->d_inode)) +- err = -EEXIST; +- return err; +-} +- +-/* +- * simple tests for the adding inode operations. +- * following the checks in vfs, plus the parent-child relationship. +- */ +-int au_may_add(struct dentry *dentry, aufs_bindex_t bindex, +- struct dentry *h_parent, int isdir) +-{ +- int err; +- umode_t h_mode; +- struct dentry *h_dentry; +- struct inode *h_inode; +- +- err = -ENAMETOOLONG; +- if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) +- goto out; +- +- h_dentry = au_h_dptr(dentry, bindex); +- h_inode = h_dentry->d_inode; +- if (!dentry->d_inode) { +- err = -EEXIST; +- if (unlikely(h_inode)) +- goto out; +- } else { +- /* rename(2) case */ +- err = -EIO; +- if (unlikely(!h_inode || !h_inode->i_nlink)) +- goto out; +- +- h_mode = h_inode->i_mode; +- if (!isdir) { +- err = -EISDIR; +- if (unlikely(S_ISDIR(h_mode))) +- goto out; +- } else if (unlikely(!S_ISDIR(h_mode))) { +- err = -ENOTDIR; +- goto out; +- } +- } +- +- err = 0; +- /* expected parent dir is locked */ +- if (unlikely(h_parent != h_dentry->d_parent)) +- err = -EIO; +- +-out: +- AuTraceErr(err); +- return err; +-} +- +-/* +- * initial procedure of adding a new entry. +- * prepare writable branch and the parent dir, lock it, +- * and lookup whiteout for the new entry. +- */ +-static struct dentry* +-lock_hdir_lkup_wh(struct dentry *dentry, struct au_dtime *dt, +- struct dentry *src_dentry, struct au_pin *pin, +- struct au_wr_dir_args *wr_dir_args) +-{ +- struct dentry *wh_dentry, *h_parent; +- struct super_block *sb; +- struct au_branch *br; +- int err; +- unsigned int udba; +- aufs_bindex_t bcpup; +- +- AuDbg("%.*s\n", AuDLNPair(dentry)); +- +- err = au_wr_dir(dentry, src_dentry, wr_dir_args); +- bcpup = err; +- wh_dentry = ERR_PTR(err); +- if (unlikely(err < 0)) +- goto out; +- +- sb = dentry->d_sb; +- udba = au_opt_udba(sb); +- err = au_pin(pin, dentry, bcpup, udba, +- AuPin_DI_LOCKED | AuPin_MNT_WRITE); +- wh_dentry = ERR_PTR(err); +- if (unlikely(err)) +- goto out; +- +- h_parent = au_pinned_h_parent(pin); +- if (udba != AuOpt_UDBA_NONE +- && au_dbstart(dentry) == bcpup) +- err = au_may_add(dentry, bcpup, h_parent, +- au_ftest_wrdir(wr_dir_args->flags, ISDIR)); +- else if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) +- err = -ENAMETOOLONG; +- wh_dentry = ERR_PTR(err); +- if (unlikely(err)) +- goto out_unpin; +- +- br = au_sbr(sb, bcpup); +- if (dt) { +- struct path tmp = { +- .dentry = h_parent, +- .mnt = br->br_mnt +- }; +- au_dtime_store(dt, au_pinned_parent(pin), &tmp); +- } +- +- wh_dentry = NULL; +- if (bcpup != au_dbwh(dentry)) +- goto out; /* success */ +- +- wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, br); +- +-out_unpin: +- if (IS_ERR(wh_dentry)) +- au_unpin(pin); +-out: +- return wh_dentry; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-enum { Mknod, Symlink, Creat }; +-struct simple_arg { +- int type; +- union { +- struct { +- umode_t mode; +- bool want_excl; +- } c; +- struct { +- const char *symname; +- } s; +- struct { +- umode_t mode; +- dev_t dev; +- } m; +- } u; +-}; +- +-static int add_simple(struct inode *dir, struct dentry *dentry, +- struct simple_arg *arg) +-{ +- int err; +- aufs_bindex_t bstart; +- unsigned char created; +- struct au_dtime dt; +- struct au_pin pin; +- struct path h_path; +- struct dentry *wh_dentry, *parent; +- struct inode *h_dir; +- struct au_wr_dir_args wr_dir_args = { +- .force_btgt = -1, +- .flags = AuWrDir_ADD_ENTRY +- }; +- +- AuDbg("%.*s\n", AuDLNPair(dentry)); +- IMustLock(dir); +- +- parent = dentry->d_parent; /* dir inode is locked */ +- err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); +- if (unlikely(err)) +- goto out; +- err = au_d_may_add(dentry); +- if (unlikely(err)) +- goto out_unlock; +- di_write_lock_parent(parent); +- wh_dentry = lock_hdir_lkup_wh(dentry, &dt, /*src_dentry*/NULL, &pin, +- &wr_dir_args); +- err = PTR_ERR(wh_dentry); +- if (IS_ERR(wh_dentry)) +- goto out_parent; +- +- bstart = au_dbstart(dentry); +- h_path.dentry = au_h_dptr(dentry, bstart); +- h_path.mnt = au_sbr_mnt(dentry->d_sb, bstart); +- h_dir = au_pinned_h_dir(&pin); +- switch (arg->type) { +- case Creat: +- err = vfsub_create(h_dir, &h_path, arg->u.c.mode, +- arg->u.c.want_excl); +- break; +- case Symlink: +- err = vfsub_symlink(h_dir, &h_path, arg->u.s.symname); +- break; +- case Mknod: +- err = vfsub_mknod(h_dir, &h_path, arg->u.m.mode, arg->u.m.dev); +- break; +- default: +- BUG(); +- } +- created = !err; +- if (!err) +- err = epilog(dir, bstart, wh_dentry, dentry); +- +- /* revert */ +- if (unlikely(created && err && h_path.dentry->d_inode)) { +- int rerr; +- rerr = vfsub_unlink(h_dir, &h_path, /*force*/0); +- if (rerr) { +- AuIOErr("%.*s revert failure(%d, %d)\n", +- AuDLNPair(dentry), err, rerr); +- err = -EIO; +- } +- au_dtime_revert(&dt); +- } +- +- au_unpin(&pin); +- dput(wh_dentry); +- +-out_parent: +- di_write_unlock(parent); +-out_unlock: +- if (unlikely(err)) { +- au_update_dbstart(dentry); +- d_drop(dentry); +- } +- aufs_read_unlock(dentry, AuLock_DW); +-out: +- return err; +-} +- +-int aufs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, +- dev_t dev) +-{ +- struct simple_arg arg = { +- .type = Mknod, +- .u.m = { +- .mode = mode, +- .dev = dev +- } +- }; +- return add_simple(dir, dentry, &arg); +-} +- +-int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) +-{ +- struct simple_arg arg = { +- .type = Symlink, +- .u.s.symname = symname +- }; +- return add_simple(dir, dentry, &arg); +-} +- +-int aufs_create(struct inode *dir, struct dentry *dentry, umode_t mode, +- bool want_excl) +-{ +- struct simple_arg arg = { +- .type = Creat, +- .u.c = { +- .mode = mode, +- .want_excl = want_excl +- } +- }; +- return add_simple(dir, dentry, &arg); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-struct au_link_args { +- aufs_bindex_t bdst, bsrc; +- struct au_pin pin; +- struct path h_path; +- struct dentry *src_parent, *parent; +-}; +- +-static int au_cpup_before_link(struct dentry *src_dentry, +- struct au_link_args *a) +-{ +- int err; +- struct dentry *h_src_dentry; +- struct mutex *h_mtx; +- struct file *h_file; +- +- di_read_lock_parent(a->src_parent, AuLock_IR); +- err = au_test_and_cpup_dirs(src_dentry, a->bdst); +- if (unlikely(err)) +- goto out; +- +- h_src_dentry = au_h_dptr(src_dentry, a->bsrc); +- h_mtx = &h_src_dentry->d_inode->i_mutex; +- err = au_pin(&a->pin, src_dentry, a->bdst, +- au_opt_udba(src_dentry->d_sb), +- AuPin_DI_LOCKED | AuPin_MNT_WRITE); +- if (unlikely(err)) +- goto out; +- mutex_lock_nested(h_mtx, AuLsc_I_CHILD); +- h_file = au_h_open_pre(src_dentry, a->bsrc); +- if (IS_ERR(h_file)) { +- err = PTR_ERR(h_file); +- h_file = NULL; +- } else +- err = au_sio_cpup_simple(src_dentry, a->bdst, -1, +- AuCpup_DTIME /* | AuCpup_KEEPLINO */); +- mutex_unlock(h_mtx); +- au_h_open_post(src_dentry, a->bsrc, h_file); +- au_unpin(&a->pin); +- +-out: +- di_read_unlock(a->src_parent, AuLock_IR); +- return err; +-} +- +-static int au_cpup_or_link(struct dentry *src_dentry, struct au_link_args *a) +-{ +- int err; +- unsigned char plink; +- struct inode *h_inode, *inode; +- struct dentry *h_src_dentry; +- struct super_block *sb; +- struct file *h_file; +- +- plink = 0; +- h_inode = NULL; +- sb = src_dentry->d_sb; +- inode = src_dentry->d_inode; +- if (au_ibstart(inode) <= a->bdst) +- h_inode = au_h_iptr(inode, a->bdst); +- if (!h_inode || !h_inode->i_nlink) { +- /* copyup src_dentry as the name of dentry. */ +- au_set_dbstart(src_dentry, a->bdst); +- au_set_h_dptr(src_dentry, a->bdst, dget(a->h_path.dentry)); +- h_inode = au_h_dptr(src_dentry, a->bsrc)->d_inode; +- mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); +- h_file = au_h_open_pre(src_dentry, a->bsrc); +- if (IS_ERR(h_file)) { +- err = PTR_ERR(h_file); +- h_file = NULL; +- } else +- err = au_sio_cpup_single(src_dentry, a->bdst, a->bsrc, +- -1, AuCpup_KEEPLINO, +- a->parent); +- mutex_unlock(&h_inode->i_mutex); +- au_h_open_post(src_dentry, a->bsrc, h_file); +- au_set_h_dptr(src_dentry, a->bdst, NULL); +- au_set_dbstart(src_dentry, a->bsrc); +- } else { +- /* the inode of src_dentry already exists on a.bdst branch */ +- h_src_dentry = d_find_alias(h_inode); +- if (!h_src_dentry && au_plink_test(inode)) { +- plink = 1; +- h_src_dentry = au_plink_lkup(inode, a->bdst); +- err = PTR_ERR(h_src_dentry); +- if (IS_ERR(h_src_dentry)) +- goto out; +- +- if (unlikely(!h_src_dentry->d_inode)) { +- dput(h_src_dentry); +- h_src_dentry = NULL; +- } +- +- } +- if (h_src_dentry) { +- err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), +- &a->h_path); +- dput(h_src_dentry); +- } else { +- AuIOErr("no dentry found for hi%lu on b%d\n", +- h_inode->i_ino, a->bdst); +- err = -EIO; +- } +- } +- +- if (!err && !plink) +- au_plink_append(inode, a->bdst, a->h_path.dentry); +- +-out: +- AuTraceErr(err); +- return err; +-} +- +-int aufs_link(struct dentry *src_dentry, struct inode *dir, +- struct dentry *dentry) +-{ +- int err, rerr; +- struct au_dtime dt; +- struct au_link_args *a; +- struct dentry *wh_dentry, *h_src_dentry; +- struct inode *inode; +- struct super_block *sb; +- struct au_wr_dir_args wr_dir_args = { +- /* .force_btgt = -1, */ +- .flags = AuWrDir_ADD_ENTRY +- }; +- +- IMustLock(dir); +- inode = src_dentry->d_inode; +- IMustLock(inode); +- +- err = -ENOMEM; +- a = kzalloc(sizeof(*a), GFP_NOFS); +- if (unlikely(!a)) +- goto out; +- +- a->parent = dentry->d_parent; /* dir inode is locked */ +- err = aufs_read_and_write_lock2(dentry, src_dentry, +- AuLock_NOPLM | AuLock_GEN); +- if (unlikely(err)) +- goto out_kfree; +- err = au_d_hashed_positive(src_dentry); +- if (unlikely(err)) +- goto out_unlock; +- err = au_d_may_add(dentry); +- if (unlikely(err)) +- goto out_unlock; +- +- a->src_parent = dget_parent(src_dentry); +- wr_dir_args.force_btgt = au_ibstart(inode); +- +- di_write_lock_parent(a->parent); +- wr_dir_args.force_btgt = au_wbr(dentry, wr_dir_args.force_btgt); +- wh_dentry = lock_hdir_lkup_wh(dentry, &dt, src_dentry, &a->pin, +- &wr_dir_args); +- err = PTR_ERR(wh_dentry); +- if (IS_ERR(wh_dentry)) +- goto out_parent; +- +- err = 0; +- sb = dentry->d_sb; +- a->bdst = au_dbstart(dentry); +- a->h_path.dentry = au_h_dptr(dentry, a->bdst); +- a->h_path.mnt = au_sbr_mnt(sb, a->bdst); +- a->bsrc = au_ibstart(inode); +- h_src_dentry = au_h_d_alias(src_dentry, a->bsrc); +- if (!h_src_dentry) { +- a->bsrc = au_dbstart(src_dentry); +- h_src_dentry = au_h_d_alias(src_dentry, a->bsrc); +- AuDebugOn(!h_src_dentry); +- } else if (IS_ERR(h_src_dentry)) +- goto out_parent; +- +- if (au_opt_test(au_mntflags(sb), PLINK)) { +- if (a->bdst < a->bsrc +- /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) +- err = au_cpup_or_link(src_dentry, a); +- else +- err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), +- &a->h_path); +- dput(h_src_dentry); +- } else { +- /* +- * copyup src_dentry to the branch we process, +- * and then link(2) to it. +- */ +- dput(h_src_dentry); +- if (a->bdst < a->bsrc +- /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) { +- au_unpin(&a->pin); +- di_write_unlock(a->parent); +- err = au_cpup_before_link(src_dentry, a); +- di_write_lock_parent(a->parent); +- if (!err) +- err = au_pin(&a->pin, dentry, a->bdst, +- au_opt_udba(sb), +- AuPin_DI_LOCKED | AuPin_MNT_WRITE); +- if (unlikely(err)) +- goto out_wh; +- } +- if (!err) { +- h_src_dentry = au_h_dptr(src_dentry, a->bdst); +- err = -ENOENT; +- if (h_src_dentry && h_src_dentry->d_inode) +- err = vfsub_link(h_src_dentry, +- au_pinned_h_dir(&a->pin), +- &a->h_path); +- } +- } +- if (unlikely(err)) +- goto out_unpin; +- +- if (wh_dentry) { +- a->h_path.dentry = wh_dentry; +- err = au_wh_unlink_dentry(au_pinned_h_dir(&a->pin), &a->h_path, +- dentry); +- if (unlikely(err)) +- goto out_revert; +- } +- +- dir->i_version++; +- if (au_ibstart(dir) == au_dbstart(dentry)) +- au_cpup_attr_timesizes(dir); +- inc_nlink(inode); +- inode->i_ctime = dir->i_ctime; +- d_instantiate(dentry, au_igrab(inode)); +- if (d_unhashed(a->h_path.dentry)) +- /* some filesystem calls d_drop() */ +- d_drop(dentry); +- goto out_unpin; /* success */ +- +-out_revert: +- rerr = vfsub_unlink(au_pinned_h_dir(&a->pin), &a->h_path, /*force*/0); +- if (unlikely(rerr)) { +- AuIOErr("%.*s reverting failed(%d, %d)\n", +- AuDLNPair(dentry), err, rerr); +- err = -EIO; +- } +- au_dtime_revert(&dt); +-out_unpin: +- au_unpin(&a->pin); +-out_wh: +- dput(wh_dentry); +-out_parent: +- di_write_unlock(a->parent); +- dput(a->src_parent); +-out_unlock: +- if (unlikely(err)) { +- au_update_dbstart(dentry); +- d_drop(dentry); +- } +- aufs_read_and_write_unlock2(dentry, src_dentry); +-out_kfree: +- kfree(a); +-out: +- return err; +-} +- +-int aufs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) +-{ +- int err, rerr; +- aufs_bindex_t bindex; +- unsigned char diropq; +- struct path h_path; +- struct dentry *wh_dentry, *parent, *opq_dentry; +- struct mutex *h_mtx; +- struct super_block *sb; +- struct { +- struct au_pin pin; +- struct au_dtime dt; +- } *a; /* reduce the stack usage */ +- struct au_wr_dir_args wr_dir_args = { +- .force_btgt = -1, +- .flags = AuWrDir_ADD_ENTRY | AuWrDir_ISDIR +- }; +- +- IMustLock(dir); +- +- err = -ENOMEM; +- a = kmalloc(sizeof(*a), GFP_NOFS); +- if (unlikely(!a)) +- goto out; +- +- err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); +- if (unlikely(err)) +- goto out_free; +- err = au_d_may_add(dentry); +- if (unlikely(err)) +- goto out_unlock; +- +- parent = dentry->d_parent; /* dir inode is locked */ +- di_write_lock_parent(parent); +- wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL, +- &a->pin, &wr_dir_args); +- err = PTR_ERR(wh_dentry); +- if (IS_ERR(wh_dentry)) +- goto out_parent; +- +- sb = dentry->d_sb; +- bindex = au_dbstart(dentry); +- h_path.dentry = au_h_dptr(dentry, bindex); +- h_path.mnt = au_sbr_mnt(sb, bindex); +- err = vfsub_mkdir(au_pinned_h_dir(&a->pin), &h_path, mode); +- if (unlikely(err)) +- goto out_unpin; +- +- /* make the dir opaque */ +- diropq = 0; +- h_mtx = &h_path.dentry->d_inode->i_mutex; +- if (wh_dentry +- || au_opt_test(au_mntflags(sb), ALWAYS_DIROPQ)) { +- mutex_lock_nested(h_mtx, AuLsc_I_CHILD); +- opq_dentry = au_diropq_create(dentry, bindex); +- mutex_unlock(h_mtx); +- err = PTR_ERR(opq_dentry); +- if (IS_ERR(opq_dentry)) +- goto out_dir; +- dput(opq_dentry); +- diropq = 1; +- } +- +- err = epilog(dir, bindex, wh_dentry, dentry); +- if (!err) { +- inc_nlink(dir); +- goto out_unpin; /* success */ +- } +- +- /* revert */ +- if (diropq) { +- AuLabel(revert opq); +- mutex_lock_nested(h_mtx, AuLsc_I_CHILD); +- rerr = au_diropq_remove(dentry, bindex); +- mutex_unlock(h_mtx); +- if (rerr) { +- AuIOErr("%.*s reverting diropq failed(%d, %d)\n", +- AuDLNPair(dentry), err, rerr); +- err = -EIO; +- } +- } +- +-out_dir: +- AuLabel(revert dir); +- rerr = vfsub_rmdir(au_pinned_h_dir(&a->pin), &h_path); +- if (rerr) { +- AuIOErr("%.*s reverting dir failed(%d, %d)\n", +- AuDLNPair(dentry), err, rerr); +- err = -EIO; +- } +- au_dtime_revert(&a->dt); +-out_unpin: +- au_unpin(&a->pin); +- dput(wh_dentry); +-out_parent: +- di_write_unlock(parent); +-out_unlock: +- if (unlikely(err)) { +- au_update_dbstart(dentry); +- d_drop(dentry); +- } +- aufs_read_unlock(dentry, AuLock_DW); +-out_free: +- kfree(a); +-out: +- return err; +-} +diff --git a/fs/aufs/i_op_del.c b/fs/aufs/i_op_del.c +deleted file mode 100644 +index c2b0a64..0000000 +--- a/fs/aufs/i_op_del.c ++++ /dev/null +@@ -1,477 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * inode operations (del entry) +- */ +- +-#include "aufs.h" +- +-/* +- * decide if a new whiteout for @dentry is necessary or not. +- * when it is necessary, prepare the parent dir for the upper branch whose +- * branch index is @bcpup for creation. the actual creation of the whiteout will +- * be done by caller. +- * return value: +- * 0: wh is unnecessary +- * plus: wh is necessary +- * minus: error +- */ +-int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup) +-{ +- int need_wh, err; +- aufs_bindex_t bstart; +- struct super_block *sb; +- +- sb = dentry->d_sb; +- bstart = au_dbstart(dentry); +- if (*bcpup < 0) { +- *bcpup = bstart; +- if (au_test_ro(sb, bstart, dentry->d_inode)) { +- err = AuWbrCopyup(au_sbi(sb), dentry); +- *bcpup = err; +- if (unlikely(err < 0)) +- goto out; +- } +- } else +- AuDebugOn(bstart < *bcpup +- || au_test_ro(sb, *bcpup, dentry->d_inode)); +- AuDbg("bcpup %d, bstart %d\n", *bcpup, bstart); +- +- if (*bcpup != bstart) { +- err = au_cpup_dirs(dentry, *bcpup); +- if (unlikely(err)) +- goto out; +- need_wh = 1; +- } else { +- struct au_dinfo *dinfo, *tmp; +- +- need_wh = -ENOMEM; +- dinfo = au_di(dentry); +- tmp = au_di_alloc(sb, AuLsc_DI_TMP); +- if (tmp) { +- au_di_cp(tmp, dinfo); +- au_di_swap(tmp, dinfo); +- /* returns the number of positive dentries */ +- need_wh = au_lkup_dentry(dentry, bstart + 1, /*type*/0); +- au_di_swap(tmp, dinfo); +- au_rw_write_unlock(&tmp->di_rwsem); +- au_di_free(tmp); +- } +- } +- AuDbg("need_wh %d\n", need_wh); +- err = need_wh; +- +-out: +- return err; +-} +- +-/* +- * simple tests for the del-entry operations. +- * following the checks in vfs, plus the parent-child relationship. +- */ +-int au_may_del(struct dentry *dentry, aufs_bindex_t bindex, +- struct dentry *h_parent, int isdir) +-{ +- int err; +- umode_t h_mode; +- struct dentry *h_dentry, *h_latest; +- struct inode *h_inode; +- +- h_dentry = au_h_dptr(dentry, bindex); +- h_inode = h_dentry->d_inode; +- if (dentry->d_inode) { +- err = -ENOENT; +- if (unlikely(!h_inode || !h_inode->i_nlink)) +- goto out; +- +- h_mode = h_inode->i_mode; +- if (!isdir) { +- err = -EISDIR; +- if (unlikely(S_ISDIR(h_mode))) +- goto out; +- } else if (unlikely(!S_ISDIR(h_mode))) { +- err = -ENOTDIR; +- goto out; +- } +- } else { +- /* rename(2) case */ +- err = -EIO; +- if (unlikely(h_inode)) +- goto out; +- } +- +- err = -ENOENT; +- /* expected parent dir is locked */ +- if (unlikely(h_parent != h_dentry->d_parent)) +- goto out; +- err = 0; +- +- /* +- * rmdir a dir may break the consistency on some filesystem. +- * let's try heavy test. +- */ +- err = -EACCES; +- if (unlikely(au_test_h_perm(h_parent->d_inode, MAY_EXEC | MAY_WRITE))) +- goto out; +- +- h_latest = au_sio_lkup_one(&dentry->d_name, h_parent, +- au_sbr(dentry->d_sb, bindex)); +- err = -EIO; +- if (IS_ERR(h_latest)) +- goto out; +- if (h_latest == h_dentry) +- err = 0; +- dput(h_latest); +- +-out: +- return err; +-} +- +-/* +- * decide the branch where we operate for @dentry. the branch index will be set +- * @rbcpup. after diciding it, 'pin' it and store the timestamps of the parent +- * dir for reverting. +- * when a new whiteout is necessary, create it. +- */ +-static struct dentry* +-lock_hdir_create_wh(struct dentry *dentry, int isdir, aufs_bindex_t *rbcpup, +- struct au_dtime *dt, struct au_pin *pin) +-{ +- struct dentry *wh_dentry; +- struct super_block *sb; +- struct path h_path; +- int err, need_wh; +- unsigned int udba; +- aufs_bindex_t bcpup; +- +- need_wh = au_wr_dir_need_wh(dentry, isdir, rbcpup); +- wh_dentry = ERR_PTR(need_wh); +- if (unlikely(need_wh < 0)) +- goto out; +- +- sb = dentry->d_sb; +- udba = au_opt_udba(sb); +- bcpup = *rbcpup; +- err = au_pin(pin, dentry, bcpup, udba, +- AuPin_DI_LOCKED | AuPin_MNT_WRITE); +- wh_dentry = ERR_PTR(err); +- if (unlikely(err)) +- goto out; +- +- h_path.dentry = au_pinned_h_parent(pin); +- if (udba != AuOpt_UDBA_NONE +- && au_dbstart(dentry) == bcpup) { +- err = au_may_del(dentry, bcpup, h_path.dentry, isdir); +- wh_dentry = ERR_PTR(err); +- if (unlikely(err)) +- goto out_unpin; +- } +- +- h_path.mnt = au_sbr_mnt(sb, bcpup); +- au_dtime_store(dt, au_pinned_parent(pin), &h_path); +- wh_dentry = NULL; +- if (!need_wh) +- goto out; /* success, no need to create whiteout */ +- +- wh_dentry = au_wh_create(dentry, bcpup, h_path.dentry); +- if (IS_ERR(wh_dentry)) +- goto out_unpin; +- +- /* returns with the parent is locked and wh_dentry is dget-ed */ +- goto out; /* success */ +- +-out_unpin: +- au_unpin(pin); +-out: +- return wh_dentry; +-} +- +-/* +- * when removing a dir, rename it to a unique temporary whiteout-ed name first +- * in order to be revertible and save time for removing many child whiteouts +- * under the dir. +- * returns 1 when there are too many child whiteout and caller should remove +- * them asynchronously. returns 0 when the number of children is enough small to +- * remove now or the branch fs is a remote fs. +- * otherwise return an error. +- */ +-static int renwh_and_rmdir(struct dentry *dentry, aufs_bindex_t bindex, +- struct au_nhash *whlist, struct inode *dir) +-{ +- int rmdir_later, err, dirwh; +- struct dentry *h_dentry; +- struct super_block *sb; +- +- sb = dentry->d_sb; +- SiMustAnyLock(sb); +- h_dentry = au_h_dptr(dentry, bindex); +- err = au_whtmp_ren(h_dentry, au_sbr(sb, bindex)); +- if (unlikely(err)) +- goto out; +- +- /* stop monitoring */ +- au_hn_free(au_hi(dentry->d_inode, bindex)); +- +- if (!au_test_fs_remote(h_dentry->d_sb)) { +- dirwh = au_sbi(sb)->si_dirwh; +- rmdir_later = (dirwh <= 1); +- if (!rmdir_later) +- rmdir_later = au_nhash_test_longer_wh(whlist, bindex, +- dirwh); +- if (rmdir_later) +- return rmdir_later; +- } +- +- err = au_whtmp_rmdir(dir, bindex, h_dentry, whlist); +- if (unlikely(err)) { +- AuIOErr("rmdir %.*s, b%d failed, %d. ignored\n", +- AuDLNPair(h_dentry), bindex, err); +- err = 0; +- } +- +-out: +- AuTraceErr(err); +- return err; +-} +- +-/* +- * final procedure for deleting a entry. +- * maintain dentry and iattr. +- */ +-static void epilog(struct inode *dir, struct dentry *dentry, +- aufs_bindex_t bindex) +-{ +- struct inode *inode; +- +- inode = dentry->d_inode; +- d_drop(dentry); +- inode->i_ctime = dir->i_ctime; +- +- if (au_ibstart(dir) == bindex) +- au_cpup_attr_timesizes(dir); +- dir->i_version++; +-} +- +-/* +- * when an error happened, remove the created whiteout and revert everything. +- */ +-static int do_revert(int err, struct inode *dir, aufs_bindex_t bindex, +- aufs_bindex_t bwh, struct dentry *wh_dentry, +- struct dentry *dentry, struct au_dtime *dt) +-{ +- int rerr; +- struct path h_path = { +- .dentry = wh_dentry, +- .mnt = au_sbr_mnt(dir->i_sb, bindex) +- }; +- +- rerr = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path, dentry); +- if (!rerr) { +- au_set_dbwh(dentry, bwh); +- au_dtime_revert(dt); +- return 0; +- } +- +- AuIOErr("%.*s reverting whiteout failed(%d, %d)\n", +- AuDLNPair(dentry), err, rerr); +- return -EIO; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-int aufs_unlink(struct inode *dir, struct dentry *dentry) +-{ +- int err; +- aufs_bindex_t bwh, bindex, bstart; +- struct au_dtime dt; +- struct au_pin pin; +- struct path h_path; +- struct inode *inode, *h_dir; +- struct dentry *parent, *wh_dentry; +- +- IMustLock(dir); +- +- err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); +- if (unlikely(err)) +- goto out; +- err = au_d_hashed_positive(dentry); +- if (unlikely(err)) +- goto out_unlock; +- inode = dentry->d_inode; +- IMustLock(inode); +- err = -EISDIR; +- if (unlikely(S_ISDIR(inode->i_mode))) +- goto out_unlock; /* possible? */ +- +- bstart = au_dbstart(dentry); +- bwh = au_dbwh(dentry); +- bindex = -1; +- parent = dentry->d_parent; /* dir inode is locked */ +- di_write_lock_parent(parent); +- wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/0, &bindex, &dt, &pin); +- err = PTR_ERR(wh_dentry); +- if (IS_ERR(wh_dentry)) +- goto out_parent; +- +- h_path.mnt = au_sbr_mnt(dentry->d_sb, bstart); +- h_path.dentry = au_h_dptr(dentry, bstart); +- dget(h_path.dentry); +- if (bindex == bstart) { +- h_dir = au_pinned_h_dir(&pin); +- err = vfsub_unlink(h_dir, &h_path, /*force*/0); +- } else { +- /* dir inode is locked */ +- h_dir = wh_dentry->d_parent->d_inode; +- IMustLock(h_dir); +- err = 0; +- } +- +- if (!err) { +- vfsub_drop_nlink(inode); +- epilog(dir, dentry, bindex); +- +- /* update target timestamps */ +- if (bindex == bstart) { +- vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/ +- inode->i_ctime = h_path.dentry->d_inode->i_ctime; +- } else +- /* todo: this timestamp may be reverted later */ +- inode->i_ctime = h_dir->i_ctime; +- goto out_unpin; /* success */ +- } +- +- /* revert */ +- if (wh_dentry) { +- int rerr; +- +- rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry, &dt); +- if (rerr) +- err = rerr; +- } +- +-out_unpin: +- au_unpin(&pin); +- dput(wh_dentry); +- dput(h_path.dentry); +-out_parent: +- di_write_unlock(parent); +-out_unlock: +- aufs_read_unlock(dentry, AuLock_DW); +-out: +- return err; +-} +- +-int aufs_rmdir(struct inode *dir, struct dentry *dentry) +-{ +- int err, rmdir_later; +- aufs_bindex_t bwh, bindex, bstart; +- struct au_dtime dt; +- struct au_pin pin; +- struct inode *inode; +- struct dentry *parent, *wh_dentry, *h_dentry; +- struct au_whtmp_rmdir *args; +- +- IMustLock(dir); +- +- err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_GEN); +- if (unlikely(err)) +- goto out; +- err = au_alive_dir(dentry); +- if (unlikely(err)) +- goto out_unlock; +- inode = dentry->d_inode; +- IMustLock(inode); +- err = -ENOTDIR; +- if (unlikely(!S_ISDIR(inode->i_mode))) +- goto out_unlock; /* possible? */ +- +- err = -ENOMEM; +- args = au_whtmp_rmdir_alloc(dir->i_sb, GFP_NOFS); +- if (unlikely(!args)) +- goto out_unlock; +- +- parent = dentry->d_parent; /* dir inode is locked */ +- di_write_lock_parent(parent); +- err = au_test_empty(dentry, &args->whlist); +- if (unlikely(err)) +- goto out_parent; +- +- bstart = au_dbstart(dentry); +- bwh = au_dbwh(dentry); +- bindex = -1; +- wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/1, &bindex, &dt, &pin); +- err = PTR_ERR(wh_dentry); +- if (IS_ERR(wh_dentry)) +- goto out_parent; +- +- h_dentry = au_h_dptr(dentry, bstart); +- dget(h_dentry); +- rmdir_later = 0; +- if (bindex == bstart) { +- err = renwh_and_rmdir(dentry, bstart, &args->whlist, dir); +- if (err > 0) { +- rmdir_later = err; +- err = 0; +- } +- } else { +- /* stop monitoring */ +- au_hn_free(au_hi(inode, bstart)); +- +- /* dir inode is locked */ +- IMustLock(wh_dentry->d_parent->d_inode); +- err = 0; +- } +- +- if (!err) { +- vfsub_dead_dir(inode); +- au_set_dbdiropq(dentry, -1); +- epilog(dir, dentry, bindex); +- +- if (rmdir_later) { +- au_whtmp_kick_rmdir(dir, bstart, h_dentry, args); +- args = NULL; +- } +- +- goto out_unpin; /* success */ +- } +- +- /* revert */ +- AuLabel(revert); +- if (wh_dentry) { +- int rerr; +- +- rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry, &dt); +- if (rerr) +- err = rerr; +- } +- +-out_unpin: +- au_unpin(&pin); +- dput(wh_dentry); +- dput(h_dentry); +-out_parent: +- di_write_unlock(parent); +- if (args) +- au_whtmp_rmdir_free(args); +-out_unlock: +- aufs_read_unlock(dentry, AuLock_DW); +-out: +- AuTraceErr(err); +- return err; +-} +diff --git a/fs/aufs/i_op_ren.c b/fs/aufs/i_op_ren.c +deleted file mode 100644 +index 83f6606..0000000 +--- a/fs/aufs/i_op_ren.c ++++ /dev/null +@@ -1,1026 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * inode operation (rename entry) +- * todo: this is crazy monster +- */ +- +-#include "aufs.h" +- +-enum { AuSRC, AuDST, AuSrcDst }; +-enum { AuPARENT, AuCHILD, AuParentChild }; +- +-#define AuRen_ISDIR 1 +-#define AuRen_ISSAMEDIR (1 << 1) +-#define AuRen_WHSRC (1 << 2) +-#define AuRen_WHDST (1 << 3) +-#define AuRen_MNT_WRITE (1 << 4) +-#define AuRen_DT_DSTDIR (1 << 5) +-#define AuRen_DIROPQ (1 << 6) +-#define AuRen_CPUP (1 << 7) +-#define au_ftest_ren(flags, name) ((flags) & AuRen_##name) +-#define au_fset_ren(flags, name) \ +- do { (flags) |= AuRen_##name; } while (0) +-#define au_fclr_ren(flags, name) \ +- do { (flags) &= ~AuRen_##name; } while (0) +- +-struct au_ren_args { +- struct { +- struct dentry *dentry, *h_dentry, *parent, *h_parent, +- *wh_dentry; +- struct inode *dir, *inode; +- struct au_hinode *hdir; +- struct au_dtime dt[AuParentChild]; +- aufs_bindex_t bstart; +- } sd[AuSrcDst]; +- +-#define src_dentry sd[AuSRC].dentry +-#define src_dir sd[AuSRC].dir +-#define src_inode sd[AuSRC].inode +-#define src_h_dentry sd[AuSRC].h_dentry +-#define src_parent sd[AuSRC].parent +-#define src_h_parent sd[AuSRC].h_parent +-#define src_wh_dentry sd[AuSRC].wh_dentry +-#define src_hdir sd[AuSRC].hdir +-#define src_h_dir sd[AuSRC].hdir->hi_inode +-#define src_dt sd[AuSRC].dt +-#define src_bstart sd[AuSRC].bstart +- +-#define dst_dentry sd[AuDST].dentry +-#define dst_dir sd[AuDST].dir +-#define dst_inode sd[AuDST].inode +-#define dst_h_dentry sd[AuDST].h_dentry +-#define dst_parent sd[AuDST].parent +-#define dst_h_parent sd[AuDST].h_parent +-#define dst_wh_dentry sd[AuDST].wh_dentry +-#define dst_hdir sd[AuDST].hdir +-#define dst_h_dir sd[AuDST].hdir->hi_inode +-#define dst_dt sd[AuDST].dt +-#define dst_bstart sd[AuDST].bstart +- +- struct dentry *h_trap; +- struct au_branch *br; +- struct au_hinode *src_hinode; +- struct path h_path; +- struct au_nhash whlist; +- aufs_bindex_t btgt, src_bwh, src_bdiropq; +- +- unsigned int flags; +- +- struct au_whtmp_rmdir *thargs; +- struct dentry *h_dst; +-}; +- +-/* ---------------------------------------------------------------------- */ +- +-/* +- * functions for reverting. +- * when an error happened in a single rename systemcall, we should revert +- * everything as if nothing happend. +- * we don't need to revert the copied-up/down the parent dir since they are +- * harmless. +- */ +- +-#define RevertFailure(fmt, ...) do { \ +- AuIOErr("revert failure: " fmt " (%d, %d)\n", \ +- ##__VA_ARGS__, err, rerr); \ +- err = -EIO; \ +-} while (0) +- +-static void au_ren_rev_diropq(int err, struct au_ren_args *a) +-{ +- int rerr; +- +- au_hn_imtx_lock_nested(a->src_hinode, AuLsc_I_CHILD); +- rerr = au_diropq_remove(a->src_dentry, a->btgt); +- au_hn_imtx_unlock(a->src_hinode); +- au_set_dbdiropq(a->src_dentry, a->src_bdiropq); +- if (rerr) +- RevertFailure("remove diropq %.*s", AuDLNPair(a->src_dentry)); +-} +- +-static void au_ren_rev_rename(int err, struct au_ren_args *a) +-{ +- int rerr; +- +- a->h_path.dentry = vfsub_lkup_one(&a->src_dentry->d_name, +- a->src_h_parent); +- rerr = PTR_ERR(a->h_path.dentry); +- if (IS_ERR(a->h_path.dentry)) { +- RevertFailure("lkup one %.*s", AuDLNPair(a->src_dentry)); +- return; +- } +- +- rerr = vfsub_rename(a->dst_h_dir, +- au_h_dptr(a->src_dentry, a->btgt), +- a->src_h_dir, &a->h_path); +- d_drop(a->h_path.dentry); +- dput(a->h_path.dentry); +- /* au_set_h_dptr(a->src_dentry, a->btgt, NULL); */ +- if (rerr) +- RevertFailure("rename %.*s", AuDLNPair(a->src_dentry)); +-} +- +-static void au_ren_rev_cpup(int err, struct au_ren_args *a) +-{ +- int rerr; +- +- a->h_path.dentry = a->dst_h_dentry; +- rerr = vfsub_unlink(a->dst_h_dir, &a->h_path, /*force*/0); +- au_set_h_dptr(a->src_dentry, a->btgt, NULL); +- au_set_dbstart(a->src_dentry, a->src_bstart); +- if (rerr) +- RevertFailure("unlink %.*s", AuDLNPair(a->dst_h_dentry)); +-} +- +-static void au_ren_rev_whtmp(int err, struct au_ren_args *a) +-{ +- int rerr; +- +- a->h_path.dentry = vfsub_lkup_one(&a->dst_dentry->d_name, +- a->dst_h_parent); +- rerr = PTR_ERR(a->h_path.dentry); +- if (IS_ERR(a->h_path.dentry)) { +- RevertFailure("lkup one %.*s", AuDLNPair(a->dst_dentry)); +- return; +- } +- if (a->h_path.dentry->d_inode) { +- d_drop(a->h_path.dentry); +- dput(a->h_path.dentry); +- return; +- } +- +- rerr = vfsub_rename(a->dst_h_dir, a->h_dst, a->dst_h_dir, &a->h_path); +- d_drop(a->h_path.dentry); +- dput(a->h_path.dentry); +- if (!rerr) +- au_set_h_dptr(a->dst_dentry, a->btgt, dget(a->h_dst)); +- else +- RevertFailure("rename %.*s", AuDLNPair(a->h_dst)); +-} +- +-static void au_ren_rev_whsrc(int err, struct au_ren_args *a) +-{ +- int rerr; +- +- a->h_path.dentry = a->src_wh_dentry; +- rerr = au_wh_unlink_dentry(a->src_h_dir, &a->h_path, a->src_dentry); +- au_set_dbwh(a->src_dentry, a->src_bwh); +- if (rerr) +- RevertFailure("unlink %.*s", AuDLNPair(a->src_wh_dentry)); +-} +-#undef RevertFailure +- +-/* ---------------------------------------------------------------------- */ +- +-/* +- * when we have to copyup the renaming entry, do it with the rename-target name +- * in order to minimize the cost (the later actual rename is unnecessary). +- * otherwise rename it on the target branch. +- */ +-static int au_ren_or_cpup(struct au_ren_args *a) +-{ +- int err; +- struct dentry *d; +- +- d = a->src_dentry; +- if (au_dbstart(d) == a->btgt) { +- a->h_path.dentry = a->dst_h_dentry; +- if (au_ftest_ren(a->flags, DIROPQ) +- && au_dbdiropq(d) == a->btgt) +- au_fclr_ren(a->flags, DIROPQ); +- AuDebugOn(au_dbstart(d) != a->btgt); +- err = vfsub_rename(a->src_h_dir, au_h_dptr(d, a->btgt), +- a->dst_h_dir, &a->h_path); +- } else { +- struct mutex *h_mtx = &a->src_h_dentry->d_inode->i_mutex; +- struct file *h_file; +- +- au_fset_ren(a->flags, CPUP); +- mutex_lock_nested(h_mtx, AuLsc_I_CHILD); +- au_set_dbstart(d, a->btgt); +- au_set_h_dptr(d, a->btgt, dget(a->dst_h_dentry)); +- h_file = au_h_open_pre(d, a->src_bstart); +- if (IS_ERR(h_file)) { +- err = PTR_ERR(h_file); +- h_file = NULL; +- } else +- err = au_sio_cpup_single(d, a->btgt, a->src_bstart, -1, +- !AuCpup_DTIME, a->dst_parent); +- mutex_unlock(h_mtx); +- au_h_open_post(d, a->src_bstart, h_file); +- if (!err) { +- d = a->dst_dentry; +- au_set_h_dptr(d, a->btgt, NULL); +- au_update_dbstart(d); +- } else { +- au_set_h_dptr(d, a->btgt, NULL); +- au_set_dbstart(d, a->src_bstart); +- } +- } +- if (!err && a->h_dst) +- /* it will be set to dinfo later */ +- dget(a->h_dst); +- +- return err; +-} +- +-/* cf. aufs_rmdir() */ +-static int au_ren_del_whtmp(struct au_ren_args *a) +-{ +- int err; +- struct inode *dir; +- +- dir = a->dst_dir; +- SiMustAnyLock(dir->i_sb); +- if (!au_nhash_test_longer_wh(&a->whlist, a->btgt, +- au_sbi(dir->i_sb)->si_dirwh) +- || au_test_fs_remote(a->h_dst->d_sb)) { +- err = au_whtmp_rmdir(dir, a->btgt, a->h_dst, &a->whlist); +- if (unlikely(err)) +- pr_warn("failed removing whtmp dir %.*s (%d), " +- "ignored.\n", AuDLNPair(a->h_dst), err); +- } else { +- au_nhash_wh_free(&a->thargs->whlist); +- a->thargs->whlist = a->whlist; +- a->whlist.nh_num = 0; +- au_whtmp_kick_rmdir(dir, a->btgt, a->h_dst, a->thargs); +- dput(a->h_dst); +- a->thargs = NULL; +- } +- +- return 0; +-} +- +-/* make it 'opaque' dir. */ +-static int au_ren_diropq(struct au_ren_args *a) +-{ +- int err; +- struct dentry *diropq; +- +- err = 0; +- a->src_bdiropq = au_dbdiropq(a->src_dentry); +- a->src_hinode = au_hi(a->src_inode, a->btgt); +- au_hn_imtx_lock_nested(a->src_hinode, AuLsc_I_CHILD); +- diropq = au_diropq_create(a->src_dentry, a->btgt); +- au_hn_imtx_unlock(a->src_hinode); +- if (IS_ERR(diropq)) +- err = PTR_ERR(diropq); +- dput(diropq); +- +- return err; +-} +- +-static int do_rename(struct au_ren_args *a) +-{ +- int err; +- struct dentry *d, *h_d; +- +- /* prepare workqueue args for asynchronous rmdir */ +- h_d = a->dst_h_dentry; +- if (au_ftest_ren(a->flags, ISDIR) && h_d->d_inode) { +- err = -ENOMEM; +- a->thargs = au_whtmp_rmdir_alloc(a->src_dentry->d_sb, GFP_NOFS); +- if (unlikely(!a->thargs)) +- goto out; +- a->h_dst = dget(h_d); +- } +- +- /* create whiteout for src_dentry */ +- if (au_ftest_ren(a->flags, WHSRC)) { +- a->src_bwh = au_dbwh(a->src_dentry); +- AuDebugOn(a->src_bwh >= 0); +- a->src_wh_dentry +- = au_wh_create(a->src_dentry, a->btgt, a->src_h_parent); +- err = PTR_ERR(a->src_wh_dentry); +- if (IS_ERR(a->src_wh_dentry)) +- goto out_thargs; +- } +- +- /* lookup whiteout for dentry */ +- if (au_ftest_ren(a->flags, WHDST)) { +- h_d = au_wh_lkup(a->dst_h_parent, &a->dst_dentry->d_name, +- a->br); +- err = PTR_ERR(h_d); +- if (IS_ERR(h_d)) +- goto out_whsrc; +- if (!h_d->d_inode) +- dput(h_d); +- else +- a->dst_wh_dentry = h_d; +- } +- +- /* rename dentry to tmpwh */ +- if (a->thargs) { +- err = au_whtmp_ren(a->dst_h_dentry, a->br); +- if (unlikely(err)) +- goto out_whdst; +- +- d = a->dst_dentry; +- au_set_h_dptr(d, a->btgt, NULL); +- err = au_lkup_neg(d, a->btgt); +- if (unlikely(err)) +- goto out_whtmp; +- a->dst_h_dentry = au_h_dptr(d, a->btgt); +- } +- +- /* cpup src */ +- if (a->dst_h_dentry->d_inode && a->src_bstart != a->btgt) { +- struct mutex *h_mtx = &a->src_h_dentry->d_inode->i_mutex; +- struct file *h_file; +- +- mutex_lock_nested(h_mtx, AuLsc_I_CHILD); +- AuDebugOn(au_dbstart(a->src_dentry) != a->src_bstart); +- h_file = au_h_open_pre(a->src_dentry, a->src_bstart); +- if (IS_ERR(h_file)) { +- err = PTR_ERR(h_file); +- h_file = NULL; +- } else +- err = au_sio_cpup_simple(a->src_dentry, a->btgt, -1, +- !AuCpup_DTIME); +- mutex_unlock(h_mtx); +- au_h_open_post(a->src_dentry, a->src_bstart, h_file); +- if (unlikely(err)) +- goto out_whtmp; +- } +- +- /* rename by vfs_rename or cpup */ +- d = a->dst_dentry; +- if (au_ftest_ren(a->flags, ISDIR) +- && (a->dst_wh_dentry +- || au_dbdiropq(d) == a->btgt +- /* hide the lower to keep xino */ +- || a->btgt < au_dbend(d) +- || au_opt_test(au_mntflags(d->d_sb), ALWAYS_DIROPQ))) +- au_fset_ren(a->flags, DIROPQ); +- err = au_ren_or_cpup(a); +- if (unlikely(err)) +- /* leave the copied-up one */ +- goto out_whtmp; +- +- /* make dir opaque */ +- if (au_ftest_ren(a->flags, DIROPQ)) { +- err = au_ren_diropq(a); +- if (unlikely(err)) +- goto out_rename; +- } +- +- /* update target timestamps */ +- AuDebugOn(au_dbstart(a->src_dentry) != a->btgt); +- a->h_path.dentry = au_h_dptr(a->src_dentry, a->btgt); +- vfsub_update_h_iattr(&a->h_path, /*did*/NULL); /*ignore*/ +- a->src_inode->i_ctime = a->h_path.dentry->d_inode->i_ctime; +- +- /* remove whiteout for dentry */ +- if (a->dst_wh_dentry) { +- a->h_path.dentry = a->dst_wh_dentry; +- err = au_wh_unlink_dentry(a->dst_h_dir, &a->h_path, +- a->dst_dentry); +- if (unlikely(err)) +- goto out_diropq; +- } +- +- /* remove whtmp */ +- if (a->thargs) +- au_ren_del_whtmp(a); /* ignore this error */ +- +- err = 0; +- goto out_success; +- +-out_diropq: +- if (au_ftest_ren(a->flags, DIROPQ)) +- au_ren_rev_diropq(err, a); +-out_rename: +- if (!au_ftest_ren(a->flags, CPUP)) +- au_ren_rev_rename(err, a); +- else +- au_ren_rev_cpup(err, a); +- dput(a->h_dst); +-out_whtmp: +- if (a->thargs) +- au_ren_rev_whtmp(err, a); +-out_whdst: +- dput(a->dst_wh_dentry); +- a->dst_wh_dentry = NULL; +-out_whsrc: +- if (a->src_wh_dentry) +- au_ren_rev_whsrc(err, a); +-out_success: +- dput(a->src_wh_dentry); +- dput(a->dst_wh_dentry); +-out_thargs: +- if (a->thargs) { +- dput(a->h_dst); +- au_whtmp_rmdir_free(a->thargs); +- a->thargs = NULL; +- } +-out: +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* +- * test if @dentry dir can be rename destination or not. +- * success means, it is a logically empty dir. +- */ +-static int may_rename_dstdir(struct dentry *dentry, struct au_nhash *whlist) +-{ +- return au_test_empty(dentry, whlist); +-} +- +-/* +- * test if @dentry dir can be rename source or not. +- * if it can, return 0 and @children is filled. +- * success means, +- * - it is a logically empty dir. +- * - or, it exists on writable branch and has no children including whiteouts +- * on the lower branch. +- */ +-static int may_rename_srcdir(struct dentry *dentry, aufs_bindex_t btgt) +-{ +- int err; +- unsigned int rdhash; +- aufs_bindex_t bstart; +- +- bstart = au_dbstart(dentry); +- if (bstart != btgt) { +- struct au_nhash whlist; +- +- SiMustAnyLock(dentry->d_sb); +- rdhash = au_sbi(dentry->d_sb)->si_rdhash; +- if (!rdhash) +- rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, +- dentry)); +- err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS); +- if (unlikely(err)) +- goto out; +- err = au_test_empty(dentry, &whlist); +- au_nhash_wh_free(&whlist); +- goto out; +- } +- +- if (bstart == au_dbtaildir(dentry)) +- return 0; /* success */ +- +- err = au_test_empty_lower(dentry); +- +-out: +- if (err == -ENOTEMPTY) { +- AuWarn1("renaming dir who has child(ren) on multiple branches," +- " is not supported\n"); +- err = -EXDEV; +- } +- return err; +-} +- +-/* side effect: sets whlist and h_dentry */ +-static int au_ren_may_dir(struct au_ren_args *a) +-{ +- int err; +- unsigned int rdhash; +- struct dentry *d; +- +- d = a->dst_dentry; +- SiMustAnyLock(d->d_sb); +- +- err = 0; +- if (au_ftest_ren(a->flags, ISDIR) && a->dst_inode) { +- rdhash = au_sbi(d->d_sb)->si_rdhash; +- if (!rdhash) +- rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, d)); +- err = au_nhash_alloc(&a->whlist, rdhash, GFP_NOFS); +- if (unlikely(err)) +- goto out; +- +- au_set_dbstart(d, a->dst_bstart); +- err = may_rename_dstdir(d, &a->whlist); +- au_set_dbstart(d, a->btgt); +- } +- a->dst_h_dentry = au_h_dptr(d, au_dbstart(d)); +- if (unlikely(err)) +- goto out; +- +- d = a->src_dentry; +- a->src_h_dentry = au_h_dptr(d, au_dbstart(d)); +- if (au_ftest_ren(a->flags, ISDIR)) { +- err = may_rename_srcdir(d, a->btgt); +- if (unlikely(err)) { +- au_nhash_wh_free(&a->whlist); +- a->whlist.nh_num = 0; +- } +- } +-out: +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* +- * simple tests for rename. +- * following the checks in vfs, plus the parent-child relationship. +- */ +-static int au_may_ren(struct au_ren_args *a) +-{ +- int err, isdir; +- struct inode *h_inode; +- +- if (a->src_bstart == a->btgt) { +- err = au_may_del(a->src_dentry, a->btgt, a->src_h_parent, +- au_ftest_ren(a->flags, ISDIR)); +- if (unlikely(err)) +- goto out; +- err = -EINVAL; +- if (unlikely(a->src_h_dentry == a->h_trap)) +- goto out; +- } +- +- err = 0; +- if (a->dst_bstart != a->btgt) +- goto out; +- +- err = -ENOTEMPTY; +- if (unlikely(a->dst_h_dentry == a->h_trap)) +- goto out; +- +- err = -EIO; +- h_inode = a->dst_h_dentry->d_inode; +- isdir = !!au_ftest_ren(a->flags, ISDIR); +- if (!a->dst_dentry->d_inode) { +- if (unlikely(h_inode)) +- goto out; +- err = au_may_add(a->dst_dentry, a->btgt, a->dst_h_parent, +- isdir); +- } else { +- if (unlikely(!h_inode || !h_inode->i_nlink)) +- goto out; +- err = au_may_del(a->dst_dentry, a->btgt, a->dst_h_parent, +- isdir); +- if (unlikely(err)) +- goto out; +- } +- +-out: +- if (unlikely(err == -ENOENT || err == -EEXIST)) +- err = -EIO; +- AuTraceErr(err); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* +- * locking order +- * (VFS) +- * - src_dir and dir by lock_rename() +- * - inode if exitsts +- * (aufs) +- * - lock all +- * + src_dentry and dentry by aufs_read_and_write_lock2() which calls, +- * + si_read_lock +- * + di_write_lock2_child() +- * + di_write_lock_child() +- * + ii_write_lock_child() +- * + di_write_lock_child2() +- * + ii_write_lock_child2() +- * + src_parent and parent +- * + di_write_lock_parent() +- * + ii_write_lock_parent() +- * + di_write_lock_parent2() +- * + ii_write_lock_parent2() +- * + lower src_dir and dir by vfsub_lock_rename() +- * + verify the every relationships between child and parent. if any +- * of them failed, unlock all and return -EBUSY. +- */ +-static void au_ren_unlock(struct au_ren_args *a) +-{ +- struct super_block *sb; +- +- sb = a->dst_dentry->d_sb; +- if (au_ftest_ren(a->flags, MNT_WRITE)) +- vfsub_mnt_drop_write(a->br->br_mnt); +- vfsub_unlock_rename(a->src_h_parent, a->src_hdir, +- a->dst_h_parent, a->dst_hdir); +-} +- +-static int au_ren_lock(struct au_ren_args *a) +-{ +- int err; +- unsigned int udba; +- +- err = 0; +- a->src_h_parent = au_h_dptr(a->src_parent, a->btgt); +- a->src_hdir = au_hi(a->src_dir, a->btgt); +- a->dst_h_parent = au_h_dptr(a->dst_parent, a->btgt); +- a->dst_hdir = au_hi(a->dst_dir, a->btgt); +- a->h_trap = vfsub_lock_rename(a->src_h_parent, a->src_hdir, +- a->dst_h_parent, a->dst_hdir); +- udba = au_opt_udba(a->src_dentry->d_sb); +- if (unlikely(a->src_hdir->hi_inode != a->src_h_parent->d_inode +- || a->dst_hdir->hi_inode != a->dst_h_parent->d_inode)) +- err = au_busy_or_stale(); +- if (!err && au_dbstart(a->src_dentry) == a->btgt) +- err = au_h_verify(a->src_h_dentry, udba, +- a->src_h_parent->d_inode, a->src_h_parent, +- a->br); +- if (!err && au_dbstart(a->dst_dentry) == a->btgt) +- err = au_h_verify(a->dst_h_dentry, udba, +- a->dst_h_parent->d_inode, a->dst_h_parent, +- a->br); +- if (!err) { +- err = vfsub_mnt_want_write(a->br->br_mnt); +- if (unlikely(err)) +- goto out_unlock; +- au_fset_ren(a->flags, MNT_WRITE); +- goto out; /* success */ +- } +- +- err = au_busy_or_stale(); +- +-out_unlock: +- au_ren_unlock(a); +-out: +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static void au_ren_refresh_dir(struct au_ren_args *a) +-{ +- struct inode *dir; +- +- dir = a->dst_dir; +- dir->i_version++; +- if (au_ftest_ren(a->flags, ISDIR)) { +- /* is this updating defined in POSIX? */ +- au_cpup_attr_timesizes(a->src_inode); +- au_cpup_attr_nlink(dir, /*force*/1); +- } +- +- if (au_ibstart(dir) == a->btgt) +- au_cpup_attr_timesizes(dir); +- +- if (au_ftest_ren(a->flags, ISSAMEDIR)) +- return; +- +- dir = a->src_dir; +- dir->i_version++; +- if (au_ftest_ren(a->flags, ISDIR)) +- au_cpup_attr_nlink(dir, /*force*/1); +- if (au_ibstart(dir) == a->btgt) +- au_cpup_attr_timesizes(dir); +-} +- +-static void au_ren_refresh(struct au_ren_args *a) +-{ +- aufs_bindex_t bend, bindex; +- struct dentry *d, *h_d; +- struct inode *i, *h_i; +- struct super_block *sb; +- +- d = a->dst_dentry; +- d_drop(d); +- if (a->h_dst) +- /* already dget-ed by au_ren_or_cpup() */ +- au_set_h_dptr(d, a->btgt, a->h_dst); +- +- i = a->dst_inode; +- if (i) { +- if (!au_ftest_ren(a->flags, ISDIR)) +- vfsub_drop_nlink(i); +- else { +- vfsub_dead_dir(i); +- au_cpup_attr_timesizes(i); +- } +- au_update_dbrange(d, /*do_put_zero*/1); +- } else { +- bend = a->btgt; +- for (bindex = au_dbstart(d); bindex < bend; bindex++) +- au_set_h_dptr(d, bindex, NULL); +- bend = au_dbend(d); +- for (bindex = a->btgt + 1; bindex <= bend; bindex++) +- au_set_h_dptr(d, bindex, NULL); +- au_update_dbrange(d, /*do_put_zero*/0); +- } +- +- d = a->src_dentry; +- au_set_dbwh(d, -1); +- bend = au_dbend(d); +- for (bindex = a->btgt + 1; bindex <= bend; bindex++) { +- h_d = au_h_dptr(d, bindex); +- if (h_d) +- au_set_h_dptr(d, bindex, NULL); +- } +- au_set_dbend(d, a->btgt); +- +- sb = d->d_sb; +- i = a->src_inode; +- if (au_opt_test(au_mntflags(sb), PLINK) && au_plink_test(i)) +- return; /* success */ +- +- bend = au_ibend(i); +- for (bindex = a->btgt + 1; bindex <= bend; bindex++) { +- h_i = au_h_iptr(i, bindex); +- if (h_i) { +- au_xino_write(sb, bindex, h_i->i_ino, /*ino*/0); +- /* ignore this error */ +- au_set_h_iptr(i, bindex, NULL, 0); +- } +- } +- au_set_ibend(i, a->btgt); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* mainly for link(2) and rename(2) */ +-int au_wbr(struct dentry *dentry, aufs_bindex_t btgt) +-{ +- aufs_bindex_t bdiropq, bwh; +- struct dentry *parent; +- struct au_branch *br; +- +- parent = dentry->d_parent; +- IMustLock(parent->d_inode); /* dir is locked */ +- +- bdiropq = au_dbdiropq(parent); +- bwh = au_dbwh(dentry); +- br = au_sbr(dentry->d_sb, btgt); +- if (au_br_rdonly(br) +- || (0 <= bdiropq && bdiropq < btgt) +- || (0 <= bwh && bwh < btgt)) +- btgt = -1; +- +- AuDbg("btgt %d\n", btgt); +- return btgt; +-} +- +-/* sets src_bstart, dst_bstart and btgt */ +-static int au_ren_wbr(struct au_ren_args *a) +-{ +- int err; +- struct au_wr_dir_args wr_dir_args = { +- /* .force_btgt = -1, */ +- .flags = AuWrDir_ADD_ENTRY +- }; +- +- a->src_bstart = au_dbstart(a->src_dentry); +- a->dst_bstart = au_dbstart(a->dst_dentry); +- if (au_ftest_ren(a->flags, ISDIR)) +- au_fset_wrdir(wr_dir_args.flags, ISDIR); +- wr_dir_args.force_btgt = a->src_bstart; +- if (a->dst_inode && a->dst_bstart < a->src_bstart) +- wr_dir_args.force_btgt = a->dst_bstart; +- wr_dir_args.force_btgt = au_wbr(a->dst_dentry, wr_dir_args.force_btgt); +- err = au_wr_dir(a->dst_dentry, a->src_dentry, &wr_dir_args); +- a->btgt = err; +- +- return err; +-} +- +-static void au_ren_dt(struct au_ren_args *a) +-{ +- a->h_path.dentry = a->src_h_parent; +- au_dtime_store(a->src_dt + AuPARENT, a->src_parent, &a->h_path); +- if (!au_ftest_ren(a->flags, ISSAMEDIR)) { +- a->h_path.dentry = a->dst_h_parent; +- au_dtime_store(a->dst_dt + AuPARENT, a->dst_parent, &a->h_path); +- } +- +- au_fclr_ren(a->flags, DT_DSTDIR); +- if (!au_ftest_ren(a->flags, ISDIR)) +- return; +- +- a->h_path.dentry = a->src_h_dentry; +- au_dtime_store(a->src_dt + AuCHILD, a->src_dentry, &a->h_path); +- if (a->dst_h_dentry->d_inode) { +- au_fset_ren(a->flags, DT_DSTDIR); +- a->h_path.dentry = a->dst_h_dentry; +- au_dtime_store(a->dst_dt + AuCHILD, a->dst_dentry, &a->h_path); +- } +-} +- +-static void au_ren_rev_dt(int err, struct au_ren_args *a) +-{ +- struct dentry *h_d; +- struct mutex *h_mtx; +- +- au_dtime_revert(a->src_dt + AuPARENT); +- if (!au_ftest_ren(a->flags, ISSAMEDIR)) +- au_dtime_revert(a->dst_dt + AuPARENT); +- +- if (au_ftest_ren(a->flags, ISDIR) && err != -EIO) { +- h_d = a->src_dt[AuCHILD].dt_h_path.dentry; +- h_mtx = &h_d->d_inode->i_mutex; +- mutex_lock_nested(h_mtx, AuLsc_I_CHILD); +- au_dtime_revert(a->src_dt + AuCHILD); +- mutex_unlock(h_mtx); +- +- if (au_ftest_ren(a->flags, DT_DSTDIR)) { +- h_d = a->dst_dt[AuCHILD].dt_h_path.dentry; +- h_mtx = &h_d->d_inode->i_mutex; +- mutex_lock_nested(h_mtx, AuLsc_I_CHILD); +- au_dtime_revert(a->dst_dt + AuCHILD); +- mutex_unlock(h_mtx); +- } +- } +-} +- +-/* ---------------------------------------------------------------------- */ +- +-int aufs_rename(struct inode *_src_dir, struct dentry *_src_dentry, +- struct inode *_dst_dir, struct dentry *_dst_dentry) +-{ +- int err, flags; +- /* reduce stack space */ +- struct au_ren_args *a; +- +- AuDbg("%.*s, %.*s\n", AuDLNPair(_src_dentry), AuDLNPair(_dst_dentry)); +- IMustLock(_src_dir); +- IMustLock(_dst_dir); +- +- err = -ENOMEM; +- BUILD_BUG_ON(sizeof(*a) > PAGE_SIZE); +- a = kzalloc(sizeof(*a), GFP_NOFS); +- if (unlikely(!a)) +- goto out; +- +- a->src_dir = _src_dir; +- a->src_dentry = _src_dentry; +- a->src_inode = a->src_dentry->d_inode; +- a->src_parent = a->src_dentry->d_parent; /* dir inode is locked */ +- a->dst_dir = _dst_dir; +- a->dst_dentry = _dst_dentry; +- a->dst_inode = a->dst_dentry->d_inode; +- a->dst_parent = a->dst_dentry->d_parent; /* dir inode is locked */ +- if (a->dst_inode) { +- IMustLock(a->dst_inode); +- au_igrab(a->dst_inode); +- } +- +- err = -ENOTDIR; +- flags = AuLock_FLUSH | AuLock_NOPLM | AuLock_GEN; +- if (S_ISDIR(a->src_inode->i_mode)) { +- au_fset_ren(a->flags, ISDIR); +- if (unlikely(a->dst_inode && !S_ISDIR(a->dst_inode->i_mode))) +- goto out_free; +- err = aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry, +- AuLock_DIR | flags); +- } else +- err = aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry, +- flags); +- if (unlikely(err)) +- goto out_free; +- +- err = au_d_hashed_positive(a->src_dentry); +- if (unlikely(err)) +- goto out_unlock; +- err = -ENOENT; +- if (a->dst_inode) { +- /* +- * If it is a dir, VFS unhash dst_dentry before this +- * function. It means we cannot rely upon d_unhashed(). +- */ +- if (unlikely(!a->dst_inode->i_nlink)) +- goto out_unlock; +- if (!S_ISDIR(a->dst_inode->i_mode)) { +- err = au_d_hashed_positive(a->dst_dentry); +- if (unlikely(err)) +- goto out_unlock; +- } else if (unlikely(IS_DEADDIR(a->dst_inode))) +- goto out_unlock; +- } else if (unlikely(d_unhashed(a->dst_dentry))) +- goto out_unlock; +- +- /* +- * is it possible? +- * yes, it happend (in linux-3.3-rcN) but I don't know why. +- * there may exist a problem somewhere else. +- */ +- err = -EINVAL; +- if (unlikely(a->dst_parent->d_inode == a->src_dentry->d_inode)) +- goto out_unlock; +- +- au_fset_ren(a->flags, ISSAMEDIR); /* temporary */ +- di_write_lock_parent(a->dst_parent); +- +- /* which branch we process */ +- err = au_ren_wbr(a); +- if (unlikely(err < 0)) +- goto out_parent; +- a->br = au_sbr(a->dst_dentry->d_sb, a->btgt); +- a->h_path.mnt = a->br->br_mnt; +- +- /* are they available to be renamed */ +- err = au_ren_may_dir(a); +- if (unlikely(err)) +- goto out_children; +- +- /* prepare the writable parent dir on the same branch */ +- if (a->dst_bstart == a->btgt) { +- au_fset_ren(a->flags, WHDST); +- } else { +- err = au_cpup_dirs(a->dst_dentry, a->btgt); +- if (unlikely(err)) +- goto out_children; +- } +- +- if (a->src_dir != a->dst_dir) { +- /* +- * this temporary unlock is safe, +- * because both dir->i_mutex are locked. +- */ +- di_write_unlock(a->dst_parent); +- di_write_lock_parent(a->src_parent); +- err = au_wr_dir_need_wh(a->src_dentry, +- au_ftest_ren(a->flags, ISDIR), +- &a->btgt); +- di_write_unlock(a->src_parent); +- di_write_lock2_parent(a->src_parent, a->dst_parent, /*isdir*/1); +- au_fclr_ren(a->flags, ISSAMEDIR); +- } else +- err = au_wr_dir_need_wh(a->src_dentry, +- au_ftest_ren(a->flags, ISDIR), +- &a->btgt); +- if (unlikely(err < 0)) +- goto out_children; +- if (err) +- au_fset_ren(a->flags, WHSRC); +- +- /* lock them all */ +- err = au_ren_lock(a); +- if (unlikely(err)) +- goto out_children; +- +- if (!au_opt_test(au_mntflags(a->dst_dir->i_sb), UDBA_NONE)) +- err = au_may_ren(a); +- else if (unlikely(a->dst_dentry->d_name.len > AUFS_MAX_NAMELEN)) +- err = -ENAMETOOLONG; +- if (unlikely(err)) +- goto out_hdir; +- +- /* store timestamps to be revertible */ +- au_ren_dt(a); +- +- /* here we go */ +- err = do_rename(a); +- if (unlikely(err)) +- goto out_dt; +- +- /* update dir attributes */ +- au_ren_refresh_dir(a); +- +- /* dput/iput all lower dentries */ +- au_ren_refresh(a); +- +- goto out_hdir; /* success */ +- +-out_dt: +- au_ren_rev_dt(err, a); +-out_hdir: +- au_ren_unlock(a); +-out_children: +- au_nhash_wh_free(&a->whlist); +- if (err && a->dst_inode && a->dst_bstart != a->btgt) { +- AuDbg("bstart %d, btgt %d\n", a->dst_bstart, a->btgt); +- au_set_h_dptr(a->dst_dentry, a->btgt, NULL); +- au_set_dbstart(a->dst_dentry, a->dst_bstart); +- } +-out_parent: +- if (!err) +- d_move(a->src_dentry, a->dst_dentry); +- else { +- au_update_dbstart(a->dst_dentry); +- if (!a->dst_inode) +- d_drop(a->dst_dentry); +- } +- if (au_ftest_ren(a->flags, ISSAMEDIR)) +- di_write_unlock(a->dst_parent); +- else +- di_write_unlock2(a->src_parent, a->dst_parent); +-out_unlock: +- aufs_read_and_write_unlock2(a->dst_dentry, a->src_dentry); +-out_free: +- iput(a->dst_inode); +- if (a->thargs) +- au_whtmp_rmdir_free(a->thargs); +- kfree(a); +-out: +- AuTraceErr(err); +- return err; +-} +diff --git a/fs/aufs/iinfo.c b/fs/aufs/iinfo.c +deleted file mode 100644 +index b82ebbf..0000000 +--- a/fs/aufs/iinfo.c ++++ /dev/null +@@ -1,276 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * inode private data +- */ +- +-#include "aufs.h" +- +-struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex) +-{ +- struct inode *h_inode; +- +- IiMustAnyLock(inode); +- +- h_inode = au_ii(inode)->ii_hinode[0 + bindex].hi_inode; +- AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0); +- return h_inode; +-} +- +-/* todo: hard/soft set? */ +-void au_hiput(struct au_hinode *hinode) +-{ +- au_hn_free(hinode); +- dput(hinode->hi_whdentry); +- iput(hinode->hi_inode); +-} +- +-unsigned int au_hi_flags(struct inode *inode, int isdir) +-{ +- unsigned int flags; +- const unsigned int mnt_flags = au_mntflags(inode->i_sb); +- +- flags = 0; +- if (au_opt_test(mnt_flags, XINO)) +- au_fset_hi(flags, XINO); +- if (isdir && au_opt_test(mnt_flags, UDBA_HNOTIFY)) +- au_fset_hi(flags, HNOTIFY); +- return flags; +-} +- +-void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex, +- struct inode *h_inode, unsigned int flags) +-{ +- struct au_hinode *hinode; +- struct inode *hi; +- struct au_iinfo *iinfo = au_ii(inode); +- +- IiMustWriteLock(inode); +- +- hinode = iinfo->ii_hinode + bindex; +- hi = hinode->hi_inode; +- AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0); +- +- if (hi) +- au_hiput(hinode); +- hinode->hi_inode = h_inode; +- if (h_inode) { +- int err; +- struct super_block *sb = inode->i_sb; +- struct au_branch *br; +- +- AuDebugOn(inode->i_mode +- && (h_inode->i_mode & S_IFMT) +- != (inode->i_mode & S_IFMT)); +- if (bindex == iinfo->ii_bstart) +- au_cpup_igen(inode, h_inode); +- br = au_sbr(sb, bindex); +- hinode->hi_id = br->br_id; +- if (au_ftest_hi(flags, XINO)) { +- err = au_xino_write(sb, bindex, h_inode->i_ino, +- inode->i_ino); +- if (unlikely(err)) +- AuIOErr1("failed au_xino_write() %d\n", err); +- } +- +- if (au_ftest_hi(flags, HNOTIFY) +- && au_br_hnotifyable(br->br_perm)) { +- err = au_hn_alloc(hinode, inode); +- if (unlikely(err)) +- AuIOErr1("au_hn_alloc() %d\n", err); +- } +- } +-} +- +-void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex, +- struct dentry *h_wh) +-{ +- struct au_hinode *hinode; +- +- IiMustWriteLock(inode); +- +- hinode = au_ii(inode)->ii_hinode + bindex; +- AuDebugOn(hinode->hi_whdentry); +- hinode->hi_whdentry = h_wh; +-} +- +-void au_update_iigen(struct inode *inode, int half) +-{ +- struct au_iinfo *iinfo; +- struct au_iigen *iigen; +- unsigned int sigen; +- +- sigen = au_sigen(inode->i_sb); +- iinfo = au_ii(inode); +- iigen = &iinfo->ii_generation; +- spin_lock(&iinfo->ii_genspin); +- iigen->ig_generation = sigen; +- if (half) +- au_ig_fset(iigen->ig_flags, HALF_REFRESHED); +- else +- au_ig_fclr(iigen->ig_flags, HALF_REFRESHED); +- spin_unlock(&iinfo->ii_genspin); +-} +- +-/* it may be called at remount time, too */ +-void au_update_ibrange(struct inode *inode, int do_put_zero) +-{ +- struct au_iinfo *iinfo; +- aufs_bindex_t bindex, bend; +- +- iinfo = au_ii(inode); +- if (!iinfo) +- return; +- +- IiMustWriteLock(inode); +- +- if (do_put_zero && iinfo->ii_bstart >= 0) { +- for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; +- bindex++) { +- struct inode *h_i; +- +- h_i = iinfo->ii_hinode[0 + bindex].hi_inode; +- if (h_i && !h_i->i_nlink) +- au_set_h_iptr(inode, bindex, NULL, 0); +- } +- } +- +- iinfo->ii_bstart = -1; +- iinfo->ii_bend = -1; +- bend = au_sbend(inode->i_sb); +- for (bindex = 0; bindex <= bend; bindex++) +- if (iinfo->ii_hinode[0 + bindex].hi_inode) { +- iinfo->ii_bstart = bindex; +- break; +- } +- if (iinfo->ii_bstart >= 0) +- for (bindex = bend; bindex >= iinfo->ii_bstart; bindex--) +- if (iinfo->ii_hinode[0 + bindex].hi_inode) { +- iinfo->ii_bend = bindex; +- break; +- } +- AuDebugOn(iinfo->ii_bstart > iinfo->ii_bend); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-void au_icntnr_init_once(void *_c) +-{ +- struct au_icntnr *c = _c; +- struct au_iinfo *iinfo = &c->iinfo; +- static struct lock_class_key aufs_ii; +- +- spin_lock_init(&iinfo->ii_genspin); +- au_rw_init(&iinfo->ii_rwsem); +- au_rw_class(&iinfo->ii_rwsem, &aufs_ii); +- inode_init_once(&c->vfs_inode); +-} +- +-int au_iinfo_init(struct inode *inode) +-{ +- struct au_iinfo *iinfo; +- struct super_block *sb; +- int nbr, i; +- +- sb = inode->i_sb; +- iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); +- nbr = au_sbend(sb) + 1; +- if (unlikely(nbr <= 0)) +- nbr = 1; +- iinfo->ii_hinode = kcalloc(nbr, sizeof(*iinfo->ii_hinode), GFP_NOFS); +- if (iinfo->ii_hinode) { +- au_ninodes_inc(sb); +- for (i = 0; i < nbr; i++) +- iinfo->ii_hinode[i].hi_id = -1; +- +- iinfo->ii_generation.ig_generation = au_sigen(sb); +- iinfo->ii_bstart = -1; +- iinfo->ii_bend = -1; +- iinfo->ii_vdir = NULL; +- return 0; +- } +- return -ENOMEM; +-} +- +-int au_ii_realloc(struct au_iinfo *iinfo, int nbr) +-{ +- int err, sz; +- struct au_hinode *hip; +- +- AuRwMustWriteLock(&iinfo->ii_rwsem); +- +- err = -ENOMEM; +- sz = sizeof(*hip) * (iinfo->ii_bend + 1); +- if (!sz) +- sz = sizeof(*hip); +- hip = au_kzrealloc(iinfo->ii_hinode, sz, sizeof(*hip) * nbr, GFP_NOFS); +- if (hip) { +- iinfo->ii_hinode = hip; +- err = 0; +- } +- +- return err; +-} +- +-void au_iinfo_fin(struct inode *inode) +-{ +- struct au_iinfo *iinfo; +- struct au_hinode *hi; +- struct super_block *sb; +- aufs_bindex_t bindex, bend; +- const unsigned char unlinked = !inode->i_nlink; +- +- iinfo = au_ii(inode); +- /* bad_inode case */ +- if (!iinfo) +- return; +- +- sb = inode->i_sb; +- au_ninodes_dec(sb); +- if (si_pid_test(sb)) +- au_xino_delete_inode(inode, unlinked); +- else { +- /* +- * it is safe to hide the dependency between sbinfo and +- * sb->s_umount. +- */ +- lockdep_off(); +- si_noflush_read_lock(sb); +- au_xino_delete_inode(inode, unlinked); +- si_read_unlock(sb); +- lockdep_on(); +- } +- +- if (iinfo->ii_vdir) +- au_vdir_free(iinfo->ii_vdir); +- +- bindex = iinfo->ii_bstart; +- if (bindex >= 0) { +- hi = iinfo->ii_hinode + bindex; +- bend = iinfo->ii_bend; +- while (bindex++ <= bend) { +- if (hi->hi_inode) +- au_hiput(hi); +- hi++; +- } +- } +- kfree(iinfo->ii_hinode); +- iinfo->ii_hinode = NULL; +- AuRwDestroy(&iinfo->ii_rwsem); +-} +diff --git a/fs/aufs/inode.c b/fs/aufs/inode.c +deleted file mode 100644 +index 9c86d98..0000000 +--- a/fs/aufs/inode.c ++++ /dev/null +@@ -1,492 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * inode functions +- */ +- +-#include "aufs.h" +- +-struct inode *au_igrab(struct inode *inode) +-{ +- if (inode) { +- AuDebugOn(!atomic_read(&inode->i_count)); +- ihold(inode); +- } +- return inode; +-} +- +-static void au_refresh_hinode_attr(struct inode *inode, int do_version) +-{ +- au_cpup_attr_all(inode, /*force*/0); +- au_update_iigen(inode, /*half*/1); +- if (do_version) +- inode->i_version++; +-} +- +-static int au_ii_refresh(struct inode *inode, int *update) +-{ +- int err, e; +- umode_t type; +- aufs_bindex_t bindex, new_bindex; +- struct super_block *sb; +- struct au_iinfo *iinfo; +- struct au_hinode *p, *q, tmp; +- +- IiMustWriteLock(inode); +- +- *update = 0; +- sb = inode->i_sb; +- type = inode->i_mode & S_IFMT; +- iinfo = au_ii(inode); +- err = au_ii_realloc(iinfo, au_sbend(sb) + 1); +- if (unlikely(err)) +- goto out; +- +- AuDebugOn(iinfo->ii_bstart < 0); +- p = iinfo->ii_hinode + iinfo->ii_bstart; +- for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; +- bindex++, p++) { +- if (!p->hi_inode) +- continue; +- +- AuDebugOn(type != (p->hi_inode->i_mode & S_IFMT)); +- new_bindex = au_br_index(sb, p->hi_id); +- if (new_bindex == bindex) +- continue; +- +- if (new_bindex < 0) { +- *update = 1; +- au_hiput(p); +- p->hi_inode = NULL; +- continue; +- } +- +- if (new_bindex < iinfo->ii_bstart) +- iinfo->ii_bstart = new_bindex; +- if (iinfo->ii_bend < new_bindex) +- iinfo->ii_bend = new_bindex; +- /* swap two lower inode, and loop again */ +- q = iinfo->ii_hinode + new_bindex; +- tmp = *q; +- *q = *p; +- *p = tmp; +- if (tmp.hi_inode) { +- bindex--; +- p--; +- } +- } +- au_update_ibrange(inode, /*do_put_zero*/0); +- e = au_dy_irefresh(inode); +- if (unlikely(e && !err)) +- err = e; +- +-out: +- AuTraceErr(err); +- return err; +-} +- +-int au_refresh_hinode_self(struct inode *inode) +-{ +- int err, update; +- +- err = au_ii_refresh(inode, &update); +- if (!err) +- au_refresh_hinode_attr(inode, update && S_ISDIR(inode->i_mode)); +- +- AuTraceErr(err); +- return err; +-} +- +-int au_refresh_hinode(struct inode *inode, struct dentry *dentry) +-{ +- int err, e, update; +- unsigned int flags; +- umode_t mode; +- aufs_bindex_t bindex, bend; +- unsigned char isdir; +- struct au_hinode *p; +- struct au_iinfo *iinfo; +- +- err = au_ii_refresh(inode, &update); +- if (unlikely(err)) +- goto out; +- +- update = 0; +- iinfo = au_ii(inode); +- p = iinfo->ii_hinode + iinfo->ii_bstart; +- mode = (inode->i_mode & S_IFMT); +- isdir = S_ISDIR(mode); +- flags = au_hi_flags(inode, isdir); +- bend = au_dbend(dentry); +- for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) { +- struct inode *h_i; +- struct dentry *h_d; +- +- h_d = au_h_dptr(dentry, bindex); +- if (!h_d || !h_d->d_inode) +- continue; +- +- AuDebugOn(mode != (h_d->d_inode->i_mode & S_IFMT)); +- if (iinfo->ii_bstart <= bindex && bindex <= iinfo->ii_bend) { +- h_i = au_h_iptr(inode, bindex); +- if (h_i) { +- if (h_i == h_d->d_inode) +- continue; +- err = -EIO; +- break; +- } +- } +- if (bindex < iinfo->ii_bstart) +- iinfo->ii_bstart = bindex; +- if (iinfo->ii_bend < bindex) +- iinfo->ii_bend = bindex; +- au_set_h_iptr(inode, bindex, au_igrab(h_d->d_inode), flags); +- update = 1; +- } +- au_update_ibrange(inode, /*do_put_zero*/0); +- e = au_dy_irefresh(inode); +- if (unlikely(e && !err)) +- err = e; +- if (!err) +- au_refresh_hinode_attr(inode, update && isdir); +- +-out: +- AuTraceErr(err); +- return err; +-} +- +-static int set_inode(struct inode *inode, struct dentry *dentry) +-{ +- int err; +- unsigned int flags; +- umode_t mode; +- aufs_bindex_t bindex, bstart, btail; +- unsigned char isdir; +- struct dentry *h_dentry; +- struct inode *h_inode; +- struct au_iinfo *iinfo; +- +- IiMustWriteLock(inode); +- +- err = 0; +- isdir = 0; +- bstart = au_dbstart(dentry); +- h_inode = au_h_dptr(dentry, bstart)->d_inode; +- mode = h_inode->i_mode; +- switch (mode & S_IFMT) { +- case S_IFREG: +- btail = au_dbtail(dentry); +- inode->i_op = &aufs_iop; +- inode->i_fop = &aufs_file_fop; +- err = au_dy_iaop(inode, bstart, h_inode); +- if (unlikely(err)) +- goto out; +- break; +- case S_IFDIR: +- isdir = 1; +- btail = au_dbtaildir(dentry); +- inode->i_op = &aufs_dir_iop; +- inode->i_fop = &aufs_dir_fop; +- break; +- case S_IFLNK: +- btail = au_dbtail(dentry); +- inode->i_op = &aufs_symlink_iop; +- break; +- case S_IFBLK: +- case S_IFCHR: +- case S_IFIFO: +- case S_IFSOCK: +- btail = au_dbtail(dentry); +- inode->i_op = &aufs_iop; +- au_init_special_fop(inode, mode, h_inode->i_rdev); +- break; +- default: +- AuIOErr("Unknown file type 0%o\n", mode); +- err = -EIO; +- goto out; +- } +- +- /* do not set hnotify for whiteouted dirs (SHWH mode) */ +- flags = au_hi_flags(inode, isdir); +- if (au_opt_test(au_mntflags(dentry->d_sb), SHWH) +- && au_ftest_hi(flags, HNOTIFY) +- && dentry->d_name.len > AUFS_WH_PFX_LEN +- && !memcmp(dentry->d_name.name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) +- au_fclr_hi(flags, HNOTIFY); +- iinfo = au_ii(inode); +- iinfo->ii_bstart = bstart; +- iinfo->ii_bend = btail; +- for (bindex = bstart; bindex <= btail; bindex++) { +- h_dentry = au_h_dptr(dentry, bindex); +- if (h_dentry) +- au_set_h_iptr(inode, bindex, +- au_igrab(h_dentry->d_inode), flags); +- } +- au_cpup_attr_all(inode, /*force*/1); +- +-out: +- return err; +-} +- +-/* +- * successful returns with iinfo write_locked +- * minus: errno +- * zero: success, matched +- * plus: no error, but unmatched +- */ +-static int reval_inode(struct inode *inode, struct dentry *dentry) +-{ +- int err; +- unsigned int gen; +- struct au_iigen iigen; +- aufs_bindex_t bindex, bend; +- struct inode *h_inode, *h_dinode; +- +- /* +- * before this function, if aufs got any iinfo lock, it must be only +- * one, the parent dir. +- * it can happen by UDBA and the obsoleted inode number. +- */ +- err = -EIO; +- if (unlikely(inode->i_ino == parent_ino(dentry))) +- goto out; +- +- err = 1; +- ii_write_lock_new_child(inode); +- h_dinode = au_h_dptr(dentry, au_dbstart(dentry))->d_inode; +- bend = au_ibend(inode); +- for (bindex = au_ibstart(inode); bindex <= bend; bindex++) { +- h_inode = au_h_iptr(inode, bindex); +- if (!h_inode || h_inode != h_dinode) +- continue; +- +- err = 0; +- gen = au_iigen(inode, &iigen); +- if (gen == au_digen(dentry) +- && !au_ig_ftest(iigen.ig_flags, HALF_REFRESHED)) +- break; +- +- /* fully refresh inode using dentry */ +- err = au_refresh_hinode(inode, dentry); +- if (!err) +- au_update_iigen(inode, /*half*/0); +- break; +- } +- +- if (unlikely(err)) +- ii_write_unlock(inode); +-out: +- return err; +-} +- +-int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, +- unsigned int d_type, ino_t *ino) +-{ +- int err; +- struct mutex *mtx; +- +- /* prevent hardlinked inode number from race condition */ +- mtx = NULL; +- if (d_type != DT_DIR) { +- mtx = &au_sbr(sb, bindex)->br_xino.xi_nondir_mtx; +- mutex_lock(mtx); +- } +- err = au_xino_read(sb, bindex, h_ino, ino); +- if (unlikely(err)) +- goto out; +- +- if (!*ino) { +- err = -EIO; +- *ino = au_xino_new_ino(sb); +- if (unlikely(!*ino)) +- goto out; +- err = au_xino_write(sb, bindex, h_ino, *ino); +- if (unlikely(err)) +- goto out; +- } +- +-out: +- if (mtx) +- mutex_unlock(mtx); +- return err; +-} +- +-/* successful returns with iinfo write_locked */ +-/* todo: return with unlocked? */ +-struct inode *au_new_inode(struct dentry *dentry, int must_new) +-{ +- struct inode *inode, *h_inode; +- struct dentry *h_dentry; +- struct super_block *sb; +- struct mutex *mtx; +- ino_t h_ino, ino; +- int err; +- aufs_bindex_t bstart; +- +- sb = dentry->d_sb; +- bstart = au_dbstart(dentry); +- h_dentry = au_h_dptr(dentry, bstart); +- h_inode = h_dentry->d_inode; +- h_ino = h_inode->i_ino; +- +- /* +- * stop 'race'-ing between hardlinks under different +- * parents. +- */ +- mtx = NULL; +- if (!S_ISDIR(h_inode->i_mode)) +- mtx = &au_sbr(sb, bstart)->br_xino.xi_nondir_mtx; +- +-new_ino: +- if (mtx) +- mutex_lock(mtx); +- err = au_xino_read(sb, bstart, h_ino, &ino); +- inode = ERR_PTR(err); +- if (unlikely(err)) +- goto out; +- +- if (!ino) { +- ino = au_xino_new_ino(sb); +- if (unlikely(!ino)) { +- inode = ERR_PTR(-EIO); +- goto out; +- } +- } +- +- AuDbg("i%lu\n", (unsigned long)ino); +- inode = au_iget_locked(sb, ino); +- err = PTR_ERR(inode); +- if (IS_ERR(inode)) +- goto out; +- +- AuDbg("%lx, new %d\n", inode->i_state, !!(inode->i_state & I_NEW)); +- if (inode->i_state & I_NEW) { +- /* verbose coding for lock class name */ +- if (unlikely(S_ISLNK(h_inode->i_mode))) +- au_rw_class(&au_ii(inode)->ii_rwsem, +- au_lc_key + AuLcSymlink_IIINFO); +- else if (unlikely(S_ISDIR(h_inode->i_mode))) +- au_rw_class(&au_ii(inode)->ii_rwsem, +- au_lc_key + AuLcDir_IIINFO); +- else /* likely */ +- au_rw_class(&au_ii(inode)->ii_rwsem, +- au_lc_key + AuLcNonDir_IIINFO); +- +- ii_write_lock_new_child(inode); +- err = set_inode(inode, dentry); +- if (!err) { +- unlock_new_inode(inode); +- goto out; /* success */ +- } +- +- /* +- * iget_failed() calls iput(), but we need to call +- * ii_write_unlock() after iget_failed(). so dirty hack for +- * i_count. +- */ +- atomic_inc(&inode->i_count); +- iget_failed(inode); +- ii_write_unlock(inode); +- au_xino_write(sb, bstart, h_ino, /*ino*/0); +- /* ignore this error */ +- goto out_iput; +- } else if (!must_new && !IS_DEADDIR(inode) && inode->i_nlink) { +- /* +- * horrible race condition between lookup, readdir and copyup +- * (or something). +- */ +- if (mtx) +- mutex_unlock(mtx); +- err = reval_inode(inode, dentry); +- if (unlikely(err < 0)) { +- mtx = NULL; +- goto out_iput; +- } +- +- if (!err) { +- mtx = NULL; +- goto out; /* success */ +- } else if (mtx) +- mutex_lock(mtx); +- } +- +- if (unlikely(au_test_fs_unique_ino(h_dentry->d_inode))) +- AuWarn1("Warning: Un-notified UDBA or repeatedly renamed dir," +- " b%d, %s, %.*s, hi%lu, i%lu.\n", +- bstart, au_sbtype(h_dentry->d_sb), AuDLNPair(dentry), +- (unsigned long)h_ino, (unsigned long)ino); +- ino = 0; +- err = au_xino_write(sb, bstart, h_ino, /*ino*/0); +- if (!err) { +- iput(inode); +- if (mtx) +- mutex_unlock(mtx); +- goto new_ino; +- } +- +-out_iput: +- iput(inode); +- inode = ERR_PTR(err); +-out: +- if (mtx) +- mutex_unlock(mtx); +- return inode; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-int au_test_ro(struct super_block *sb, aufs_bindex_t bindex, +- struct inode *inode) +-{ +- int err; +- +- err = au_br_rdonly(au_sbr(sb, bindex)); +- +- /* pseudo-link after flushed may happen out of bounds */ +- if (!err +- && inode +- && au_ibstart(inode) <= bindex +- && bindex <= au_ibend(inode)) { +- /* +- * permission check is unnecessary since vfsub routine +- * will be called later +- */ +- struct inode *hi = au_h_iptr(inode, bindex); +- if (hi) +- err = IS_IMMUTABLE(hi) ? -EROFS : 0; +- } +- +- return err; +-} +- +-int au_test_h_perm(struct inode *h_inode, int mask) +-{ +- if (uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) +- return 0; +- return inode_permission(h_inode, mask); +-} +- +-int au_test_h_perm_sio(struct inode *h_inode, int mask) +-{ +- if (au_test_nfs(h_inode->i_sb) +- && (mask & MAY_WRITE) +- && S_ISDIR(h_inode->i_mode)) +- mask |= MAY_READ; /* force permission check */ +- return au_test_h_perm(h_inode, mask); +-} +diff --git a/fs/aufs/inode.h b/fs/aufs/inode.h +deleted file mode 100644 +index 29ac879..0000000 +--- a/fs/aufs/inode.h ++++ /dev/null +@@ -1,588 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * inode operations +- */ +- +-#ifndef __AUFS_INODE_H__ +-#define __AUFS_INODE_H__ +- +-#ifdef __KERNEL__ +- +-#include +-#include "rwsem.h" +- +-struct vfsmount; +- +-struct au_hnotify { +-#ifdef CONFIG_AUFS_HNOTIFY +-#ifdef CONFIG_AUFS_HFSNOTIFY +- /* never use fsnotify_add_vfsmount_mark() */ +- struct fsnotify_mark hn_mark; +-#endif +- struct inode *hn_aufs_inode; /* no get/put */ +-#endif +-} ____cacheline_aligned_in_smp; +- +-struct au_hinode { +- struct inode *hi_inode; +- aufs_bindex_t hi_id; +-#ifdef CONFIG_AUFS_HNOTIFY +- struct au_hnotify *hi_notify; +-#endif +- +- /* reference to the copied-up whiteout with get/put */ +- struct dentry *hi_whdentry; +-}; +- +-/* ig_flags */ +-#define AuIG_HALF_REFRESHED 1 +-#define au_ig_ftest(flags, name) ((flags) & AuIG_##name) +-#define au_ig_fset(flags, name) \ +- do { (flags) |= AuIG_##name; } while (0) +-#define au_ig_fclr(flags, name) \ +- do { (flags) &= ~AuIG_##name; } while (0) +- +-struct au_iigen { +- __u32 ig_generation, ig_flags; +-}; +- +-struct au_vdir; +-struct au_iinfo { +- spinlock_t ii_genspin; +- struct au_iigen ii_generation; +- struct super_block *ii_hsb1; /* no get/put */ +- +- struct au_rwsem ii_rwsem; +- aufs_bindex_t ii_bstart, ii_bend; +- __u32 ii_higen; +- struct au_hinode *ii_hinode; +- struct au_vdir *ii_vdir; +-}; +- +-struct au_icntnr { +- struct au_iinfo iinfo; +- struct inode vfs_inode; +-} ____cacheline_aligned_in_smp; +- +-/* au_pin flags */ +-#define AuPin_DI_LOCKED 1 +-#define AuPin_MNT_WRITE (1 << 1) +-#define au_ftest_pin(flags, name) ((flags) & AuPin_##name) +-#define au_fset_pin(flags, name) \ +- do { (flags) |= AuPin_##name; } while (0) +-#define au_fclr_pin(flags, name) \ +- do { (flags) &= ~AuPin_##name; } while (0) +- +-struct au_pin { +- /* input */ +- struct dentry *dentry; +- unsigned int udba; +- unsigned char lsc_di, lsc_hi, flags; +- aufs_bindex_t bindex; +- +- /* output */ +- struct dentry *parent; +- struct au_hinode *hdir; +- struct vfsmount *h_mnt; +-}; +- +-/* ---------------------------------------------------------------------- */ +- +-static inline struct au_iinfo *au_ii(struct inode *inode) +-{ +- struct au_iinfo *iinfo; +- +- iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); +- if (iinfo->ii_hinode) +- return iinfo; +- return NULL; /* debugging bad_inode case */ +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* inode.c */ +-struct inode *au_igrab(struct inode *inode); +-int au_refresh_hinode_self(struct inode *inode); +-int au_refresh_hinode(struct inode *inode, struct dentry *dentry); +-int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, +- unsigned int d_type, ino_t *ino); +-struct inode *au_new_inode(struct dentry *dentry, int must_new); +-int au_test_ro(struct super_block *sb, aufs_bindex_t bindex, +- struct inode *inode); +-int au_test_h_perm(struct inode *h_inode, int mask); +-int au_test_h_perm_sio(struct inode *h_inode, int mask); +- +-static inline int au_wh_ino(struct super_block *sb, aufs_bindex_t bindex, +- ino_t h_ino, unsigned int d_type, ino_t *ino) +-{ +-#ifdef CONFIG_AUFS_SHWH +- return au_ino(sb, bindex, h_ino, d_type, ino); +-#else +- return 0; +-#endif +-} +- +-/* i_op.c */ +-extern struct inode_operations aufs_iop, aufs_symlink_iop, aufs_dir_iop; +- +-/* au_wr_dir flags */ +-#define AuWrDir_ADD_ENTRY 1 +-#define AuWrDir_ISDIR (1 << 1) +-#define au_ftest_wrdir(flags, name) ((flags) & AuWrDir_##name) +-#define au_fset_wrdir(flags, name) \ +- do { (flags) |= AuWrDir_##name; } while (0) +-#define au_fclr_wrdir(flags, name) \ +- do { (flags) &= ~AuWrDir_##name; } while (0) +- +-struct au_wr_dir_args { +- aufs_bindex_t force_btgt; +- unsigned char flags; +-}; +-int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry, +- struct au_wr_dir_args *args); +- +-struct dentry *au_pinned_h_parent(struct au_pin *pin); +-void au_pin_init(struct au_pin *pin, struct dentry *dentry, +- aufs_bindex_t bindex, int lsc_di, int lsc_hi, +- unsigned int udba, unsigned char flags); +-int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex, +- unsigned int udba, unsigned char flags) __must_check; +-int au_do_pin(struct au_pin *pin) __must_check; +-void au_unpin(struct au_pin *pin); +- +-/* i_op_add.c */ +-int au_may_add(struct dentry *dentry, aufs_bindex_t bindex, +- struct dentry *h_parent, int isdir); +-int aufs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, +- dev_t dev); +-int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname); +-int aufs_create(struct inode *dir, struct dentry *dentry, umode_t mode, +- bool want_excl); +-int aufs_link(struct dentry *src_dentry, struct inode *dir, +- struct dentry *dentry); +-int aufs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode); +- +-/* i_op_del.c */ +-int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup); +-int au_may_del(struct dentry *dentry, aufs_bindex_t bindex, +- struct dentry *h_parent, int isdir); +-int aufs_unlink(struct inode *dir, struct dentry *dentry); +-int aufs_rmdir(struct inode *dir, struct dentry *dentry); +- +-/* i_op_ren.c */ +-int au_wbr(struct dentry *dentry, aufs_bindex_t btgt); +-int aufs_rename(struct inode *src_dir, struct dentry *src_dentry, +- struct inode *dir, struct dentry *dentry); +- +-/* iinfo.c */ +-struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex); +-void au_hiput(struct au_hinode *hinode); +-void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex, +- struct dentry *h_wh); +-unsigned int au_hi_flags(struct inode *inode, int isdir); +- +-/* hinode flags */ +-#define AuHi_XINO 1 +-#define AuHi_HNOTIFY (1 << 1) +-#define au_ftest_hi(flags, name) ((flags) & AuHi_##name) +-#define au_fset_hi(flags, name) \ +- do { (flags) |= AuHi_##name; } while (0) +-#define au_fclr_hi(flags, name) \ +- do { (flags) &= ~AuHi_##name; } while (0) +- +-#ifndef CONFIG_AUFS_HNOTIFY +-#undef AuHi_HNOTIFY +-#define AuHi_HNOTIFY 0 +-#endif +- +-void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex, +- struct inode *h_inode, unsigned int flags); +- +-void au_update_iigen(struct inode *inode, int half); +-void au_update_ibrange(struct inode *inode, int do_put_zero); +- +-void au_icntnr_init_once(void *_c); +-int au_iinfo_init(struct inode *inode); +-void au_iinfo_fin(struct inode *inode); +-int au_ii_realloc(struct au_iinfo *iinfo, int nbr); +- +-#ifdef CONFIG_PROC_FS +-/* plink.c */ +-int au_plink_maint(struct super_block *sb, int flags); +-void au_plink_maint_leave(struct au_sbinfo *sbinfo); +-int au_plink_maint_enter(struct super_block *sb); +-#ifdef CONFIG_AUFS_DEBUG +-void au_plink_list(struct super_block *sb); +-#else +-AuStubVoid(au_plink_list, struct super_block *sb) +-#endif +-int au_plink_test(struct inode *inode); +-struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex); +-void au_plink_append(struct inode *inode, aufs_bindex_t bindex, +- struct dentry *h_dentry); +-void au_plink_put(struct super_block *sb, int verbose); +-void au_plink_clean(struct super_block *sb, int verbose); +-void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id); +-#else +-AuStubInt0(au_plink_maint, struct super_block *sb, int flags); +-AuStubVoid(au_plink_maint_leave, struct au_sbinfo *sbinfo); +-AuStubInt0(au_plink_maint_enter, struct super_block *sb); +-AuStubVoid(au_plink_list, struct super_block *sb); +-AuStubInt0(au_plink_test, struct inode *inode); +-AuStub(struct dentry *, au_plink_lkup, return NULL, +- struct inode *inode, aufs_bindex_t bindex); +-AuStubVoid(au_plink_append, struct inode *inode, aufs_bindex_t bindex, +- struct dentry *h_dentry); +-AuStubVoid(au_plink_put, struct super_block *sb, int verbose); +-AuStubVoid(au_plink_clean, struct super_block *sb, int verbose); +-AuStubVoid(au_plink_half_refresh, struct super_block *sb, aufs_bindex_t br_id); +-#endif /* CONFIG_PROC_FS */ +- +-/* ---------------------------------------------------------------------- */ +- +-/* lock subclass for iinfo */ +-enum { +- AuLsc_II_CHILD, /* child first */ +- AuLsc_II_CHILD2, /* rename(2), link(2), and cpup at hnotify */ +- AuLsc_II_CHILD3, /* copyup dirs */ +- AuLsc_II_PARENT, /* see AuLsc_I_PARENT in vfsub.h */ +- AuLsc_II_PARENT2, +- AuLsc_II_PARENT3, /* copyup dirs */ +- AuLsc_II_NEW_CHILD +-}; +- +-/* +- * ii_read_lock_child, ii_write_lock_child, +- * ii_read_lock_child2, ii_write_lock_child2, +- * ii_read_lock_child3, ii_write_lock_child3, +- * ii_read_lock_parent, ii_write_lock_parent, +- * ii_read_lock_parent2, ii_write_lock_parent2, +- * ii_read_lock_parent3, ii_write_lock_parent3, +- * ii_read_lock_new_child, ii_write_lock_new_child, +- */ +-#define AuReadLockFunc(name, lsc) \ +-static inline void ii_read_lock_##name(struct inode *i) \ +-{ \ +- au_rw_read_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); \ +-} +- +-#define AuWriteLockFunc(name, lsc) \ +-static inline void ii_write_lock_##name(struct inode *i) \ +-{ \ +- au_rw_write_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); \ +-} +- +-#define AuRWLockFuncs(name, lsc) \ +- AuReadLockFunc(name, lsc) \ +- AuWriteLockFunc(name, lsc) +- +-AuRWLockFuncs(child, CHILD); +-AuRWLockFuncs(child2, CHILD2); +-AuRWLockFuncs(child3, CHILD3); +-AuRWLockFuncs(parent, PARENT); +-AuRWLockFuncs(parent2, PARENT2); +-AuRWLockFuncs(parent3, PARENT3); +-AuRWLockFuncs(new_child, NEW_CHILD); +- +-#undef AuReadLockFunc +-#undef AuWriteLockFunc +-#undef AuRWLockFuncs +- +-/* +- * ii_read_unlock, ii_write_unlock, ii_downgrade_lock +- */ +-AuSimpleUnlockRwsemFuncs(ii, struct inode *i, &au_ii(i)->ii_rwsem); +- +-#define IiMustNoWaiters(i) AuRwMustNoWaiters(&au_ii(i)->ii_rwsem) +-#define IiMustAnyLock(i) AuRwMustAnyLock(&au_ii(i)->ii_rwsem) +-#define IiMustWriteLock(i) AuRwMustWriteLock(&au_ii(i)->ii_rwsem) +- +-/* ---------------------------------------------------------------------- */ +- +-static inline void au_icntnr_init(struct au_icntnr *c) +-{ +-#ifdef CONFIG_AUFS_DEBUG +- c->vfs_inode.i_mode = 0; +-#endif +-} +- +-static inline unsigned int au_iigen(struct inode *inode, struct au_iigen *iigen) +-{ +- unsigned int gen; +- struct au_iinfo *iinfo; +- +- iinfo = au_ii(inode); +- spin_lock(&iinfo->ii_genspin); +- if (iigen) +- *iigen = iinfo->ii_generation; +- gen = iinfo->ii_generation.ig_generation; +- spin_unlock(&iinfo->ii_genspin); +- +- return gen; +-} +- +-/* tiny test for inode number */ +-/* tmpfs generation is too rough */ +-static inline int au_test_higen(struct inode *inode, struct inode *h_inode) +-{ +- struct au_iinfo *iinfo; +- +- iinfo = au_ii(inode); +- AuRwMustAnyLock(&iinfo->ii_rwsem); +- return !(iinfo->ii_hsb1 == h_inode->i_sb +- && iinfo->ii_higen == h_inode->i_generation); +-} +- +-static inline void au_iigen_dec(struct inode *inode) +-{ +- struct au_iinfo *iinfo; +- +- iinfo = au_ii(inode); +- spin_lock(&iinfo->ii_genspin); +- iinfo->ii_generation.ig_generation--; +- spin_unlock(&iinfo->ii_genspin); +-} +- +-static inline int au_iigen_test(struct inode *inode, unsigned int sigen) +-{ +- int err; +- +- err = 0; +- if (unlikely(inode && au_iigen(inode, NULL) != sigen)) +- err = -EIO; +- +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static inline aufs_bindex_t au_ii_br_id(struct inode *inode, +- aufs_bindex_t bindex) +-{ +- IiMustAnyLock(inode); +- return au_ii(inode)->ii_hinode[0 + bindex].hi_id; +-} +- +-static inline aufs_bindex_t au_ibstart(struct inode *inode) +-{ +- IiMustAnyLock(inode); +- return au_ii(inode)->ii_bstart; +-} +- +-static inline aufs_bindex_t au_ibend(struct inode *inode) +-{ +- IiMustAnyLock(inode); +- return au_ii(inode)->ii_bend; +-} +- +-static inline struct au_vdir *au_ivdir(struct inode *inode) +-{ +- IiMustAnyLock(inode); +- return au_ii(inode)->ii_vdir; +-} +- +-static inline struct dentry *au_hi_wh(struct inode *inode, aufs_bindex_t bindex) +-{ +- IiMustAnyLock(inode); +- return au_ii(inode)->ii_hinode[0 + bindex].hi_whdentry; +-} +- +-static inline void au_set_ibstart(struct inode *inode, aufs_bindex_t bindex) +-{ +- IiMustWriteLock(inode); +- au_ii(inode)->ii_bstart = bindex; +-} +- +-static inline void au_set_ibend(struct inode *inode, aufs_bindex_t bindex) +-{ +- IiMustWriteLock(inode); +- au_ii(inode)->ii_bend = bindex; +-} +- +-static inline void au_set_ivdir(struct inode *inode, struct au_vdir *vdir) +-{ +- IiMustWriteLock(inode); +- au_ii(inode)->ii_vdir = vdir; +-} +- +-static inline struct au_hinode *au_hi(struct inode *inode, aufs_bindex_t bindex) +-{ +- IiMustAnyLock(inode); +- return au_ii(inode)->ii_hinode + bindex; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static inline struct dentry *au_pinned_parent(struct au_pin *pin) +-{ +- if (pin) +- return pin->parent; +- return NULL; +-} +- +-static inline struct inode *au_pinned_h_dir(struct au_pin *pin) +-{ +- if (pin && pin->hdir) +- return pin->hdir->hi_inode; +- return NULL; +-} +- +-static inline struct au_hinode *au_pinned_hdir(struct au_pin *pin) +-{ +- if (pin) +- return pin->hdir; +- return NULL; +-} +- +-static inline void au_pin_set_dentry(struct au_pin *pin, struct dentry *dentry) +-{ +- if (pin) +- pin->dentry = dentry; +-} +- +-static inline void au_pin_set_parent_lflag(struct au_pin *pin, +- unsigned char lflag) +-{ +- if (pin) { +- if (lflag) +- au_fset_pin(pin->flags, DI_LOCKED); +- else +- au_fclr_pin(pin->flags, DI_LOCKED); +- } +-} +- +-static inline void au_pin_set_parent(struct au_pin *pin, struct dentry *parent) +-{ +- if (pin) { +- dput(pin->parent); +- pin->parent = dget(parent); +- } +-} +- +-/* ---------------------------------------------------------------------- */ +- +-struct au_branch; +-#ifdef CONFIG_AUFS_HNOTIFY +-struct au_hnotify_op { +- void (*ctl)(struct au_hinode *hinode, int do_set); +- int (*alloc)(struct au_hinode *hinode); +- +- /* +- * if it returns true, the the caller should free hinode->hi_notify, +- * otherwise ->free() frees it. +- */ +- int (*free)(struct au_hinode *hinode, +- struct au_hnotify *hn) __must_check; +- +- void (*fin)(void); +- int (*init)(void); +- +- int (*reset_br)(unsigned int udba, struct au_branch *br, int perm); +- void (*fin_br)(struct au_branch *br); +- int (*init_br)(struct au_branch *br, int perm); +-}; +- +-/* hnotify.c */ +-int au_hn_alloc(struct au_hinode *hinode, struct inode *inode); +-void au_hn_free(struct au_hinode *hinode); +-void au_hn_ctl(struct au_hinode *hinode, int do_set); +-void au_hn_reset(struct inode *inode, unsigned int flags); +-int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask, +- struct qstr *h_child_qstr, struct inode *h_child_inode); +-int au_hnotify_reset_br(unsigned int udba, struct au_branch *br, int perm); +-int au_hnotify_init_br(struct au_branch *br, int perm); +-void au_hnotify_fin_br(struct au_branch *br); +-int __init au_hnotify_init(void); +-void au_hnotify_fin(void); +- +-/* hfsnotify.c */ +-extern const struct au_hnotify_op au_hnotify_op; +- +-static inline +-void au_hn_init(struct au_hinode *hinode) +-{ +- hinode->hi_notify = NULL; +-} +- +-static inline struct au_hnotify *au_hn(struct au_hinode *hinode) +-{ +- return hinode->hi_notify; +-} +- +-#else +-static inline +-int au_hn_alloc(struct au_hinode *hinode __maybe_unused, +- struct inode *inode __maybe_unused) +-{ +- return -EOPNOTSUPP; +-} +- +-static inline struct au_hnotify *au_hn(struct au_hinode *hinode) +-{ +- return NULL; +-} +- +-AuStubVoid(au_hn_free, struct au_hinode *hinode __maybe_unused) +-AuStubVoid(au_hn_ctl, struct au_hinode *hinode __maybe_unused, +- int do_set __maybe_unused) +-AuStubVoid(au_hn_reset, struct inode *inode __maybe_unused, +- unsigned int flags __maybe_unused) +-AuStubInt0(au_hnotify_reset_br, unsigned int udba __maybe_unused, +- struct au_branch *br __maybe_unused, +- int perm __maybe_unused) +-AuStubInt0(au_hnotify_init_br, struct au_branch *br __maybe_unused, +- int perm __maybe_unused) +-AuStubVoid(au_hnotify_fin_br, struct au_branch *br __maybe_unused) +-AuStubInt0(__init au_hnotify_init, void) +-AuStubVoid(au_hnotify_fin, void) +-AuStubVoid(au_hn_init, struct au_hinode *hinode __maybe_unused) +-#endif /* CONFIG_AUFS_HNOTIFY */ +- +-static inline void au_hn_suspend(struct au_hinode *hdir) +-{ +- au_hn_ctl(hdir, /*do_set*/0); +-} +- +-static inline void au_hn_resume(struct au_hinode *hdir) +-{ +- au_hn_ctl(hdir, /*do_set*/1); +-} +- +-static inline void au_hn_imtx_lock(struct au_hinode *hdir) +-{ +- mutex_lock(&hdir->hi_inode->i_mutex); +- au_hn_suspend(hdir); +-} +- +-static inline void au_hn_imtx_lock_nested(struct au_hinode *hdir, +- unsigned int sc __maybe_unused) +-{ +- mutex_lock_nested(&hdir->hi_inode->i_mutex, sc); +- au_hn_suspend(hdir); +-} +- +-static inline void au_hn_imtx_unlock(struct au_hinode *hdir) +-{ +- au_hn_resume(hdir); +- mutex_unlock(&hdir->hi_inode->i_mutex); +-} +- +-#endif /* __KERNEL__ */ +-#endif /* __AUFS_INODE_H__ */ +diff --git a/fs/aufs/ioctl.c b/fs/aufs/ioctl.c +deleted file mode 100644 +index dcb837f..0000000 +--- a/fs/aufs/ioctl.c ++++ /dev/null +@@ -1,196 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * ioctl +- * plink-management and readdir in userspace. +- * assist the pathconf(3) wrapper library. +- */ +- +-#include "aufs.h" +- +-static int au_wbr_fd(struct path *path, struct aufs_wbr_fd __user *arg) +-{ +- int err, fd; +- aufs_bindex_t wbi, bindex, bend; +- struct file *h_file; +- struct super_block *sb; +- struct dentry *root; +- struct au_branch *br; +- struct aufs_wbr_fd wbrfd = { +- .oflags = au_dir_roflags, +- .brid = -1 +- }; +- const int valid = O_RDONLY | O_NONBLOCK | O_LARGEFILE | O_DIRECTORY +- | O_NOATIME | O_CLOEXEC; +- +- AuDebugOn(wbrfd.oflags & ~valid); +- +- if (arg) { +- err = copy_from_user(&wbrfd, arg, sizeof(wbrfd)); +- if (unlikely(err)) { +- err = -EFAULT; +- goto out; +- } +- +- err = -EINVAL; +- AuDbg("wbrfd{0%o, %d}\n", wbrfd.oflags, wbrfd.brid); +- wbrfd.oflags |= au_dir_roflags; +- AuDbg("0%o\n", wbrfd.oflags); +- if (unlikely(wbrfd.oflags & ~valid)) +- goto out; +- } +- +- fd = get_unused_fd(); +- err = fd; +- if (unlikely(fd < 0)) +- goto out; +- +- h_file = ERR_PTR(-EINVAL); +- wbi = 0; +- br = NULL; +- sb = path->dentry->d_sb; +- root = sb->s_root; +- aufs_read_lock(root, AuLock_IR); +- bend = au_sbend(sb); +- if (wbrfd.brid >= 0) { +- wbi = au_br_index(sb, wbrfd.brid); +- if (unlikely(wbi < 0 || wbi > bend)) +- goto out_unlock; +- } +- +- h_file = ERR_PTR(-ENOENT); +- br = au_sbr(sb, wbi); +- if (!au_br_writable(br->br_perm)) { +- if (arg) +- goto out_unlock; +- +- bindex = wbi + 1; +- wbi = -1; +- for (; bindex <= bend; bindex++) { +- br = au_sbr(sb, bindex); +- if (au_br_writable(br->br_perm)) { +- wbi = bindex; +- br = au_sbr(sb, wbi); +- break; +- } +- } +- } +- AuDbg("wbi %d\n", wbi); +- if (wbi >= 0) +- h_file = au_h_open(root, wbi, wbrfd.oflags, NULL); +- +-out_unlock: +- aufs_read_unlock(root, AuLock_IR); +- err = PTR_ERR(h_file); +- if (IS_ERR(h_file)) +- goto out_fd; +- +- atomic_dec(&br->br_count); /* cf. au_h_open() */ +- fd_install(fd, h_file); +- err = fd; +- goto out; /* success */ +- +-out_fd: +- put_unused_fd(fd); +-out: +- AuTraceErr(err); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg) +-{ +- long err; +- +- switch (cmd) { +- case AUFS_CTL_RDU: +- case AUFS_CTL_RDU_INO: +- err = au_rdu_ioctl(file, cmd, arg); +- break; +- +- case AUFS_CTL_WBR_FD: +- err = au_wbr_fd(&file->f_path, (void __user *)arg); +- break; +- +- case AUFS_CTL_IBUSY: +- err = au_ibusy_ioctl(file, arg); +- break; +- +- default: +- /* do not call the lower */ +- AuDbg("0x%x\n", cmd); +- err = -ENOTTY; +- } +- +- AuTraceErr(err); +- return err; +-} +- +-long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg) +-{ +- long err; +- +- switch (cmd) { +- case AUFS_CTL_WBR_FD: +- err = au_wbr_fd(&file->f_path, (void __user *)arg); +- break; +- +- default: +- /* do not call the lower */ +- AuDbg("0x%x\n", cmd); +- err = -ENOTTY; +- } +- +- AuTraceErr(err); +- return err; +-} +- +-#ifdef CONFIG_COMPAT +-long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd, +- unsigned long arg) +-{ +- long err; +- +- switch (cmd) { +- case AUFS_CTL_RDU: +- case AUFS_CTL_RDU_INO: +- err = au_rdu_compat_ioctl(file, cmd, arg); +- break; +- +- case AUFS_CTL_IBUSY: +- err = au_ibusy_compat_ioctl(file, arg); +- break; +- +- default: +- err = aufs_ioctl_dir(file, cmd, arg); +- } +- +- AuTraceErr(err); +- return err; +-} +- +-#if 0 /* unused yet */ +-long aufs_compat_ioctl_nondir(struct file *file, unsigned int cmd, +- unsigned long arg) +-{ +- return aufs_ioctl_nondir(file, cmd, (unsigned long)compat_ptr(arg)); +-} +-#endif +-#endif +diff --git a/fs/aufs/loop.c b/fs/aufs/loop.c +deleted file mode 100644 +index ccae19c..0000000 +--- a/fs/aufs/loop.c ++++ /dev/null +@@ -1,135 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * support for loopback block device as a branch +- */ +- +-#include +-#include "aufs.h" +- +-/* +- * test if two lower dentries have overlapping branches. +- */ +-int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_adding) +-{ +- struct super_block *h_sb; +- struct loop_device *l; +- +- h_sb = h_adding->d_sb; +- if (MAJOR(h_sb->s_dev) != LOOP_MAJOR) +- return 0; +- +- l = h_sb->s_bdev->bd_disk->private_data; +- h_adding = l->lo_backing_file->f_dentry; +- /* +- * h_adding can be local NFS. +- * in this case aufs cannot detect the loop. +- */ +- if (unlikely(h_adding->d_sb == sb)) +- return 1; +- return !!au_test_subdir(h_adding, sb->s_root); +-} +- +-/* true if a kernel thread named 'loop[0-9].*' accesses a file */ +-int au_test_loopback_kthread(void) +-{ +- int ret; +- struct task_struct *tsk = current; +- char c, comm[sizeof(tsk->comm)]; +- +- ret = 0; +- if (tsk->flags & PF_KTHREAD) { +- get_task_comm(comm, tsk); +- c = comm[4]; +- ret = ('0' <= c && c <= '9' +- && !strncmp(comm, "loop", 4)); +- } +- +- return ret; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-#define au_warn_loopback_step 16 +-static int au_warn_loopback_nelem = au_warn_loopback_step; +-static unsigned long *au_warn_loopback_array; +- +-void au_warn_loopback(struct super_block *h_sb) +-{ +- int i, new_nelem; +- unsigned long *a, magic; +- static DEFINE_SPINLOCK(spin); +- +- magic = h_sb->s_magic; +- spin_lock(&spin); +- a = au_warn_loopback_array; +- for (i = 0; i < au_warn_loopback_nelem && *a; i++) +- if (a[i] == magic) { +- spin_unlock(&spin); +- return; +- } +- +- /* h_sb is new to us, print it */ +- if (i < au_warn_loopback_nelem) { +- a[i] = magic; +- goto pr; +- } +- +- /* expand the array */ +- new_nelem = au_warn_loopback_nelem + au_warn_loopback_step; +- a = au_kzrealloc(au_warn_loopback_array, +- au_warn_loopback_nelem * sizeof(unsigned long), +- new_nelem * sizeof(unsigned long), GFP_ATOMIC); +- if (a) { +- au_warn_loopback_nelem = new_nelem; +- au_warn_loopback_array = a; +- a[i] = magic; +- goto pr; +- } +- +- spin_unlock(&spin); +- AuWarn1("realloc failed, ignored\n"); +- return; +- +-pr: +- spin_unlock(&spin); +- pr_warn("you may want to try another patch for loopback file " +- "on %s(0x%lx) branch\n", au_sbtype(h_sb), magic); +-} +- +-int au_loopback_init(void) +-{ +- int err; +- struct super_block *sb __maybe_unused; +- +- AuDebugOn(sizeof(sb->s_magic) != sizeof(unsigned long)); +- +- err = 0; +- au_warn_loopback_array = kcalloc(au_warn_loopback_step, +- sizeof(unsigned long), GFP_NOFS); +- if (unlikely(!au_warn_loopback_array)) +- err = -ENOMEM; +- +- return err; +-} +- +-void au_loopback_fin(void) +-{ +- kfree(au_warn_loopback_array); +-} +diff --git a/fs/aufs/loop.h b/fs/aufs/loop.h +deleted file mode 100644 +index 88d019c..0000000 +--- a/fs/aufs/loop.h ++++ /dev/null +@@ -1,50 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * support for loopback mount as a branch +- */ +- +-#ifndef __AUFS_LOOP_H__ +-#define __AUFS_LOOP_H__ +- +-#ifdef __KERNEL__ +- +-struct dentry; +-struct super_block; +- +-#ifdef CONFIG_AUFS_BDEV_LOOP +-/* loop.c */ +-int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_adding); +-int au_test_loopback_kthread(void); +-void au_warn_loopback(struct super_block *h_sb); +- +-int au_loopback_init(void); +-void au_loopback_fin(void); +-#else +-AuStubInt0(au_test_loopback_overlap, struct super_block *sb, +- struct dentry *h_adding) +-AuStubInt0(au_test_loopback_kthread, void) +-AuStubVoid(au_warn_loopback, struct super_block *h_sb) +- +-AuStubInt0(au_loopback_init, void) +-AuStubVoid(au_loopback_fin, void) +-#endif /* BLK_DEV_LOOP */ +- +-#endif /* __KERNEL__ */ +-#endif /* __AUFS_LOOP_H__ */ +diff --git a/fs/aufs/magic.mk b/fs/aufs/magic.mk +deleted file mode 100644 +index 3e6387b..0000000 +--- a/fs/aufs/magic.mk ++++ /dev/null +@@ -1,54 +0,0 @@ +- +-# defined in ${srctree}/fs/fuse/inode.c +-# tristate +-ifdef CONFIG_FUSE_FS +-ccflags-y += -DFUSE_SUPER_MAGIC=0x65735546 +-endif +- +-# defined in ${srctree}/fs/ocfs2/ocfs2_fs.h +-# tristate +-ifdef CONFIG_OCFS2_FS +-ccflags-y += -DOCFS2_SUPER_MAGIC=0x7461636f +-endif +- +-# defined in ${srctree}/fs/ocfs2/dlm/userdlm.h +-# tristate +-ifdef CONFIG_OCFS2_FS_O2CB +-ccflags-y += -DDLMFS_MAGIC=0x76a9f425 +-endif +- +-# defined in ${srctree}/fs/cifs/cifsfs.c +-# tristate +-ifdef CONFIG_CIFS_FS +-ccflags-y += -DCIFS_MAGIC_NUMBER=0xFF534D42 +-endif +- +-# defined in ${srctree}/fs/xfs/xfs_sb.h +-# tristate +-ifdef CONFIG_XFS_FS +-ccflags-y += -DXFS_SB_MAGIC=0x58465342 +-endif +- +-# defined in ${srctree}/fs/configfs/mount.c +-# tristate +-ifdef CONFIG_CONFIGFS_FS +-ccflags-y += -DCONFIGFS_MAGIC=0x62656570 +-endif +- +-# defined in ${srctree}/fs/9p/v9fs.h +-# tristate +-ifdef CONFIG_9P_FS +-ccflags-y += -DV9FS_MAGIC=0x01021997 +-endif +- +-# defined in ${srctree}/fs/ubifs/ubifs.h +-# tristate +-ifdef CONFIG_UBIFS_FS +-ccflags-y += -DUBIFS_SUPER_MAGIC=0x24051905 +-endif +- +-# defined in ${srctree}/fs/hfsplus/hfsplus_raw.h +-# tristate +-ifdef CONFIG_HFSPLUS_FS +-ccflags-y += -DHFSPLUS_SUPER_MAGIC=0x482b +-endif +diff --git a/fs/aufs/module.c b/fs/aufs/module.c +deleted file mode 100644 +index 36013ee..0000000 +--- a/fs/aufs/module.c ++++ /dev/null +@@ -1,202 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * module global variables and operations +- */ +- +-#include +-#include +-#include "aufs.h" +- +-void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp) +-{ +- if (new_sz <= nused) +- return p; +- +- p = krealloc(p, new_sz, gfp); +- if (p) +- memset(p + nused, 0, new_sz - nused); +- return p; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* +- * aufs caches +- */ +-struct kmem_cache *au_cachep[AuCache_Last]; +-static int __init au_cache_init(void) +-{ +- au_cachep[AuCache_DINFO] = AuCacheCtor(au_dinfo, au_di_init_once); +- if (au_cachep[AuCache_DINFO]) +- /* SLAB_DESTROY_BY_RCU */ +- au_cachep[AuCache_ICNTNR] = AuCacheCtor(au_icntnr, +- au_icntnr_init_once); +- if (au_cachep[AuCache_ICNTNR]) +- au_cachep[AuCache_FINFO] = AuCacheCtor(au_finfo, +- au_fi_init_once); +- if (au_cachep[AuCache_FINFO]) +- au_cachep[AuCache_VDIR] = AuCache(au_vdir); +- if (au_cachep[AuCache_VDIR]) +- au_cachep[AuCache_DEHSTR] = AuCache(au_vdir_dehstr); +- if (au_cachep[AuCache_DEHSTR]) +- return 0; +- +- return -ENOMEM; +-} +- +-static void au_cache_fin(void) +-{ +- int i; +- +- /* +- * Make sure all delayed rcu free inodes are flushed before we +- * destroy cache. +- */ +- rcu_barrier(); +- +- /* excluding AuCache_HNOTIFY */ +- BUILD_BUG_ON(AuCache_HNOTIFY + 1 != AuCache_Last); +- for (i = 0; i < AuCache_HNOTIFY; i++) +- if (au_cachep[i]) { +- kmem_cache_destroy(au_cachep[i]); +- au_cachep[i] = NULL; +- } +-} +- +-/* ---------------------------------------------------------------------- */ +- +-int au_dir_roflags; +- +-#ifdef CONFIG_AUFS_SBILIST +-/* +- * iterate_supers_type() doesn't protect us from +- * remounting (branch management) +- */ +-struct au_splhead au_sbilist; +-#endif +- +-struct lock_class_key au_lc_key[AuLcKey_Last]; +- +-/* +- * functions for module interface. +- */ +-MODULE_LICENSE("GPL"); +-/* MODULE_LICENSE("GPL v2"); */ +-MODULE_AUTHOR("Junjiro R. Okajima "); +-MODULE_DESCRIPTION(AUFS_NAME +- " -- Advanced multi layered unification filesystem"); +-MODULE_VERSION(AUFS_VERSION); +- +-/* this module parameter has no meaning when SYSFS is disabled */ +-int sysaufs_brs = 1; +-MODULE_PARM_DESC(brs, "use /fs/aufs/si_*/brN"); +-module_param_named(brs, sysaufs_brs, int, S_IRUGO); +- +-/* ---------------------------------------------------------------------- */ +- +-static char au_esc_chars[0x20 + 3]; /* 0x01-0x20, backslash, del, and NULL */ +- +-int au_seq_path(struct seq_file *seq, struct path *path) +-{ +- return seq_path(seq, path, au_esc_chars); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static int __init aufs_init(void) +-{ +- int err, i; +- char *p; +- +- p = au_esc_chars; +- for (i = 1; i <= ' '; i++) +- *p++ = i; +- *p++ = '\\'; +- *p++ = '\x7f'; +- *p = 0; +- +- au_dir_roflags = au_file_roflags(O_DIRECTORY | O_LARGEFILE); +- +- au_sbilist_init(); +- sysaufs_brs_init(); +- au_debug_init(); +- au_dy_init(); +- err = sysaufs_init(); +- if (unlikely(err)) +- goto out; +- err = au_procfs_init(); +- if (unlikely(err)) +- goto out_sysaufs; +- err = au_wkq_init(); +- if (unlikely(err)) +- goto out_procfs; +- err = au_loopback_init(); +- if (unlikely(err)) +- goto out_wkq; +- err = au_hnotify_init(); +- if (unlikely(err)) +- goto out_loopback; +- err = au_sysrq_init(); +- if (unlikely(err)) +- goto out_hin; +- err = au_cache_init(); +- if (unlikely(err)) +- goto out_sysrq; +- err = register_filesystem(&aufs_fs_type); +- if (unlikely(err)) +- goto out_cache; +- /* since we define pr_fmt, call printk directly */ +- printk(KERN_INFO AUFS_NAME " " AUFS_VERSION "\n"); +- goto out; /* success */ +- +-out_cache: +- au_cache_fin(); +-out_sysrq: +- au_sysrq_fin(); +-out_hin: +- au_hnotify_fin(); +-out_loopback: +- au_loopback_fin(); +-out_wkq: +- au_wkq_fin(); +-out_procfs: +- au_procfs_fin(); +-out_sysaufs: +- sysaufs_fin(); +- au_dy_fin(); +-out: +- return err; +-} +- +-static void __exit aufs_exit(void) +-{ +- unregister_filesystem(&aufs_fs_type); +- au_cache_fin(); +- au_sysrq_fin(); +- au_hnotify_fin(); +- au_loopback_fin(); +- au_wkq_fin(); +- au_procfs_fin(); +- sysaufs_fin(); +- au_dy_fin(); +-} +- +-module_init(aufs_init); +-module_exit(aufs_exit); +diff --git a/fs/aufs/module.h b/fs/aufs/module.h +deleted file mode 100644 +index 52bf472..0000000 +--- a/fs/aufs/module.h ++++ /dev/null +@@ -1,105 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * module initialization and module-global +- */ +- +-#ifndef __AUFS_MODULE_H__ +-#define __AUFS_MODULE_H__ +- +-#ifdef __KERNEL__ +- +-#include +- +-struct path; +-struct seq_file; +- +-/* module parameters */ +-extern int sysaufs_brs; +- +-/* ---------------------------------------------------------------------- */ +- +-extern int au_dir_roflags; +- +-enum { +- AuLcNonDir_FIINFO, +- AuLcNonDir_DIINFO, +- AuLcNonDir_IIINFO, +- +- AuLcDir_FIINFO, +- AuLcDir_DIINFO, +- AuLcDir_IIINFO, +- +- AuLcSymlink_DIINFO, +- AuLcSymlink_IIINFO, +- +- AuLcKey_Last +-}; +-extern struct lock_class_key au_lc_key[AuLcKey_Last]; +- +-void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp); +-int au_seq_path(struct seq_file *seq, struct path *path); +- +-#ifdef CONFIG_PROC_FS +-/* procfs.c */ +-int __init au_procfs_init(void); +-void au_procfs_fin(void); +-#else +-AuStubInt0(au_procfs_init, void); +-AuStubVoid(au_procfs_fin, void); +-#endif +- +-/* ---------------------------------------------------------------------- */ +- +-/* kmem cache */ +-enum { +- AuCache_DINFO, +- AuCache_ICNTNR, +- AuCache_FINFO, +- AuCache_VDIR, +- AuCache_DEHSTR, +- AuCache_HNOTIFY, /* must be last */ +- AuCache_Last +-}; +- +-#define AuCacheFlags (SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD) +-#define AuCache(type) KMEM_CACHE(type, AuCacheFlags) +-#define AuCacheCtor(type, ctor) \ +- kmem_cache_create(#type, sizeof(struct type), \ +- __alignof__(struct type), AuCacheFlags, ctor) +- +-extern struct kmem_cache *au_cachep[]; +- +-#define AuCacheFuncs(name, index) \ +-static inline struct au_##name *au_cache_alloc_##name(void) \ +-{ return kmem_cache_alloc(au_cachep[AuCache_##index], GFP_NOFS); } \ +-static inline void au_cache_free_##name(struct au_##name *p) \ +-{ kmem_cache_free(au_cachep[AuCache_##index], p); } +- +-AuCacheFuncs(dinfo, DINFO); +-AuCacheFuncs(icntnr, ICNTNR); +-AuCacheFuncs(finfo, FINFO); +-AuCacheFuncs(vdir, VDIR); +-AuCacheFuncs(vdir_dehstr, DEHSTR); +-#ifdef CONFIG_AUFS_HNOTIFY +-AuCacheFuncs(hnotify, HNOTIFY); +-#endif +- +-#endif /* __KERNEL__ */ +-#endif /* __AUFS_MODULE_H__ */ +diff --git a/fs/aufs/opts.c b/fs/aufs/opts.c +deleted file mode 100644 +index ff0d5a5..0000000 +--- a/fs/aufs/opts.c ++++ /dev/null +@@ -1,1677 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * mount options/flags +- */ +- +-#include +-#include /* a distribution requires */ +-#include +-#include "aufs.h" +- +-/* ---------------------------------------------------------------------- */ +- +-enum { +- Opt_br, +- Opt_add, Opt_del, Opt_mod, Opt_reorder, Opt_append, Opt_prepend, +- Opt_idel, Opt_imod, Opt_ireorder, +- Opt_dirwh, Opt_rdcache, Opt_rdblk, Opt_rdhash, Opt_rendir, +- Opt_rdblk_def, Opt_rdhash_def, +- Opt_xino, Opt_zxino, Opt_noxino, +- Opt_trunc_xino, Opt_trunc_xino_v, Opt_notrunc_xino, +- Opt_trunc_xino_path, Opt_itrunc_xino, +- Opt_trunc_xib, Opt_notrunc_xib, +- Opt_shwh, Opt_noshwh, +- Opt_plink, Opt_noplink, Opt_list_plink, +- Opt_udba, +- Opt_dio, Opt_nodio, +- /* Opt_lock, Opt_unlock, */ +- Opt_cmd, Opt_cmd_args, +- Opt_diropq_a, Opt_diropq_w, +- Opt_warn_perm, Opt_nowarn_perm, +- Opt_wbr_copyup, Opt_wbr_create, +- Opt_refrof, Opt_norefrof, +- Opt_verbose, Opt_noverbose, +- Opt_sum, Opt_nosum, Opt_wsum, +- Opt_tail, Opt_ignore, Opt_ignore_silent, Opt_err +-}; +- +-static match_table_t options = { +- {Opt_br, "br=%s"}, +- {Opt_br, "br:%s"}, +- +- {Opt_add, "add=%d:%s"}, +- {Opt_add, "add:%d:%s"}, +- {Opt_add, "ins=%d:%s"}, +- {Opt_add, "ins:%d:%s"}, +- {Opt_append, "append=%s"}, +- {Opt_append, "append:%s"}, +- {Opt_prepend, "prepend=%s"}, +- {Opt_prepend, "prepend:%s"}, +- +- {Opt_del, "del=%s"}, +- {Opt_del, "del:%s"}, +- /* {Opt_idel, "idel:%d"}, */ +- {Opt_mod, "mod=%s"}, +- {Opt_mod, "mod:%s"}, +- /* {Opt_imod, "imod:%d:%s"}, */ +- +- {Opt_dirwh, "dirwh=%d"}, +- +- {Opt_xino, "xino=%s"}, +- {Opt_noxino, "noxino"}, +- {Opt_trunc_xino, "trunc_xino"}, +- {Opt_trunc_xino_v, "trunc_xino_v=%d:%d"}, +- {Opt_notrunc_xino, "notrunc_xino"}, +- {Opt_trunc_xino_path, "trunc_xino=%s"}, +- {Opt_itrunc_xino, "itrunc_xino=%d"}, +- /* {Opt_zxino, "zxino=%s"}, */ +- {Opt_trunc_xib, "trunc_xib"}, +- {Opt_notrunc_xib, "notrunc_xib"}, +- +-#ifdef CONFIG_PROC_FS +- {Opt_plink, "plink"}, +-#else +- {Opt_ignore_silent, "plink"}, +-#endif +- +- {Opt_noplink, "noplink"}, +- +-#ifdef CONFIG_AUFS_DEBUG +- {Opt_list_plink, "list_plink"}, +-#endif +- +- {Opt_udba, "udba=%s"}, +- +- {Opt_dio, "dio"}, +- {Opt_nodio, "nodio"}, +- +- {Opt_diropq_a, "diropq=always"}, +- {Opt_diropq_a, "diropq=a"}, +- {Opt_diropq_w, "diropq=whiteouted"}, +- {Opt_diropq_w, "diropq=w"}, +- +- {Opt_warn_perm, "warn_perm"}, +- {Opt_nowarn_perm, "nowarn_perm"}, +- +- /* keep them temporary */ +- {Opt_ignore_silent, "coo=%s"}, +- {Opt_ignore_silent, "nodlgt"}, +- {Opt_ignore_silent, "nodirperm1"}, +- {Opt_ignore_silent, "clean_plink"}, +- +-#ifdef CONFIG_AUFS_SHWH +- {Opt_shwh, "shwh"}, +-#endif +- {Opt_noshwh, "noshwh"}, +- +- {Opt_rendir, "rendir=%d"}, +- +- {Opt_refrof, "refrof"}, +- {Opt_norefrof, "norefrof"}, +- +- {Opt_verbose, "verbose"}, +- {Opt_verbose, "v"}, +- {Opt_noverbose, "noverbose"}, +- {Opt_noverbose, "quiet"}, +- {Opt_noverbose, "q"}, +- {Opt_noverbose, "silent"}, +- +- {Opt_sum, "sum"}, +- {Opt_nosum, "nosum"}, +- {Opt_wsum, "wsum"}, +- +- {Opt_rdcache, "rdcache=%d"}, +- {Opt_rdblk, "rdblk=%d"}, +- {Opt_rdblk_def, "rdblk=def"}, +- {Opt_rdhash, "rdhash=%d"}, +- {Opt_rdhash_def, "rdhash=def"}, +- +- {Opt_wbr_create, "create=%s"}, +- {Opt_wbr_create, "create_policy=%s"}, +- {Opt_wbr_copyup, "cpup=%s"}, +- {Opt_wbr_copyup, "copyup=%s"}, +- {Opt_wbr_copyup, "copyup_policy=%s"}, +- +- /* internal use for the scripts */ +- {Opt_ignore_silent, "si=%s"}, +- +- {Opt_br, "dirs=%s"}, +- {Opt_ignore, "debug=%d"}, +- {Opt_ignore, "delete=whiteout"}, +- {Opt_ignore, "delete=all"}, +- {Opt_ignore, "imap=%s"}, +- +- /* temporary workaround, due to old mount(8)? */ +- {Opt_ignore_silent, "relatime"}, +- +- {Opt_err, NULL} +-}; +- +-/* ---------------------------------------------------------------------- */ +- +-static const char *au_parser_pattern(int val, struct match_token *token) +-{ +- while (token->pattern) { +- if (token->token == val) +- return token->pattern; +- token++; +- } +- BUG(); +- return "??"; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static match_table_t brperm = { +- {AuBrPerm_RO, AUFS_BRPERM_RO}, +- {AuBrPerm_RR, AUFS_BRPERM_RR}, +- {AuBrPerm_RW, AUFS_BRPERM_RW}, +- {0, NULL} +-}; +- +-static match_table_t brrattr = { +- {AuBrRAttr_WH, AUFS_BRRATTR_WH}, +- {0, NULL} +-}; +- +-static match_table_t brwattr = { +- {AuBrWAttr_NoLinkWH, AUFS_BRWATTR_NLWH}, +- {0, NULL} +-}; +- +-#define AuBrStr_LONGEST AUFS_BRPERM_RW "+" AUFS_BRWATTR_NLWH +- +-static int br_attr_val(char *str, match_table_t table, substring_t args[]) +-{ +- int attr, v; +- char *p; +- +- attr = 0; +- do { +- p = strchr(str, '+'); +- if (p) +- *p = 0; +- v = match_token(str, table, args); +- if (v) +- attr |= v; +- else { +- if (p) +- *p = '+'; +- pr_warn("ignored branch attribute %s\n", str); +- break; +- } +- if (p) +- str = p + 1; +- } while (p); +- +- return attr; +-} +- +-static int noinline_for_stack br_perm_val(char *perm) +-{ +- int val; +- char *p; +- substring_t args[MAX_OPT_ARGS]; +- +- p = strchr(perm, '+'); +- if (p) +- *p = 0; +- val = match_token(perm, brperm, args); +- if (!val) { +- if (p) +- *p = '+'; +- pr_warn("ignored branch permission %s\n", perm); +- val = AuBrPerm_RO; +- goto out; +- } +- if (!p) +- goto out; +- +- switch (val) { +- case AuBrPerm_RO: +- case AuBrPerm_RR: +- val |= br_attr_val(p + 1, brrattr, args); +- break; +- case AuBrPerm_RW: +- val |= br_attr_val(p + 1, brwattr, args); +- break; +- } +- +-out: +- return val; +-} +- +-/* Caller should free the return value */ +-char *au_optstr_br_perm(int brperm) +-{ +- char *p, a[sizeof(AuBrStr_LONGEST)]; +- int sz; +- +-#define SetPerm(str) do { \ +- sz = sizeof(str); \ +- memcpy(a, str, sz); \ +- p = a + sz - 1; \ +- } while (0) +- +-#define AppendAttr(flag, str) do { \ +- if (brperm & flag) { \ +- sz = sizeof(str); \ +- *p++ = '+'; \ +- memcpy(p, str, sz); \ +- p += sz - 1; \ +- } \ +- } while (0) +- +- switch (brperm & AuBrPerm_Mask) { +- case AuBrPerm_RO: +- SetPerm(AUFS_BRPERM_RO); +- break; +- case AuBrPerm_RR: +- SetPerm(AUFS_BRPERM_RR); +- break; +- case AuBrPerm_RW: +- SetPerm(AUFS_BRPERM_RW); +- break; +- default: +- AuDebugOn(1); +- } +- +- AppendAttr(AuBrRAttr_WH, AUFS_BRRATTR_WH); +- AppendAttr(AuBrWAttr_NoLinkWH, AUFS_BRWATTR_NLWH); +- +- AuDebugOn(strlen(a) >= sizeof(a)); +- return kstrdup(a, GFP_NOFS); +-#undef SetPerm +-#undef AppendAttr +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static match_table_t udbalevel = { +- {AuOpt_UDBA_REVAL, "reval"}, +- {AuOpt_UDBA_NONE, "none"}, +-#ifdef CONFIG_AUFS_HNOTIFY +- {AuOpt_UDBA_HNOTIFY, "notify"}, /* abstraction */ +-#ifdef CONFIG_AUFS_HFSNOTIFY +- {AuOpt_UDBA_HNOTIFY, "fsnotify"}, +-#endif +-#endif +- {-1, NULL} +-}; +- +-static int noinline_for_stack udba_val(char *str) +-{ +- substring_t args[MAX_OPT_ARGS]; +- +- return match_token(str, udbalevel, args); +-} +- +-const char *au_optstr_udba(int udba) +-{ +- return au_parser_pattern(udba, (void *)udbalevel); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static match_table_t au_wbr_create_policy = { +- {AuWbrCreate_TDP, "tdp"}, +- {AuWbrCreate_TDP, "top-down-parent"}, +- {AuWbrCreate_RR, "rr"}, +- {AuWbrCreate_RR, "round-robin"}, +- {AuWbrCreate_MFS, "mfs"}, +- {AuWbrCreate_MFS, "most-free-space"}, +- {AuWbrCreate_MFSV, "mfs:%d"}, +- {AuWbrCreate_MFSV, "most-free-space:%d"}, +- +- {AuWbrCreate_MFSRR, "mfsrr:%d"}, +- {AuWbrCreate_MFSRRV, "mfsrr:%d:%d"}, +- {AuWbrCreate_PMFS, "pmfs"}, +- {AuWbrCreate_PMFSV, "pmfs:%d"}, +- +- {-1, NULL} +-}; +- +-/* +- * cf. linux/lib/parser.c and cmdline.c +- * gave up calling memparse() since it uses simple_strtoull() instead of +- * kstrto...(). +- */ +-static int noinline_for_stack +-au_match_ull(substring_t *s, unsigned long long *result) +-{ +- int err; +- unsigned int len; +- char a[32]; +- +- err = -ERANGE; +- len = s->to - s->from; +- if (len + 1 <= sizeof(a)) { +- memcpy(a, s->from, len); +- a[len] = '\0'; +- err = kstrtoull(a, 0, result); +- } +- return err; +-} +- +-static int au_wbr_mfs_wmark(substring_t *arg, char *str, +- struct au_opt_wbr_create *create) +-{ +- int err; +- unsigned long long ull; +- +- err = 0; +- if (!au_match_ull(arg, &ull)) +- create->mfsrr_watermark = ull; +- else { +- pr_err("bad integer in %s\n", str); +- err = -EINVAL; +- } +- +- return err; +-} +- +-static int au_wbr_mfs_sec(substring_t *arg, char *str, +- struct au_opt_wbr_create *create) +-{ +- int n, err; +- +- err = 0; +- if (!match_int(arg, &n) && 0 <= n && n <= AUFS_MFS_MAX_SEC) +- create->mfs_second = n; +- else { +- pr_err("bad integer in %s\n", str); +- err = -EINVAL; +- } +- +- return err; +-} +- +-static int noinline_for_stack +-au_wbr_create_val(char *str, struct au_opt_wbr_create *create) +-{ +- int err, e; +- substring_t args[MAX_OPT_ARGS]; +- +- err = match_token(str, au_wbr_create_policy, args); +- create->wbr_create = err; +- switch (err) { +- case AuWbrCreate_MFSRRV: +- e = au_wbr_mfs_wmark(&args[0], str, create); +- if (!e) +- e = au_wbr_mfs_sec(&args[1], str, create); +- if (unlikely(e)) +- err = e; +- break; +- case AuWbrCreate_MFSRR: +- e = au_wbr_mfs_wmark(&args[0], str, create); +- if (unlikely(e)) { +- err = e; +- break; +- } +- /*FALLTHROUGH*/ +- case AuWbrCreate_MFS: +- case AuWbrCreate_PMFS: +- create->mfs_second = AUFS_MFS_DEF_SEC; +- break; +- case AuWbrCreate_MFSV: +- case AuWbrCreate_PMFSV: +- e = au_wbr_mfs_sec(&args[0], str, create); +- if (unlikely(e)) +- err = e; +- break; +- } +- +- return err; +-} +- +-const char *au_optstr_wbr_create(int wbr_create) +-{ +- return au_parser_pattern(wbr_create, (void *)au_wbr_create_policy); +-} +- +-static match_table_t au_wbr_copyup_policy = { +- {AuWbrCopyup_TDP, "tdp"}, +- {AuWbrCopyup_TDP, "top-down-parent"}, +- {AuWbrCopyup_BUP, "bup"}, +- {AuWbrCopyup_BUP, "bottom-up-parent"}, +- {AuWbrCopyup_BU, "bu"}, +- {AuWbrCopyup_BU, "bottom-up"}, +- {-1, NULL} +-}; +- +-static int noinline_for_stack au_wbr_copyup_val(char *str) +-{ +- substring_t args[MAX_OPT_ARGS]; +- +- return match_token(str, au_wbr_copyup_policy, args); +-} +- +-const char *au_optstr_wbr_copyup(int wbr_copyup) +-{ +- return au_parser_pattern(wbr_copyup, (void *)au_wbr_copyup_policy); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static const int lkup_dirflags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY; +- +-static void dump_opts(struct au_opts *opts) +-{ +-#ifdef CONFIG_AUFS_DEBUG +- /* reduce stack space */ +- union { +- struct au_opt_add *add; +- struct au_opt_del *del; +- struct au_opt_mod *mod; +- struct au_opt_xino *xino; +- struct au_opt_xino_itrunc *xino_itrunc; +- struct au_opt_wbr_create *create; +- } u; +- struct au_opt *opt; +- +- opt = opts->opt; +- while (opt->type != Opt_tail) { +- switch (opt->type) { +- case Opt_add: +- u.add = &opt->add; +- AuDbg("add {b%d, %s, 0x%x, %p}\n", +- u.add->bindex, u.add->pathname, u.add->perm, +- u.add->path.dentry); +- break; +- case Opt_del: +- case Opt_idel: +- u.del = &opt->del; +- AuDbg("del {%s, %p}\n", +- u.del->pathname, u.del->h_path.dentry); +- break; +- case Opt_mod: +- case Opt_imod: +- u.mod = &opt->mod; +- AuDbg("mod {%s, 0x%x, %p}\n", +- u.mod->path, u.mod->perm, u.mod->h_root); +- break; +- case Opt_append: +- u.add = &opt->add; +- AuDbg("append {b%d, %s, 0x%x, %p}\n", +- u.add->bindex, u.add->pathname, u.add->perm, +- u.add->path.dentry); +- break; +- case Opt_prepend: +- u.add = &opt->add; +- AuDbg("prepend {b%d, %s, 0x%x, %p}\n", +- u.add->bindex, u.add->pathname, u.add->perm, +- u.add->path.dentry); +- break; +- case Opt_dirwh: +- AuDbg("dirwh %d\n", opt->dirwh); +- break; +- case Opt_rdcache: +- AuDbg("rdcache %d\n", opt->rdcache); +- break; +- case Opt_rdblk: +- AuDbg("rdblk %u\n", opt->rdblk); +- break; +- case Opt_rdblk_def: +- AuDbg("rdblk_def\n"); +- break; +- case Opt_rdhash: +- AuDbg("rdhash %u\n", opt->rdhash); +- break; +- case Opt_rdhash_def: +- AuDbg("rdhash_def\n"); +- break; +- case Opt_xino: +- u.xino = &opt->xino; +- AuDbg("xino {%s %.*s}\n", +- u.xino->path, +- AuDLNPair(u.xino->file->f_dentry)); +- break; +- case Opt_trunc_xino: +- AuLabel(trunc_xino); +- break; +- case Opt_notrunc_xino: +- AuLabel(notrunc_xino); +- break; +- case Opt_trunc_xino_path: +- case Opt_itrunc_xino: +- u.xino_itrunc = &opt->xino_itrunc; +- AuDbg("trunc_xino %d\n", u.xino_itrunc->bindex); +- break; +- +- case Opt_noxino: +- AuLabel(noxino); +- break; +- case Opt_trunc_xib: +- AuLabel(trunc_xib); +- break; +- case Opt_notrunc_xib: +- AuLabel(notrunc_xib); +- break; +- case Opt_shwh: +- AuLabel(shwh); +- break; +- case Opt_noshwh: +- AuLabel(noshwh); +- break; +- case Opt_plink: +- AuLabel(plink); +- break; +- case Opt_noplink: +- AuLabel(noplink); +- break; +- case Opt_list_plink: +- AuLabel(list_plink); +- break; +- case Opt_udba: +- AuDbg("udba %d, %s\n", +- opt->udba, au_optstr_udba(opt->udba)); +- break; +- case Opt_dio: +- AuLabel(dio); +- break; +- case Opt_nodio: +- AuLabel(nodio); +- break; +- case Opt_diropq_a: +- AuLabel(diropq_a); +- break; +- case Opt_diropq_w: +- AuLabel(diropq_w); +- break; +- case Opt_warn_perm: +- AuLabel(warn_perm); +- break; +- case Opt_nowarn_perm: +- AuLabel(nowarn_perm); +- break; +- case Opt_refrof: +- AuLabel(refrof); +- break; +- case Opt_norefrof: +- AuLabel(norefrof); +- break; +- case Opt_verbose: +- AuLabel(verbose); +- break; +- case Opt_noverbose: +- AuLabel(noverbose); +- break; +- case Opt_sum: +- AuLabel(sum); +- break; +- case Opt_nosum: +- AuLabel(nosum); +- break; +- case Opt_wsum: +- AuLabel(wsum); +- break; +- case Opt_wbr_create: +- u.create = &opt->wbr_create; +- AuDbg("create %d, %s\n", u.create->wbr_create, +- au_optstr_wbr_create(u.create->wbr_create)); +- switch (u.create->wbr_create) { +- case AuWbrCreate_MFSV: +- case AuWbrCreate_PMFSV: +- AuDbg("%d sec\n", u.create->mfs_second); +- break; +- case AuWbrCreate_MFSRR: +- AuDbg("%llu watermark\n", +- u.create->mfsrr_watermark); +- break; +- case AuWbrCreate_MFSRRV: +- AuDbg("%llu watermark, %d sec\n", +- u.create->mfsrr_watermark, +- u.create->mfs_second); +- break; +- } +- break; +- case Opt_wbr_copyup: +- AuDbg("copyup %d, %s\n", opt->wbr_copyup, +- au_optstr_wbr_copyup(opt->wbr_copyup)); +- break; +- default: +- BUG(); +- } +- opt++; +- } +-#endif +-} +- +-void au_opts_free(struct au_opts *opts) +-{ +- struct au_opt *opt; +- +- opt = opts->opt; +- while (opt->type != Opt_tail) { +- switch (opt->type) { +- case Opt_add: +- case Opt_append: +- case Opt_prepend: +- path_put(&opt->add.path); +- break; +- case Opt_del: +- case Opt_idel: +- path_put(&opt->del.h_path); +- break; +- case Opt_mod: +- case Opt_imod: +- dput(opt->mod.h_root); +- break; +- case Opt_xino: +- fput(opt->xino.file); +- break; +- } +- opt++; +- } +-} +- +-static int opt_add(struct au_opt *opt, char *opt_str, unsigned long sb_flags, +- aufs_bindex_t bindex) +-{ +- int err; +- struct au_opt_add *add = &opt->add; +- char *p; +- +- add->bindex = bindex; +- add->perm = AuBrPerm_RO; +- add->pathname = opt_str; +- p = strchr(opt_str, '='); +- if (p) { +- *p++ = 0; +- if (*p) +- add->perm = br_perm_val(p); +- } +- +- err = vfsub_kern_path(add->pathname, lkup_dirflags, &add->path); +- if (!err) { +- if (!p) { +- add->perm = AuBrPerm_RO; +- if (au_test_fs_rr(add->path.dentry->d_sb)) +- add->perm = AuBrPerm_RR; +- else if (!bindex && !(sb_flags & MS_RDONLY)) +- add->perm = AuBrPerm_RW; +- } +- opt->type = Opt_add; +- goto out; +- } +- pr_err("lookup failed %s (%d)\n", add->pathname, err); +- err = -EINVAL; +- +-out: +- return err; +-} +- +-static int au_opts_parse_del(struct au_opt_del *del, substring_t args[]) +-{ +- int err; +- +- del->pathname = args[0].from; +- AuDbg("del path %s\n", del->pathname); +- +- err = vfsub_kern_path(del->pathname, lkup_dirflags, &del->h_path); +- if (unlikely(err)) +- pr_err("lookup failed %s (%d)\n", del->pathname, err); +- +- return err; +-} +- +-#if 0 /* reserved for future use */ +-static int au_opts_parse_idel(struct super_block *sb, aufs_bindex_t bindex, +- struct au_opt_del *del, substring_t args[]) +-{ +- int err; +- struct dentry *root; +- +- err = -EINVAL; +- root = sb->s_root; +- aufs_read_lock(root, AuLock_FLUSH); +- if (bindex < 0 || au_sbend(sb) < bindex) { +- pr_err("out of bounds, %d\n", bindex); +- goto out; +- } +- +- err = 0; +- del->h_path.dentry = dget(au_h_dptr(root, bindex)); +- del->h_path.mnt = mntget(au_sbr_mnt(sb, bindex)); +- +-out: +- aufs_read_unlock(root, !AuLock_IR); +- return err; +-} +-#endif +- +-static int noinline_for_stack +-au_opts_parse_mod(struct au_opt_mod *mod, substring_t args[]) +-{ +- int err; +- struct path path; +- char *p; +- +- err = -EINVAL; +- mod->path = args[0].from; +- p = strchr(mod->path, '='); +- if (unlikely(!p)) { +- pr_err("no permssion %s\n", args[0].from); +- goto out; +- } +- +- *p++ = 0; +- err = vfsub_kern_path(mod->path, lkup_dirflags, &path); +- if (unlikely(err)) { +- pr_err("lookup failed %s (%d)\n", mod->path, err); +- goto out; +- } +- +- mod->perm = br_perm_val(p); +- AuDbg("mod path %s, perm 0x%x, %s\n", mod->path, mod->perm, p); +- mod->h_root = dget(path.dentry); +- path_put(&path); +- +-out: +- return err; +-} +- +-#if 0 /* reserved for future use */ +-static int au_opts_parse_imod(struct super_block *sb, aufs_bindex_t bindex, +- struct au_opt_mod *mod, substring_t args[]) +-{ +- int err; +- struct dentry *root; +- +- err = -EINVAL; +- root = sb->s_root; +- aufs_read_lock(root, AuLock_FLUSH); +- if (bindex < 0 || au_sbend(sb) < bindex) { +- pr_err("out of bounds, %d\n", bindex); +- goto out; +- } +- +- err = 0; +- mod->perm = br_perm_val(args[1].from); +- AuDbg("mod path %s, perm 0x%x, %s\n", +- mod->path, mod->perm, args[1].from); +- mod->h_root = dget(au_h_dptr(root, bindex)); +- +-out: +- aufs_read_unlock(root, !AuLock_IR); +- return err; +-} +-#endif +- +-static int au_opts_parse_xino(struct super_block *sb, struct au_opt_xino *xino, +- substring_t args[]) +-{ +- int err; +- struct file *file; +- +- file = au_xino_create(sb, args[0].from, /*silent*/0); +- err = PTR_ERR(file); +- if (IS_ERR(file)) +- goto out; +- +- err = -EINVAL; +- if (unlikely(file->f_dentry->d_sb == sb)) { +- fput(file); +- pr_err("%s must be outside\n", args[0].from); +- goto out; +- } +- +- err = 0; +- xino->file = file; +- xino->path = args[0].from; +- +-out: +- return err; +-} +- +-static int noinline_for_stack +-au_opts_parse_xino_itrunc_path(struct super_block *sb, +- struct au_opt_xino_itrunc *xino_itrunc, +- substring_t args[]) +-{ +- int err; +- aufs_bindex_t bend, bindex; +- struct path path; +- struct dentry *root; +- +- err = vfsub_kern_path(args[0].from, lkup_dirflags, &path); +- if (unlikely(err)) { +- pr_err("lookup failed %s (%d)\n", args[0].from, err); +- goto out; +- } +- +- xino_itrunc->bindex = -1; +- root = sb->s_root; +- aufs_read_lock(root, AuLock_FLUSH); +- bend = au_sbend(sb); +- for (bindex = 0; bindex <= bend; bindex++) { +- if (au_h_dptr(root, bindex) == path.dentry) { +- xino_itrunc->bindex = bindex; +- break; +- } +- } +- aufs_read_unlock(root, !AuLock_IR); +- path_put(&path); +- +- if (unlikely(xino_itrunc->bindex < 0)) { +- pr_err("no such branch %s\n", args[0].from); +- err = -EINVAL; +- } +- +-out: +- return err; +-} +- +-/* called without aufs lock */ +-int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts) +-{ +- int err, n, token; +- aufs_bindex_t bindex; +- unsigned char skipped; +- struct dentry *root; +- struct au_opt *opt, *opt_tail; +- char *opt_str; +- /* reduce the stack space */ +- union { +- struct au_opt_xino_itrunc *xino_itrunc; +- struct au_opt_wbr_create *create; +- } u; +- struct { +- substring_t args[MAX_OPT_ARGS]; +- } *a; +- +- err = -ENOMEM; +- a = kmalloc(sizeof(*a), GFP_NOFS); +- if (unlikely(!a)) +- goto out; +- +- root = sb->s_root; +- err = 0; +- bindex = 0; +- opt = opts->opt; +- opt_tail = opt + opts->max_opt - 1; +- opt->type = Opt_tail; +- while (!err && (opt_str = strsep(&str, ",")) && *opt_str) { +- err = -EINVAL; +- skipped = 0; +- token = match_token(opt_str, options, a->args); +- switch (token) { +- case Opt_br: +- err = 0; +- while (!err && (opt_str = strsep(&a->args[0].from, ":")) +- && *opt_str) { +- err = opt_add(opt, opt_str, opts->sb_flags, +- bindex++); +- if (unlikely(!err && ++opt > opt_tail)) { +- err = -E2BIG; +- break; +- } +- opt->type = Opt_tail; +- skipped = 1; +- } +- break; +- case Opt_add: +- if (unlikely(match_int(&a->args[0], &n))) { +- pr_err("bad integer in %s\n", opt_str); +- break; +- } +- bindex = n; +- err = opt_add(opt, a->args[1].from, opts->sb_flags, +- bindex); +- if (!err) +- opt->type = token; +- break; +- case Opt_append: +- err = opt_add(opt, a->args[0].from, opts->sb_flags, +- /*dummy bindex*/1); +- if (!err) +- opt->type = token; +- break; +- case Opt_prepend: +- err = opt_add(opt, a->args[0].from, opts->sb_flags, +- /*bindex*/0); +- if (!err) +- opt->type = token; +- break; +- case Opt_del: +- err = au_opts_parse_del(&opt->del, a->args); +- if (!err) +- opt->type = token; +- break; +-#if 0 /* reserved for future use */ +- case Opt_idel: +- del->pathname = "(indexed)"; +- if (unlikely(match_int(&args[0], &n))) { +- pr_err("bad integer in %s\n", opt_str); +- break; +- } +- err = au_opts_parse_idel(sb, n, &opt->del, a->args); +- if (!err) +- opt->type = token; +- break; +-#endif +- case Opt_mod: +- err = au_opts_parse_mod(&opt->mod, a->args); +- if (!err) +- opt->type = token; +- break; +-#ifdef IMOD /* reserved for future use */ +- case Opt_imod: +- u.mod->path = "(indexed)"; +- if (unlikely(match_int(&a->args[0], &n))) { +- pr_err("bad integer in %s\n", opt_str); +- break; +- } +- err = au_opts_parse_imod(sb, n, &opt->mod, a->args); +- if (!err) +- opt->type = token; +- break; +-#endif +- case Opt_xino: +- err = au_opts_parse_xino(sb, &opt->xino, a->args); +- if (!err) +- opt->type = token; +- break; +- +- case Opt_trunc_xino_path: +- err = au_opts_parse_xino_itrunc_path +- (sb, &opt->xino_itrunc, a->args); +- if (!err) +- opt->type = token; +- break; +- +- case Opt_itrunc_xino: +- u.xino_itrunc = &opt->xino_itrunc; +- if (unlikely(match_int(&a->args[0], &n))) { +- pr_err("bad integer in %s\n", opt_str); +- break; +- } +- u.xino_itrunc->bindex = n; +- aufs_read_lock(root, AuLock_FLUSH); +- if (n < 0 || au_sbend(sb) < n) { +- pr_err("out of bounds, %d\n", n); +- aufs_read_unlock(root, !AuLock_IR); +- break; +- } +- aufs_read_unlock(root, !AuLock_IR); +- err = 0; +- opt->type = token; +- break; +- +- case Opt_dirwh: +- if (unlikely(match_int(&a->args[0], &opt->dirwh))) +- break; +- err = 0; +- opt->type = token; +- break; +- +- case Opt_rdcache: +- if (unlikely(match_int(&a->args[0], &n))) { +- pr_err("bad integer in %s\n", opt_str); +- break; +- } +- if (unlikely(n > AUFS_RDCACHE_MAX)) { +- pr_err("rdcache must be smaller than %d\n", +- AUFS_RDCACHE_MAX); +- break; +- } +- opt->rdcache = n; +- err = 0; +- opt->type = token; +- break; +- case Opt_rdblk: +- if (unlikely(match_int(&a->args[0], &n) +- || n < 0 +- || n > KMALLOC_MAX_SIZE)) { +- pr_err("bad integer in %s\n", opt_str); +- break; +- } +- if (unlikely(n && n < NAME_MAX)) { +- pr_err("rdblk must be larger than %d\n", +- NAME_MAX); +- break; +- } +- opt->rdblk = n; +- err = 0; +- opt->type = token; +- break; +- case Opt_rdhash: +- if (unlikely(match_int(&a->args[0], &n) +- || n < 0 +- || n * sizeof(struct hlist_head) +- > KMALLOC_MAX_SIZE)) { +- pr_err("bad integer in %s\n", opt_str); +- break; +- } +- opt->rdhash = n; +- err = 0; +- opt->type = token; +- break; +- +- case Opt_trunc_xino: +- case Opt_notrunc_xino: +- case Opt_noxino: +- case Opt_trunc_xib: +- case Opt_notrunc_xib: +- case Opt_shwh: +- case Opt_noshwh: +- case Opt_plink: +- case Opt_noplink: +- case Opt_list_plink: +- case Opt_dio: +- case Opt_nodio: +- case Opt_diropq_a: +- case Opt_diropq_w: +- case Opt_warn_perm: +- case Opt_nowarn_perm: +- case Opt_refrof: +- case Opt_norefrof: +- case Opt_verbose: +- case Opt_noverbose: +- case Opt_sum: +- case Opt_nosum: +- case Opt_wsum: +- case Opt_rdblk_def: +- case Opt_rdhash_def: +- err = 0; +- opt->type = token; +- break; +- +- case Opt_udba: +- opt->udba = udba_val(a->args[0].from); +- if (opt->udba >= 0) { +- err = 0; +- opt->type = token; +- } else +- pr_err("wrong value, %s\n", opt_str); +- break; +- +- case Opt_wbr_create: +- u.create = &opt->wbr_create; +- u.create->wbr_create +- = au_wbr_create_val(a->args[0].from, u.create); +- if (u.create->wbr_create >= 0) { +- err = 0; +- opt->type = token; +- } else +- pr_err("wrong value, %s\n", opt_str); +- break; +- case Opt_wbr_copyup: +- opt->wbr_copyup = au_wbr_copyup_val(a->args[0].from); +- if (opt->wbr_copyup >= 0) { +- err = 0; +- opt->type = token; +- } else +- pr_err("wrong value, %s\n", opt_str); +- break; +- +- case Opt_ignore: +- pr_warn("ignored %s\n", opt_str); +- /*FALLTHROUGH*/ +- case Opt_ignore_silent: +- skipped = 1; +- err = 0; +- break; +- case Opt_err: +- pr_err("unknown option %s\n", opt_str); +- break; +- } +- +- if (!err && !skipped) { +- if (unlikely(++opt > opt_tail)) { +- err = -E2BIG; +- opt--; +- opt->type = Opt_tail; +- break; +- } +- opt->type = Opt_tail; +- } +- } +- +- kfree(a); +- dump_opts(opts); +- if (unlikely(err)) +- au_opts_free(opts); +- +-out: +- return err; +-} +- +-static int au_opt_wbr_create(struct super_block *sb, +- struct au_opt_wbr_create *create) +-{ +- int err; +- struct au_sbinfo *sbinfo; +- +- SiMustWriteLock(sb); +- +- err = 1; /* handled */ +- sbinfo = au_sbi(sb); +- if (sbinfo->si_wbr_create_ops->fin) { +- err = sbinfo->si_wbr_create_ops->fin(sb); +- if (!err) +- err = 1; +- } +- +- sbinfo->si_wbr_create = create->wbr_create; +- sbinfo->si_wbr_create_ops = au_wbr_create_ops + create->wbr_create; +- switch (create->wbr_create) { +- case AuWbrCreate_MFSRRV: +- case AuWbrCreate_MFSRR: +- sbinfo->si_wbr_mfs.mfsrr_watermark = create->mfsrr_watermark; +- /*FALLTHROUGH*/ +- case AuWbrCreate_MFS: +- case AuWbrCreate_MFSV: +- case AuWbrCreate_PMFS: +- case AuWbrCreate_PMFSV: +- sbinfo->si_wbr_mfs.mfs_expire +- = msecs_to_jiffies(create->mfs_second * MSEC_PER_SEC); +- break; +- } +- +- if (sbinfo->si_wbr_create_ops->init) +- sbinfo->si_wbr_create_ops->init(sb); /* ignore */ +- +- return err; +-} +- +-/* +- * returns, +- * plus: processed without an error +- * zero: unprocessed +- */ +-static int au_opt_simple(struct super_block *sb, struct au_opt *opt, +- struct au_opts *opts) +-{ +- int err; +- struct au_sbinfo *sbinfo; +- +- SiMustWriteLock(sb); +- +- err = 1; /* handled */ +- sbinfo = au_sbi(sb); +- switch (opt->type) { +- case Opt_udba: +- sbinfo->si_mntflags &= ~AuOptMask_UDBA; +- sbinfo->si_mntflags |= opt->udba; +- opts->given_udba |= opt->udba; +- break; +- +- case Opt_plink: +- au_opt_set(sbinfo->si_mntflags, PLINK); +- break; +- case Opt_noplink: +- if (au_opt_test(sbinfo->si_mntflags, PLINK)) +- au_plink_put(sb, /*verbose*/1); +- au_opt_clr(sbinfo->si_mntflags, PLINK); +- break; +- case Opt_list_plink: +- if (au_opt_test(sbinfo->si_mntflags, PLINK)) +- au_plink_list(sb); +- break; +- +- case Opt_dio: +- au_opt_set(sbinfo->si_mntflags, DIO); +- au_fset_opts(opts->flags, REFRESH_DYAOP); +- break; +- case Opt_nodio: +- au_opt_clr(sbinfo->si_mntflags, DIO); +- au_fset_opts(opts->flags, REFRESH_DYAOP); +- break; +- +- case Opt_diropq_a: +- au_opt_set(sbinfo->si_mntflags, ALWAYS_DIROPQ); +- break; +- case Opt_diropq_w: +- au_opt_clr(sbinfo->si_mntflags, ALWAYS_DIROPQ); +- break; +- +- case Opt_warn_perm: +- au_opt_set(sbinfo->si_mntflags, WARN_PERM); +- break; +- case Opt_nowarn_perm: +- au_opt_clr(sbinfo->si_mntflags, WARN_PERM); +- break; +- +- case Opt_refrof: +- au_opt_set(sbinfo->si_mntflags, REFROF); +- break; +- case Opt_norefrof: +- au_opt_clr(sbinfo->si_mntflags, REFROF); +- break; +- +- case Opt_verbose: +- au_opt_set(sbinfo->si_mntflags, VERBOSE); +- break; +- case Opt_noverbose: +- au_opt_clr(sbinfo->si_mntflags, VERBOSE); +- break; +- +- case Opt_sum: +- au_opt_set(sbinfo->si_mntflags, SUM); +- break; +- case Opt_wsum: +- au_opt_clr(sbinfo->si_mntflags, SUM); +- au_opt_set(sbinfo->si_mntflags, SUM_W); +- case Opt_nosum: +- au_opt_clr(sbinfo->si_mntflags, SUM); +- au_opt_clr(sbinfo->si_mntflags, SUM_W); +- break; +- +- case Opt_wbr_create: +- err = au_opt_wbr_create(sb, &opt->wbr_create); +- break; +- case Opt_wbr_copyup: +- sbinfo->si_wbr_copyup = opt->wbr_copyup; +- sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + opt->wbr_copyup; +- break; +- +- case Opt_dirwh: +- sbinfo->si_dirwh = opt->dirwh; +- break; +- +- case Opt_rdcache: +- sbinfo->si_rdcache +- = msecs_to_jiffies(opt->rdcache * MSEC_PER_SEC); +- break; +- case Opt_rdblk: +- sbinfo->si_rdblk = opt->rdblk; +- break; +- case Opt_rdblk_def: +- sbinfo->si_rdblk = AUFS_RDBLK_DEF; +- break; +- case Opt_rdhash: +- sbinfo->si_rdhash = opt->rdhash; +- break; +- case Opt_rdhash_def: +- sbinfo->si_rdhash = AUFS_RDHASH_DEF; +- break; +- +- case Opt_shwh: +- au_opt_set(sbinfo->si_mntflags, SHWH); +- break; +- case Opt_noshwh: +- au_opt_clr(sbinfo->si_mntflags, SHWH); +- break; +- +- case Opt_trunc_xino: +- au_opt_set(sbinfo->si_mntflags, TRUNC_XINO); +- break; +- case Opt_notrunc_xino: +- au_opt_clr(sbinfo->si_mntflags, TRUNC_XINO); +- break; +- +- case Opt_trunc_xino_path: +- case Opt_itrunc_xino: +- err = au_xino_trunc(sb, opt->xino_itrunc.bindex); +- if (!err) +- err = 1; +- break; +- +- case Opt_trunc_xib: +- au_fset_opts(opts->flags, TRUNC_XIB); +- break; +- case Opt_notrunc_xib: +- au_fclr_opts(opts->flags, TRUNC_XIB); +- break; +- +- default: +- err = 0; +- break; +- } +- +- return err; +-} +- +-/* +- * returns tri-state. +- * plus: processed without an error +- * zero: unprocessed +- * minus: error +- */ +-static int au_opt_br(struct super_block *sb, struct au_opt *opt, +- struct au_opts *opts) +-{ +- int err, do_refresh; +- +- err = 0; +- switch (opt->type) { +- case Opt_append: +- opt->add.bindex = au_sbend(sb) + 1; +- if (opt->add.bindex < 0) +- opt->add.bindex = 0; +- goto add; +- case Opt_prepend: +- opt->add.bindex = 0; +- add: +- case Opt_add: +- err = au_br_add(sb, &opt->add, +- au_ftest_opts(opts->flags, REMOUNT)); +- if (!err) { +- err = 1; +- au_fset_opts(opts->flags, REFRESH); +- } +- break; +- +- case Opt_del: +- case Opt_idel: +- err = au_br_del(sb, &opt->del, +- au_ftest_opts(opts->flags, REMOUNT)); +- if (!err) { +- err = 1; +- au_fset_opts(opts->flags, TRUNC_XIB); +- au_fset_opts(opts->flags, REFRESH); +- } +- break; +- +- case Opt_mod: +- case Opt_imod: +- err = au_br_mod(sb, &opt->mod, +- au_ftest_opts(opts->flags, REMOUNT), +- &do_refresh); +- if (!err) { +- err = 1; +- if (do_refresh) +- au_fset_opts(opts->flags, REFRESH); +- } +- break; +- } +- +- return err; +-} +- +-static int au_opt_xino(struct super_block *sb, struct au_opt *opt, +- struct au_opt_xino **opt_xino, +- struct au_opts *opts) +-{ +- int err; +- aufs_bindex_t bend, bindex; +- struct dentry *root, *parent, *h_root; +- +- err = 0; +- switch (opt->type) { +- case Opt_xino: +- err = au_xino_set(sb, &opt->xino, +- !!au_ftest_opts(opts->flags, REMOUNT)); +- if (unlikely(err)) +- break; +- +- *opt_xino = &opt->xino; +- au_xino_brid_set(sb, -1); +- +- /* safe d_parent access */ +- parent = opt->xino.file->f_dentry->d_parent; +- root = sb->s_root; +- bend = au_sbend(sb); +- for (bindex = 0; bindex <= bend; bindex++) { +- h_root = au_h_dptr(root, bindex); +- if (h_root == parent) { +- au_xino_brid_set(sb, au_sbr_id(sb, bindex)); +- break; +- } +- } +- break; +- +- case Opt_noxino: +- au_xino_clr(sb); +- au_xino_brid_set(sb, -1); +- *opt_xino = (void *)-1; +- break; +- } +- +- return err; +-} +- +-int au_opts_verify(struct super_block *sb, unsigned long sb_flags, +- unsigned int pending) +-{ +- int err; +- aufs_bindex_t bindex, bend; +- unsigned char do_plink, skip, do_free; +- struct au_branch *br; +- struct au_wbr *wbr; +- struct dentry *root; +- struct inode *dir, *h_dir; +- struct au_sbinfo *sbinfo; +- struct au_hinode *hdir; +- +- SiMustAnyLock(sb); +- +- sbinfo = au_sbi(sb); +- AuDebugOn(!(sbinfo->si_mntflags & AuOptMask_UDBA)); +- +- if (!(sb_flags & MS_RDONLY)) { +- if (unlikely(!au_br_writable(au_sbr_perm(sb, 0)))) +- pr_warn("first branch should be rw\n"); +- if (unlikely(au_opt_test(sbinfo->si_mntflags, SHWH))) +- pr_warn("shwh should be used with ro\n"); +- } +- +- if (au_opt_test((sbinfo->si_mntflags | pending), UDBA_HNOTIFY) +- && !au_opt_test(sbinfo->si_mntflags, XINO)) +- pr_warn("udba=*notify requires xino\n"); +- +- err = 0; +- root = sb->s_root; +- dir = root->d_inode; +- do_plink = !!au_opt_test(sbinfo->si_mntflags, PLINK); +- bend = au_sbend(sb); +- for (bindex = 0; !err && bindex <= bend; bindex++) { +- skip = 0; +- h_dir = au_h_iptr(dir, bindex); +- br = au_sbr(sb, bindex); +- do_free = 0; +- +- wbr = br->br_wbr; +- if (wbr) +- wbr_wh_read_lock(wbr); +- +- if (!au_br_writable(br->br_perm)) { +- do_free = !!wbr; +- skip = (!wbr +- || (!wbr->wbr_whbase +- && !wbr->wbr_plink +- && !wbr->wbr_orph)); +- } else if (!au_br_wh_linkable(br->br_perm)) { +- /* skip = (!br->br_whbase && !br->br_orph); */ +- skip = (!wbr || !wbr->wbr_whbase); +- if (skip && wbr) { +- if (do_plink) +- skip = !!wbr->wbr_plink; +- else +- skip = !wbr->wbr_plink; +- } +- } else { +- /* skip = (br->br_whbase && br->br_ohph); */ +- skip = (wbr && wbr->wbr_whbase); +- if (skip) { +- if (do_plink) +- skip = !!wbr->wbr_plink; +- else +- skip = !wbr->wbr_plink; +- } +- } +- if (wbr) +- wbr_wh_read_unlock(wbr); +- +- if (skip) +- continue; +- +- hdir = au_hi(dir, bindex); +- au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT); +- if (wbr) +- wbr_wh_write_lock(wbr); +- err = au_wh_init(au_h_dptr(root, bindex), br, sb); +- if (wbr) +- wbr_wh_write_unlock(wbr); +- au_hn_imtx_unlock(hdir); +- +- if (!err && do_free) { +- kfree(wbr); +- br->br_wbr = NULL; +- } +- } +- +- return err; +-} +- +-int au_opts_mount(struct super_block *sb, struct au_opts *opts) +-{ +- int err; +- unsigned int tmp; +- aufs_bindex_t bindex, bend; +- struct au_opt *opt; +- struct au_opt_xino *opt_xino, xino; +- struct au_sbinfo *sbinfo; +- struct au_branch *br; +- +- SiMustWriteLock(sb); +- +- err = 0; +- opt_xino = NULL; +- opt = opts->opt; +- while (err >= 0 && opt->type != Opt_tail) +- err = au_opt_simple(sb, opt++, opts); +- if (err > 0) +- err = 0; +- else if (unlikely(err < 0)) +- goto out; +- +- /* disable xino and udba temporary */ +- sbinfo = au_sbi(sb); +- tmp = sbinfo->si_mntflags; +- au_opt_clr(sbinfo->si_mntflags, XINO); +- au_opt_set_udba(sbinfo->si_mntflags, UDBA_REVAL); +- +- opt = opts->opt; +- while (err >= 0 && opt->type != Opt_tail) +- err = au_opt_br(sb, opt++, opts); +- if (err > 0) +- err = 0; +- else if (unlikely(err < 0)) +- goto out; +- +- bend = au_sbend(sb); +- if (unlikely(bend < 0)) { +- err = -EINVAL; +- pr_err("no branches\n"); +- goto out; +- } +- +- if (au_opt_test(tmp, XINO)) +- au_opt_set(sbinfo->si_mntflags, XINO); +- opt = opts->opt; +- while (!err && opt->type != Opt_tail) +- err = au_opt_xino(sb, opt++, &opt_xino, opts); +- if (unlikely(err)) +- goto out; +- +- err = au_opts_verify(sb, sb->s_flags, tmp); +- if (unlikely(err)) +- goto out; +- +- /* restore xino */ +- if (au_opt_test(tmp, XINO) && !opt_xino) { +- xino.file = au_xino_def(sb); +- err = PTR_ERR(xino.file); +- if (IS_ERR(xino.file)) +- goto out; +- +- err = au_xino_set(sb, &xino, /*remount*/0); +- fput(xino.file); +- if (unlikely(err)) +- goto out; +- } +- +- /* restore udba */ +- tmp &= AuOptMask_UDBA; +- sbinfo->si_mntflags &= ~AuOptMask_UDBA; +- sbinfo->si_mntflags |= tmp; +- bend = au_sbend(sb); +- for (bindex = 0; bindex <= bend; bindex++) { +- br = au_sbr(sb, bindex); +- err = au_hnotify_reset_br(tmp, br, br->br_perm); +- if (unlikely(err)) +- AuIOErr("hnotify failed on br %d, %d, ignored\n", +- bindex, err); +- /* go on even if err */ +- } +- if (au_opt_test(tmp, UDBA_HNOTIFY)) { +- struct inode *dir = sb->s_root->d_inode; +- au_hn_reset(dir, au_hi_flags(dir, /*isdir*/1) & ~AuHi_XINO); +- } +- +-out: +- return err; +-} +- +-int au_opts_remount(struct super_block *sb, struct au_opts *opts) +-{ +- int err, rerr; +- struct inode *dir; +- struct au_opt_xino *opt_xino; +- struct au_opt *opt; +- struct au_sbinfo *sbinfo; +- +- SiMustWriteLock(sb); +- +- dir = sb->s_root->d_inode; +- sbinfo = au_sbi(sb); +- err = 0; +- opt_xino = NULL; +- opt = opts->opt; +- while (err >= 0 && opt->type != Opt_tail) { +- err = au_opt_simple(sb, opt, opts); +- if (!err) +- err = au_opt_br(sb, opt, opts); +- if (!err) +- err = au_opt_xino(sb, opt, &opt_xino, opts); +- opt++; +- } +- if (err > 0) +- err = 0; +- AuTraceErr(err); +- /* go on even err */ +- +- rerr = au_opts_verify(sb, opts->sb_flags, /*pending*/0); +- if (unlikely(rerr && !err)) +- err = rerr; +- +- if (au_ftest_opts(opts->flags, TRUNC_XIB)) { +- rerr = au_xib_trunc(sb); +- if (unlikely(rerr && !err)) +- err = rerr; +- } +- +- /* will be handled by the caller */ +- if (!au_ftest_opts(opts->flags, REFRESH) +- && (opts->given_udba || au_opt_test(sbinfo->si_mntflags, XINO))) +- au_fset_opts(opts->flags, REFRESH); +- +- AuDbg("status 0x%x\n", opts->flags); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-unsigned int au_opt_udba(struct super_block *sb) +-{ +- return au_mntflags(sb) & AuOptMask_UDBA; +-} +diff --git a/fs/aufs/opts.h b/fs/aufs/opts.h +deleted file mode 100644 +index e2f1803..0000000 +--- a/fs/aufs/opts.h ++++ /dev/null +@@ -1,209 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * mount options/flags +- */ +- +-#ifndef __AUFS_OPTS_H__ +-#define __AUFS_OPTS_H__ +- +-#ifdef __KERNEL__ +- +-#include +- +-struct file; +-struct super_block; +- +-/* ---------------------------------------------------------------------- */ +- +-/* mount flags */ +-#define AuOpt_XINO 1 /* external inode number bitmap +- and translation table */ +-#define AuOpt_TRUNC_XINO (1 << 1) /* truncate xino files */ +-#define AuOpt_UDBA_NONE (1 << 2) /* users direct branch access */ +-#define AuOpt_UDBA_REVAL (1 << 3) +-#define AuOpt_UDBA_HNOTIFY (1 << 4) +-#define AuOpt_SHWH (1 << 5) /* show whiteout */ +-#define AuOpt_PLINK (1 << 6) /* pseudo-link */ +-#define AuOpt_DIRPERM1 (1 << 7) /* unimplemented */ +-#define AuOpt_REFROF (1 << 8) /* unimplemented */ +-#define AuOpt_ALWAYS_DIROPQ (1 << 9) /* policy to creating diropq */ +-#define AuOpt_SUM (1 << 10) /* summation for statfs(2) */ +-#define AuOpt_SUM_W (1 << 11) /* unimplemented */ +-#define AuOpt_WARN_PERM (1 << 12) /* warn when add-branch */ +-#define AuOpt_VERBOSE (1 << 13) /* busy inode when del-branch */ +-#define AuOpt_DIO (1 << 14) /* direct io */ +- +-#ifndef CONFIG_AUFS_HNOTIFY +-#undef AuOpt_UDBA_HNOTIFY +-#define AuOpt_UDBA_HNOTIFY 0 +-#endif +-#ifndef CONFIG_AUFS_SHWH +-#undef AuOpt_SHWH +-#define AuOpt_SHWH 0 +-#endif +- +-#define AuOpt_Def (AuOpt_XINO \ +- | AuOpt_UDBA_REVAL \ +- | AuOpt_PLINK \ +- /* | AuOpt_DIRPERM1 */ \ +- | AuOpt_WARN_PERM) +-#define AuOptMask_UDBA (AuOpt_UDBA_NONE \ +- | AuOpt_UDBA_REVAL \ +- | AuOpt_UDBA_HNOTIFY) +- +-#define au_opt_test(flags, name) (flags & AuOpt_##name) +-#define au_opt_set(flags, name) do { \ +- BUILD_BUG_ON(AuOpt_##name & AuOptMask_UDBA); \ +- ((flags) |= AuOpt_##name); \ +-} while (0) +-#define au_opt_set_udba(flags, name) do { \ +- (flags) &= ~AuOptMask_UDBA; \ +- ((flags) |= AuOpt_##name); \ +-} while (0) +-#define au_opt_clr(flags, name) do { \ +- ((flags) &= ~AuOpt_##name); \ +-} while (0) +- +-static inline unsigned int au_opts_plink(unsigned int mntflags) +-{ +-#ifdef CONFIG_PROC_FS +- return mntflags; +-#else +- return mntflags & ~AuOpt_PLINK; +-#endif +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* policies to select one among multiple writable branches */ +-enum { +- AuWbrCreate_TDP, /* top down parent */ +- AuWbrCreate_RR, /* round robin */ +- AuWbrCreate_MFS, /* most free space */ +- AuWbrCreate_MFSV, /* mfs with seconds */ +- AuWbrCreate_MFSRR, /* mfs then rr */ +- AuWbrCreate_MFSRRV, /* mfs then rr with seconds */ +- AuWbrCreate_PMFS, /* parent and mfs */ +- AuWbrCreate_PMFSV, /* parent and mfs with seconds */ +- +- AuWbrCreate_Def = AuWbrCreate_TDP +-}; +- +-enum { +- AuWbrCopyup_TDP, /* top down parent */ +- AuWbrCopyup_BUP, /* bottom up parent */ +- AuWbrCopyup_BU, /* bottom up */ +- +- AuWbrCopyup_Def = AuWbrCopyup_TDP +-}; +- +-/* ---------------------------------------------------------------------- */ +- +-struct au_opt_add { +- aufs_bindex_t bindex; +- char *pathname; +- int perm; +- struct path path; +-}; +- +-struct au_opt_del { +- char *pathname; +- struct path h_path; +-}; +- +-struct au_opt_mod { +- char *path; +- int perm; +- struct dentry *h_root; +-}; +- +-struct au_opt_xino { +- char *path; +- struct file *file; +-}; +- +-struct au_opt_xino_itrunc { +- aufs_bindex_t bindex; +-}; +- +-struct au_opt_wbr_create { +- int wbr_create; +- int mfs_second; +- unsigned long long mfsrr_watermark; +-}; +- +-struct au_opt { +- int type; +- union { +- struct au_opt_xino xino; +- struct au_opt_xino_itrunc xino_itrunc; +- struct au_opt_add add; +- struct au_opt_del del; +- struct au_opt_mod mod; +- int dirwh; +- int rdcache; +- unsigned int rdblk; +- unsigned int rdhash; +- int udba; +- struct au_opt_wbr_create wbr_create; +- int wbr_copyup; +- }; +-}; +- +-/* opts flags */ +-#define AuOpts_REMOUNT 1 +-#define AuOpts_REFRESH (1 << 1) +-#define AuOpts_TRUNC_XIB (1 << 2) +-#define AuOpts_REFRESH_DYAOP (1 << 3) +-#define au_ftest_opts(flags, name) ((flags) & AuOpts_##name) +-#define au_fset_opts(flags, name) \ +- do { (flags) |= AuOpts_##name; } while (0) +-#define au_fclr_opts(flags, name) \ +- do { (flags) &= ~AuOpts_##name; } while (0) +- +-struct au_opts { +- struct au_opt *opt; +- int max_opt; +- +- unsigned int given_udba; +- unsigned int flags; +- unsigned long sb_flags; +-}; +- +-/* ---------------------------------------------------------------------- */ +- +-char *au_optstr_br_perm(int brperm); +-const char *au_optstr_udba(int udba); +-const char *au_optstr_wbr_copyup(int wbr_copyup); +-const char *au_optstr_wbr_create(int wbr_create); +- +-void au_opts_free(struct au_opts *opts); +-int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts); +-int au_opts_verify(struct super_block *sb, unsigned long sb_flags, +- unsigned int pending); +-int au_opts_mount(struct super_block *sb, struct au_opts *opts); +-int au_opts_remount(struct super_block *sb, struct au_opts *opts); +- +-unsigned int au_opt_udba(struct super_block *sb); +- +-/* ---------------------------------------------------------------------- */ +- +-#endif /* __KERNEL__ */ +-#endif /* __AUFS_OPTS_H__ */ +diff --git a/fs/aufs/plink.c b/fs/aufs/plink.c +deleted file mode 100644 +index 7121d4f..0000000 +--- a/fs/aufs/plink.c ++++ /dev/null +@@ -1,511 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * pseudo-link +- */ +- +-#include "aufs.h" +- +-/* +- * the pseudo-link maintenance mode. +- * during a user process maintains the pseudo-links, +- * prohibit adding a new plink and branch manipulation. +- * +- * Flags +- * NOPLM: +- * For entry functions which will handle plink, and i_mutex is already held +- * in VFS. +- * They cannot wait and should return an error at once. +- * Callers has to check the error. +- * NOPLMW: +- * For entry functions which will handle plink, but i_mutex is not held +- * in VFS. +- * They can wait the plink maintenance mode to finish. +- * +- * They behave like F_SETLK and F_SETLKW. +- * If the caller never handle plink, then both flags are unnecessary. +- */ +- +-int au_plink_maint(struct super_block *sb, int flags) +-{ +- int err; +- pid_t pid, ppid; +- struct au_sbinfo *sbi; +- +- SiMustAnyLock(sb); +- +- err = 0; +- if (!au_opt_test(au_mntflags(sb), PLINK)) +- goto out; +- +- sbi = au_sbi(sb); +- pid = sbi->si_plink_maint_pid; +- if (!pid || pid == current->pid) +- goto out; +- +- /* todo: it highly depends upon /sbin/mount.aufs */ +- rcu_read_lock(); +- ppid = task_pid_vnr(rcu_dereference(current->real_parent)); +- rcu_read_unlock(); +- if (pid == ppid) +- goto out; +- +- if (au_ftest_lock(flags, NOPLMW)) { +- /* if there is no i_mutex lock in VFS, we don't need to wait */ +- /* AuDebugOn(!lockdep_depth(current)); */ +- while (sbi->si_plink_maint_pid) { +- si_read_unlock(sb); +- /* gave up wake_up_bit() */ +- wait_event(sbi->si_plink_wq, !sbi->si_plink_maint_pid); +- +- if (au_ftest_lock(flags, FLUSH)) +- au_nwt_flush(&sbi->si_nowait); +- si_noflush_read_lock(sb); +- } +- } else if (au_ftest_lock(flags, NOPLM)) { +- AuDbg("ppid %d, pid %d\n", ppid, pid); +- err = -EAGAIN; +- } +- +-out: +- return err; +-} +- +-void au_plink_maint_leave(struct au_sbinfo *sbinfo) +-{ +- spin_lock(&sbinfo->si_plink_maint_lock); +- sbinfo->si_plink_maint_pid = 0; +- spin_unlock(&sbinfo->si_plink_maint_lock); +- wake_up_all(&sbinfo->si_plink_wq); +-} +- +-int au_plink_maint_enter(struct super_block *sb) +-{ +- int err; +- struct au_sbinfo *sbinfo; +- +- err = 0; +- sbinfo = au_sbi(sb); +- /* make sure i am the only one in this fs */ +- si_write_lock(sb, AuLock_FLUSH); +- if (au_opt_test(au_mntflags(sb), PLINK)) { +- spin_lock(&sbinfo->si_plink_maint_lock); +- if (!sbinfo->si_plink_maint_pid) +- sbinfo->si_plink_maint_pid = current->pid; +- else +- err = -EBUSY; +- spin_unlock(&sbinfo->si_plink_maint_lock); +- } +- si_write_unlock(sb); +- +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-struct pseudo_link { +- union { +- struct list_head list; +- struct rcu_head rcu; +- }; +- struct inode *inode; +-}; +- +-#ifdef CONFIG_AUFS_DEBUG +-void au_plink_list(struct super_block *sb) +-{ +- struct au_sbinfo *sbinfo; +- struct list_head *plink_list; +- struct pseudo_link *plink; +- +- SiMustAnyLock(sb); +- +- sbinfo = au_sbi(sb); +- AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); +- AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); +- +- plink_list = &sbinfo->si_plink.head; +- rcu_read_lock(); +- list_for_each_entry_rcu(plink, plink_list, list) +- AuDbg("%lu\n", plink->inode->i_ino); +- rcu_read_unlock(); +-} +-#endif +- +-/* is the inode pseudo-linked? */ +-int au_plink_test(struct inode *inode) +-{ +- int found; +- struct au_sbinfo *sbinfo; +- struct list_head *plink_list; +- struct pseudo_link *plink; +- +- sbinfo = au_sbi(inode->i_sb); +- AuRwMustAnyLock(&sbinfo->si_rwsem); +- AuDebugOn(!au_opt_test(au_mntflags(inode->i_sb), PLINK)); +- AuDebugOn(au_plink_maint(inode->i_sb, AuLock_NOPLM)); +- +- found = 0; +- plink_list = &sbinfo->si_plink.head; +- rcu_read_lock(); +- list_for_each_entry_rcu(plink, plink_list, list) +- if (plink->inode == inode) { +- found = 1; +- break; +- } +- rcu_read_unlock(); +- return found; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* +- * generate a name for plink. +- * the file will be stored under AUFS_WH_PLINKDIR. +- */ +-/* 20 is max digits length of ulong 64 */ +-#define PLINK_NAME_LEN ((20 + 1) * 2) +- +-static int plink_name(char *name, int len, struct inode *inode, +- aufs_bindex_t bindex) +-{ +- int rlen; +- struct inode *h_inode; +- +- h_inode = au_h_iptr(inode, bindex); +- rlen = snprintf(name, len, "%lu.%lu", inode->i_ino, h_inode->i_ino); +- return rlen; +-} +- +-struct au_do_plink_lkup_args { +- struct dentry **errp; +- struct qstr *tgtname; +- struct dentry *h_parent; +- struct au_branch *br; +-}; +- +-static struct dentry *au_do_plink_lkup(struct qstr *tgtname, +- struct dentry *h_parent, +- struct au_branch *br) +-{ +- struct dentry *h_dentry; +- struct mutex *h_mtx; +- +- h_mtx = &h_parent->d_inode->i_mutex; +- mutex_lock_nested(h_mtx, AuLsc_I_CHILD2); +- h_dentry = vfsub_lkup_one(tgtname, h_parent); +- mutex_unlock(h_mtx); +- return h_dentry; +-} +- +-static void au_call_do_plink_lkup(void *args) +-{ +- struct au_do_plink_lkup_args *a = args; +- *a->errp = au_do_plink_lkup(a->tgtname, a->h_parent, a->br); +-} +- +-/* lookup the plink-ed @inode under the branch at @bindex */ +-struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex) +-{ +- struct dentry *h_dentry, *h_parent; +- struct au_branch *br; +- struct inode *h_dir; +- int wkq_err; +- char a[PLINK_NAME_LEN]; +- struct qstr tgtname = QSTR_INIT(a, 0); +- +- AuDebugOn(au_plink_maint(inode->i_sb, AuLock_NOPLM)); +- +- br = au_sbr(inode->i_sb, bindex); +- h_parent = br->br_wbr->wbr_plink; +- h_dir = h_parent->d_inode; +- tgtname.len = plink_name(a, sizeof(a), inode, bindex); +- +- if (!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) { +- struct au_do_plink_lkup_args args = { +- .errp = &h_dentry, +- .tgtname = &tgtname, +- .h_parent = h_parent, +- .br = br +- }; +- +- wkq_err = au_wkq_wait(au_call_do_plink_lkup, &args); +- if (unlikely(wkq_err)) +- h_dentry = ERR_PTR(wkq_err); +- } else +- h_dentry = au_do_plink_lkup(&tgtname, h_parent, br); +- +- return h_dentry; +-} +- +-/* create a pseudo-link */ +-static int do_whplink(struct qstr *tgt, struct dentry *h_parent, +- struct dentry *h_dentry, struct au_branch *br) +-{ +- int err; +- struct path h_path = { +- .mnt = br->br_mnt +- }; +- struct inode *h_dir; +- +- h_dir = h_parent->d_inode; +- mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_CHILD2); +-again: +- h_path.dentry = vfsub_lkup_one(tgt, h_parent); +- err = PTR_ERR(h_path.dentry); +- if (IS_ERR(h_path.dentry)) +- goto out; +- +- err = 0; +- /* wh.plink dir is not monitored */ +- /* todo: is it really safe? */ +- if (h_path.dentry->d_inode +- && h_path.dentry->d_inode != h_dentry->d_inode) { +- err = vfsub_unlink(h_dir, &h_path, /*force*/0); +- dput(h_path.dentry); +- h_path.dentry = NULL; +- if (!err) +- goto again; +- } +- if (!err && !h_path.dentry->d_inode) +- err = vfsub_link(h_dentry, h_dir, &h_path); +- dput(h_path.dentry); +- +-out: +- mutex_unlock(&h_dir->i_mutex); +- return err; +-} +- +-struct do_whplink_args { +- int *errp; +- struct qstr *tgt; +- struct dentry *h_parent; +- struct dentry *h_dentry; +- struct au_branch *br; +-}; +- +-static void call_do_whplink(void *args) +-{ +- struct do_whplink_args *a = args; +- *a->errp = do_whplink(a->tgt, a->h_parent, a->h_dentry, a->br); +-} +- +-static int whplink(struct dentry *h_dentry, struct inode *inode, +- aufs_bindex_t bindex, struct au_branch *br) +-{ +- int err, wkq_err; +- struct au_wbr *wbr; +- struct dentry *h_parent; +- struct inode *h_dir; +- char a[PLINK_NAME_LEN]; +- struct qstr tgtname = QSTR_INIT(a, 0); +- +- wbr = au_sbr(inode->i_sb, bindex)->br_wbr; +- h_parent = wbr->wbr_plink; +- h_dir = h_parent->d_inode; +- tgtname.len = plink_name(a, sizeof(a), inode, bindex); +- +- /* always superio. */ +- if (!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) { +- struct do_whplink_args args = { +- .errp = &err, +- .tgt = &tgtname, +- .h_parent = h_parent, +- .h_dentry = h_dentry, +- .br = br +- }; +- wkq_err = au_wkq_wait(call_do_whplink, &args); +- if (unlikely(wkq_err)) +- err = wkq_err; +- } else +- err = do_whplink(&tgtname, h_parent, h_dentry, br); +- +- return err; +-} +- +-/* free a single plink */ +-static void do_put_plink(struct pseudo_link *plink, int do_del) +-{ +- if (do_del) +- list_del(&plink->list); +- iput(plink->inode); +- kfree(plink); +-} +- +-static void do_put_plink_rcu(struct rcu_head *rcu) +-{ +- struct pseudo_link *plink; +- +- plink = container_of(rcu, struct pseudo_link, rcu); +- iput(plink->inode); +- kfree(plink); +-} +- +-/* +- * create a new pseudo-link for @h_dentry on @bindex. +- * the linked inode is held in aufs @inode. +- */ +-void au_plink_append(struct inode *inode, aufs_bindex_t bindex, +- struct dentry *h_dentry) +-{ +- struct super_block *sb; +- struct au_sbinfo *sbinfo; +- struct list_head *plink_list; +- struct pseudo_link *plink, *tmp; +- int found, err, cnt; +- +- sb = inode->i_sb; +- sbinfo = au_sbi(sb); +- AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); +- AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); +- +- cnt = 0; +- found = 0; +- plink_list = &sbinfo->si_plink.head; +- rcu_read_lock(); +- list_for_each_entry_rcu(plink, plink_list, list) { +- cnt++; +- if (plink->inode == inode) { +- found = 1; +- break; +- } +- } +- rcu_read_unlock(); +- if (found) +- return; +- +- tmp = kmalloc(sizeof(*plink), GFP_NOFS); +- if (tmp) +- tmp->inode = au_igrab(inode); +- else { +- err = -ENOMEM; +- goto out; +- } +- +- spin_lock(&sbinfo->si_plink.spin); +- list_for_each_entry(plink, plink_list, list) { +- if (plink->inode == inode) { +- found = 1; +- break; +- } +- } +- if (!found) +- list_add_rcu(&tmp->list, plink_list); +- spin_unlock(&sbinfo->si_plink.spin); +- if (!found) { +- cnt++; +- WARN_ONCE(cnt > AUFS_PLINK_WARN, +- "unexpectedly many pseudo links, %d\n", cnt); +- err = whplink(h_dentry, inode, bindex, au_sbr(sb, bindex)); +- } else { +- do_put_plink(tmp, 0); +- return; +- } +- +-out: +- if (unlikely(err)) { +- pr_warn("err %d, damaged pseudo link.\n", err); +- if (tmp) { +- au_spl_del_rcu(&tmp->list, &sbinfo->si_plink); +- call_rcu(&tmp->rcu, do_put_plink_rcu); +- } +- } +-} +- +-/* free all plinks */ +-void au_plink_put(struct super_block *sb, int verbose) +-{ +- struct au_sbinfo *sbinfo; +- struct list_head *plink_list; +- struct pseudo_link *plink, *tmp; +- +- SiMustWriteLock(sb); +- +- sbinfo = au_sbi(sb); +- AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); +- AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); +- +- plink_list = &sbinfo->si_plink.head; +- /* no spin_lock since sbinfo is write-locked */ +- WARN(verbose && !list_empty(plink_list), "pseudo-link is not flushed"); +- list_for_each_entry_safe(plink, tmp, plink_list, list) +- do_put_plink(plink, 0); +- INIT_LIST_HEAD(plink_list); +-} +- +-void au_plink_clean(struct super_block *sb, int verbose) +-{ +- struct dentry *root; +- +- root = sb->s_root; +- aufs_write_lock(root); +- if (au_opt_test(au_mntflags(sb), PLINK)) +- au_plink_put(sb, verbose); +- aufs_write_unlock(root); +-} +- +-/* free the plinks on a branch specified by @br_id */ +-void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id) +-{ +- struct au_sbinfo *sbinfo; +- struct list_head *plink_list; +- struct pseudo_link *plink, *tmp; +- struct inode *inode; +- aufs_bindex_t bstart, bend, bindex; +- unsigned char do_put; +- +- SiMustWriteLock(sb); +- +- sbinfo = au_sbi(sb); +- AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); +- AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); +- +- plink_list = &sbinfo->si_plink.head; +- /* no spin_lock since sbinfo is write-locked */ +- list_for_each_entry_safe(plink, tmp, plink_list, list) { +- do_put = 0; +- inode = au_igrab(plink->inode); +- ii_write_lock_child(inode); +- bstart = au_ibstart(inode); +- bend = au_ibend(inode); +- if (bstart >= 0) { +- for (bindex = bstart; bindex <= bend; bindex++) { +- if (!au_h_iptr(inode, bindex) +- || au_ii_br_id(inode, bindex) != br_id) +- continue; +- au_set_h_iptr(inode, bindex, NULL, 0); +- do_put = 1; +- break; +- } +- } else +- do_put_plink(plink, 1); +- +- if (do_put) { +- for (bindex = bstart; bindex <= bend; bindex++) +- if (au_h_iptr(inode, bindex)) { +- do_put = 0; +- break; +- } +- if (do_put) +- do_put_plink(plink, 1); +- } +- ii_write_unlock(inode); +- iput(inode); +- } +-} +diff --git a/fs/aufs/poll.c b/fs/aufs/poll.c +deleted file mode 100644 +index aa5e2ae..0000000 +--- a/fs/aufs/poll.c ++++ /dev/null +@@ -1,56 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * poll operation +- * There is only one filesystem which implements ->poll operation, currently. +- */ +- +-#include "aufs.h" +- +-unsigned int aufs_poll(struct file *file, poll_table *wait) +-{ +- unsigned int mask; +- int err; +- struct file *h_file; +- struct dentry *dentry; +- struct super_block *sb; +- +- /* We should pretend an error happened. */ +- mask = POLLERR /* | POLLIN | POLLOUT */; +- dentry = file->f_dentry; +- sb = dentry->d_sb; +- si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); +- err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0); +- if (unlikely(err)) +- goto out; +- +- /* it is not an error if h_file has no operation */ +- mask = DEFAULT_POLLMASK; +- h_file = au_hf_top(file); +- if (h_file->f_op && h_file->f_op->poll) +- mask = h_file->f_op->poll(h_file, wait); +- +- di_read_unlock(dentry, AuLock_IR); +- fi_read_unlock(file); +- +-out: +- si_read_unlock(sb); +- AuTraceErr((int)mask); +- return mask; +-} +diff --git a/fs/aufs/procfs.c b/fs/aufs/procfs.c +deleted file mode 100644 +index 7201cdf..0000000 +--- a/fs/aufs/procfs.c ++++ /dev/null +@@ -1,170 +0,0 @@ +-/* +- * Copyright (C) 2010-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * procfs interfaces +- */ +- +-#include +-#include "aufs.h" +- +-static int au_procfs_plm_release(struct inode *inode, struct file *file) +-{ +- struct au_sbinfo *sbinfo; +- +- sbinfo = file->private_data; +- if (sbinfo) { +- au_plink_maint_leave(sbinfo); +- kobject_put(&sbinfo->si_kobj); +- } +- +- return 0; +-} +- +-static void au_procfs_plm_write_clean(struct file *file) +-{ +- struct au_sbinfo *sbinfo; +- +- sbinfo = file->private_data; +- if (sbinfo) +- au_plink_clean(sbinfo->si_sb, /*verbose*/0); +-} +- +-static int au_procfs_plm_write_si(struct file *file, unsigned long id) +-{ +- int err; +- struct super_block *sb; +- struct au_sbinfo *sbinfo; +- +- err = -EBUSY; +- if (unlikely(file->private_data)) +- goto out; +- +- sb = NULL; +- /* don't use au_sbilist_lock() here */ +- spin_lock(&au_sbilist.spin); +- list_for_each_entry(sbinfo, &au_sbilist.head, si_list) +- if (id == sysaufs_si_id(sbinfo)) { +- kobject_get(&sbinfo->si_kobj); +- sb = sbinfo->si_sb; +- break; +- } +- spin_unlock(&au_sbilist.spin); +- +- err = -EINVAL; +- if (unlikely(!sb)) +- goto out; +- +- err = au_plink_maint_enter(sb); +- if (!err) +- /* keep kobject_get() */ +- file->private_data = sbinfo; +- else +- kobject_put(&sbinfo->si_kobj); +-out: +- return err; +-} +- +-/* +- * Accept a valid "si=xxxx" only. +- * Once it is accepted successfully, accept "clean" too. +- */ +-static ssize_t au_procfs_plm_write(struct file *file, const char __user *ubuf, +- size_t count, loff_t *ppos) +-{ +- ssize_t err; +- unsigned long id; +- /* last newline is allowed */ +- char buf[3 + sizeof(unsigned long) * 2 + 1]; +- +- err = -EACCES; +- if (unlikely(!capable(CAP_SYS_ADMIN))) +- goto out; +- +- err = -EINVAL; +- if (unlikely(count > sizeof(buf))) +- goto out; +- +- err = copy_from_user(buf, ubuf, count); +- if (unlikely(err)) { +- err = -EFAULT; +- goto out; +- } +- buf[count] = 0; +- +- err = -EINVAL; +- if (!strcmp("clean", buf)) { +- au_procfs_plm_write_clean(file); +- goto out_success; +- } else if (unlikely(strncmp("si=", buf, 3))) +- goto out; +- +- err = kstrtoul(buf + 3, 16, &id); +- if (unlikely(err)) +- goto out; +- +- err = au_procfs_plm_write_si(file, id); +- if (unlikely(err)) +- goto out; +- +-out_success: +- err = count; /* success */ +-out: +- return err; +-} +- +-static const struct file_operations au_procfs_plm_fop = { +- .write = au_procfs_plm_write, +- .release = au_procfs_plm_release, +- .owner = THIS_MODULE +-}; +- +-/* ---------------------------------------------------------------------- */ +- +-static struct proc_dir_entry *au_procfs_dir; +- +-void au_procfs_fin(void) +-{ +- remove_proc_entry(AUFS_PLINK_MAINT_NAME, au_procfs_dir); +- remove_proc_entry(AUFS_PLINK_MAINT_DIR, NULL); +-} +- +-int __init au_procfs_init(void) +-{ +- int err; +- struct proc_dir_entry *entry; +- +- err = -ENOMEM; +- au_procfs_dir = proc_mkdir(AUFS_PLINK_MAINT_DIR, NULL); +- if (unlikely(!au_procfs_dir)) +- goto out; +- +- entry = proc_create(AUFS_PLINK_MAINT_NAME, S_IFREG | S_IWUSR, +- au_procfs_dir, &au_procfs_plm_fop); +- if (unlikely(!entry)) +- goto out_dir; +- +- err = 0; +- goto out; /* success */ +- +- +-out_dir: +- remove_proc_entry(AUFS_PLINK_MAINT_DIR, NULL); +-out: +- return err; +-} +diff --git a/fs/aufs/rdu.c b/fs/aufs/rdu.c +deleted file mode 100644 +index 0dce11e..0000000 +--- a/fs/aufs/rdu.c ++++ /dev/null +@@ -1,384 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * readdir in userspace. +- */ +- +-#include +-#include +-#include +-#include "aufs.h" +- +-/* bits for struct aufs_rdu.flags */ +-#define AuRdu_CALLED 1 +-#define AuRdu_CONT (1 << 1) +-#define AuRdu_FULL (1 << 2) +-#define au_ftest_rdu(flags, name) ((flags) & AuRdu_##name) +-#define au_fset_rdu(flags, name) \ +- do { (flags) |= AuRdu_##name; } while (0) +-#define au_fclr_rdu(flags, name) \ +- do { (flags) &= ~AuRdu_##name; } while (0) +- +-struct au_rdu_arg { +- struct aufs_rdu *rdu; +- union au_rdu_ent_ul ent; +- unsigned long end; +- +- struct super_block *sb; +- int err; +-}; +- +-static int au_rdu_fill(void *__arg, const char *name, int nlen, +- loff_t offset, u64 h_ino, unsigned int d_type) +-{ +- int err, len; +- struct au_rdu_arg *arg = __arg; +- struct aufs_rdu *rdu = arg->rdu; +- struct au_rdu_ent ent; +- +- err = 0; +- arg->err = 0; +- au_fset_rdu(rdu->cookie.flags, CALLED); +- len = au_rdu_len(nlen); +- if (arg->ent.ul + len < arg->end) { +- ent.ino = h_ino; +- ent.bindex = rdu->cookie.bindex; +- ent.type = d_type; +- ent.nlen = nlen; +- if (unlikely(nlen > AUFS_MAX_NAMELEN)) +- ent.type = DT_UNKNOWN; +- +- /* unnecessary to support mmap_sem since this is a dir */ +- err = -EFAULT; +- if (copy_to_user(arg->ent.e, &ent, sizeof(ent))) +- goto out; +- if (copy_to_user(arg->ent.e->name, name, nlen)) +- goto out; +- /* the terminating NULL */ +- if (__put_user(0, arg->ent.e->name + nlen)) +- goto out; +- err = 0; +- /* AuDbg("%p, %.*s\n", arg->ent.p, nlen, name); */ +- arg->ent.ul += len; +- rdu->rent++; +- } else { +- err = -EFAULT; +- au_fset_rdu(rdu->cookie.flags, FULL); +- rdu->full = 1; +- rdu->tail = arg->ent; +- } +- +-out: +- /* AuTraceErr(err); */ +- return err; +-} +- +-static int au_rdu_do(struct file *h_file, struct au_rdu_arg *arg) +-{ +- int err; +- loff_t offset; +- struct au_rdu_cookie *cookie = &arg->rdu->cookie; +- +- /* we don't have to care (FMODE_32BITHASH | FMODE_64BITHASH) for ext4 */ +- offset = vfsub_llseek(h_file, cookie->h_pos, SEEK_SET); +- err = offset; +- if (unlikely(offset != cookie->h_pos)) +- goto out; +- +- err = 0; +- do { +- arg->err = 0; +- au_fclr_rdu(cookie->flags, CALLED); +- /* smp_mb(); */ +- err = vfsub_readdir(h_file, au_rdu_fill, arg); +- if (err >= 0) +- err = arg->err; +- } while (!err +- && au_ftest_rdu(cookie->flags, CALLED) +- && !au_ftest_rdu(cookie->flags, FULL)); +- cookie->h_pos = h_file->f_pos; +- +-out: +- AuTraceErr(err); +- return err; +-} +- +-static int au_rdu(struct file *file, struct aufs_rdu *rdu) +-{ +- int err; +- aufs_bindex_t bend; +- struct au_rdu_arg arg; +- struct dentry *dentry; +- struct inode *inode; +- struct file *h_file; +- struct au_rdu_cookie *cookie = &rdu->cookie; +- +- err = !access_ok(VERIFY_WRITE, rdu->ent.e, rdu->sz); +- if (unlikely(err)) { +- err = -EFAULT; +- AuTraceErr(err); +- goto out; +- } +- rdu->rent = 0; +- rdu->tail = rdu->ent; +- rdu->full = 0; +- arg.rdu = rdu; +- arg.ent = rdu->ent; +- arg.end = arg.ent.ul; +- arg.end += rdu->sz; +- +- err = -ENOTDIR; +- if (unlikely(!file->f_op || !file->f_op->readdir)) +- goto out; +- +- err = security_file_permission(file, MAY_READ); +- AuTraceErr(err); +- if (unlikely(err)) +- goto out; +- +- dentry = file->f_dentry; +- inode = dentry->d_inode; +-#if 1 +- mutex_lock(&inode->i_mutex); +-#else +- err = mutex_lock_killable(&inode->i_mutex); +- AuTraceErr(err); +- if (unlikely(err)) +- goto out; +-#endif +- +- arg.sb = inode->i_sb; +- err = si_read_lock(arg.sb, AuLock_FLUSH | AuLock_NOPLM); +- if (unlikely(err)) +- goto out_mtx; +- err = au_alive_dir(dentry); +- if (unlikely(err)) +- goto out_si; +- /* todo: reval? */ +- fi_read_lock(file); +- +- err = -EAGAIN; +- if (unlikely(au_ftest_rdu(cookie->flags, CONT) +- && cookie->generation != au_figen(file))) +- goto out_unlock; +- +- err = 0; +- if (!rdu->blk) { +- rdu->blk = au_sbi(arg.sb)->si_rdblk; +- if (!rdu->blk) +- rdu->blk = au_dir_size(file, /*dentry*/NULL); +- } +- bend = au_fbstart(file); +- if (cookie->bindex < bend) +- cookie->bindex = bend; +- bend = au_fbend_dir(file); +- /* AuDbg("b%d, b%d\n", cookie->bindex, bend); */ +- for (; !err && cookie->bindex <= bend; +- cookie->bindex++, cookie->h_pos = 0) { +- h_file = au_hf_dir(file, cookie->bindex); +- if (!h_file) +- continue; +- +- au_fclr_rdu(cookie->flags, FULL); +- err = au_rdu_do(h_file, &arg); +- AuTraceErr(err); +- if (unlikely(au_ftest_rdu(cookie->flags, FULL) || err)) +- break; +- } +- AuDbg("rent %llu\n", rdu->rent); +- +- if (!err && !au_ftest_rdu(cookie->flags, CONT)) { +- rdu->shwh = !!au_opt_test(au_sbi(arg.sb)->si_mntflags, SHWH); +- au_fset_rdu(cookie->flags, CONT); +- cookie->generation = au_figen(file); +- } +- +- ii_read_lock_child(inode); +- fsstack_copy_attr_atime(inode, au_h_iptr(inode, au_ibstart(inode))); +- ii_read_unlock(inode); +- +-out_unlock: +- fi_read_unlock(file); +-out_si: +- si_read_unlock(arg.sb); +-out_mtx: +- mutex_unlock(&inode->i_mutex); +-out: +- AuTraceErr(err); +- return err; +-} +- +-static int au_rdu_ino(struct file *file, struct aufs_rdu *rdu) +-{ +- int err; +- ino_t ino; +- unsigned long long nent; +- union au_rdu_ent_ul *u; +- struct au_rdu_ent ent; +- struct super_block *sb; +- +- err = 0; +- nent = rdu->nent; +- u = &rdu->ent; +- sb = file->f_dentry->d_sb; +- si_read_lock(sb, AuLock_FLUSH); +- while (nent-- > 0) { +- /* unnecessary to support mmap_sem since this is a dir */ +- err = copy_from_user(&ent, u->e, sizeof(ent)); +- if (!err) +- err = !access_ok(VERIFY_WRITE, &u->e->ino, sizeof(ino)); +- if (unlikely(err)) { +- err = -EFAULT; +- AuTraceErr(err); +- break; +- } +- +- /* AuDbg("b%d, i%llu\n", ent.bindex, ent.ino); */ +- if (!ent.wh) +- err = au_ino(sb, ent.bindex, ent.ino, ent.type, &ino); +- else +- err = au_wh_ino(sb, ent.bindex, ent.ino, ent.type, +- &ino); +- if (unlikely(err)) { +- AuTraceErr(err); +- break; +- } +- +- err = __put_user(ino, &u->e->ino); +- if (unlikely(err)) { +- err = -EFAULT; +- AuTraceErr(err); +- break; +- } +- u->ul += au_rdu_len(ent.nlen); +- } +- si_read_unlock(sb); +- +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static int au_rdu_verify(struct aufs_rdu *rdu) +-{ +- AuDbg("rdu{%llu, %p, %u | %u | %llu, %u, %u | " +- "%llu, b%d, 0x%x, g%u}\n", +- rdu->sz, rdu->ent.e, rdu->verify[AufsCtlRduV_SZ], +- rdu->blk, +- rdu->rent, rdu->shwh, rdu->full, +- rdu->cookie.h_pos, rdu->cookie.bindex, rdu->cookie.flags, +- rdu->cookie.generation); +- +- if (rdu->verify[AufsCtlRduV_SZ] == sizeof(*rdu)) +- return 0; +- +- AuDbg("%u:%u\n", +- rdu->verify[AufsCtlRduV_SZ], (unsigned int)sizeof(*rdu)); +- return -EINVAL; +-} +- +-long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +-{ +- long err, e; +- struct aufs_rdu rdu; +- void __user *p = (void __user *)arg; +- +- err = copy_from_user(&rdu, p, sizeof(rdu)); +- if (unlikely(err)) { +- err = -EFAULT; +- AuTraceErr(err); +- goto out; +- } +- err = au_rdu_verify(&rdu); +- if (unlikely(err)) +- goto out; +- +- switch (cmd) { +- case AUFS_CTL_RDU: +- err = au_rdu(file, &rdu); +- if (unlikely(err)) +- break; +- +- e = copy_to_user(p, &rdu, sizeof(rdu)); +- if (unlikely(e)) { +- err = -EFAULT; +- AuTraceErr(err); +- } +- break; +- case AUFS_CTL_RDU_INO: +- err = au_rdu_ino(file, &rdu); +- break; +- +- default: +- /* err = -ENOTTY; */ +- err = -EINVAL; +- } +- +-out: +- AuTraceErr(err); +- return err; +-} +- +-#ifdef CONFIG_COMPAT +-long au_rdu_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +-{ +- long err, e; +- struct aufs_rdu rdu; +- void __user *p = compat_ptr(arg); +- +- /* todo: get_user()? */ +- err = copy_from_user(&rdu, p, sizeof(rdu)); +- if (unlikely(err)) { +- err = -EFAULT; +- AuTraceErr(err); +- goto out; +- } +- rdu.ent.e = compat_ptr(rdu.ent.ul); +- err = au_rdu_verify(&rdu); +- if (unlikely(err)) +- goto out; +- +- switch (cmd) { +- case AUFS_CTL_RDU: +- err = au_rdu(file, &rdu); +- if (unlikely(err)) +- break; +- +- rdu.ent.ul = ptr_to_compat(rdu.ent.e); +- rdu.tail.ul = ptr_to_compat(rdu.tail.e); +- e = copy_to_user(p, &rdu, sizeof(rdu)); +- if (unlikely(e)) { +- err = -EFAULT; +- AuTraceErr(err); +- } +- break; +- case AUFS_CTL_RDU_INO: +- err = au_rdu_ino(file, &rdu); +- break; +- +- default: +- /* err = -ENOTTY; */ +- err = -EINVAL; +- } +- +-out: +- AuTraceErr(err); +- return err; +-} +-#endif +diff --git a/fs/aufs/rwsem.h b/fs/aufs/rwsem.h +deleted file mode 100644 +index a1eb04b..0000000 +--- a/fs/aufs/rwsem.h ++++ /dev/null +@@ -1,188 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * simple read-write semaphore wrappers +- */ +- +-#ifndef __AUFS_RWSEM_H__ +-#define __AUFS_RWSEM_H__ +- +-#ifdef __KERNEL__ +- +-#include "debug.h" +- +-struct au_rwsem { +- struct rw_semaphore rwsem; +-#ifdef CONFIG_AUFS_DEBUG +- /* just for debugging, not almighty counter */ +- atomic_t rcnt, wcnt; +-#endif +-}; +- +-#ifdef CONFIG_AUFS_DEBUG +-#define AuDbgCntInit(rw) do { \ +- atomic_set(&(rw)->rcnt, 0); \ +- atomic_set(&(rw)->wcnt, 0); \ +- smp_mb(); /* atomic set */ \ +-} while (0) +- +-#define AuDbgRcntInc(rw) atomic_inc(&(rw)->rcnt) +-#define AuDbgRcntDec(rw) WARN_ON(atomic_dec_return(&(rw)->rcnt) < 0) +-#define AuDbgWcntInc(rw) atomic_inc(&(rw)->wcnt) +-#define AuDbgWcntDec(rw) WARN_ON(atomic_dec_return(&(rw)->wcnt) < 0) +-#else +-#define AuDbgCntInit(rw) do {} while (0) +-#define AuDbgRcntInc(rw) do {} while (0) +-#define AuDbgRcntDec(rw) do {} while (0) +-#define AuDbgWcntInc(rw) do {} while (0) +-#define AuDbgWcntDec(rw) do {} while (0) +-#endif /* CONFIG_AUFS_DEBUG */ +- +-/* to debug easier, do not make them inlined functions */ +-#define AuRwMustNoWaiters(rw) AuDebugOn(!list_empty(&(rw)->rwsem.wait_list)) +-/* rwsem_is_locked() is unusable */ +-#define AuRwMustReadLock(rw) AuDebugOn(atomic_read(&(rw)->rcnt) <= 0) +-#define AuRwMustWriteLock(rw) AuDebugOn(atomic_read(&(rw)->wcnt) <= 0) +-#define AuRwMustAnyLock(rw) AuDebugOn(atomic_read(&(rw)->rcnt) <= 0 \ +- && atomic_read(&(rw)->wcnt) <= 0) +-#define AuRwDestroy(rw) AuDebugOn(atomic_read(&(rw)->rcnt) \ +- || atomic_read(&(rw)->wcnt)) +- +-#define au_rw_class(rw, key) lockdep_set_class(&(rw)->rwsem, key) +- +-static inline void au_rw_init(struct au_rwsem *rw) +-{ +- AuDbgCntInit(rw); +- init_rwsem(&rw->rwsem); +-} +- +-static inline void au_rw_init_wlock(struct au_rwsem *rw) +-{ +- au_rw_init(rw); +- down_write(&rw->rwsem); +- AuDbgWcntInc(rw); +-} +- +-static inline void au_rw_init_wlock_nested(struct au_rwsem *rw, +- unsigned int lsc) +-{ +- au_rw_init(rw); +- down_write_nested(&rw->rwsem, lsc); +- AuDbgWcntInc(rw); +-} +- +-static inline void au_rw_read_lock(struct au_rwsem *rw) +-{ +- down_read(&rw->rwsem); +- AuDbgRcntInc(rw); +-} +- +-static inline void au_rw_read_lock_nested(struct au_rwsem *rw, unsigned int lsc) +-{ +- down_read_nested(&rw->rwsem, lsc); +- AuDbgRcntInc(rw); +-} +- +-static inline void au_rw_read_unlock(struct au_rwsem *rw) +-{ +- AuRwMustReadLock(rw); +- AuDbgRcntDec(rw); +- up_read(&rw->rwsem); +-} +- +-static inline void au_rw_dgrade_lock(struct au_rwsem *rw) +-{ +- AuRwMustWriteLock(rw); +- AuDbgRcntInc(rw); +- AuDbgWcntDec(rw); +- downgrade_write(&rw->rwsem); +-} +- +-static inline void au_rw_write_lock(struct au_rwsem *rw) +-{ +- down_write(&rw->rwsem); +- AuDbgWcntInc(rw); +-} +- +-static inline void au_rw_write_lock_nested(struct au_rwsem *rw, +- unsigned int lsc) +-{ +- down_write_nested(&rw->rwsem, lsc); +- AuDbgWcntInc(rw); +-} +- +-static inline void au_rw_write_unlock(struct au_rwsem *rw) +-{ +- AuRwMustWriteLock(rw); +- AuDbgWcntDec(rw); +- up_write(&rw->rwsem); +-} +- +-/* why is not _nested version defined */ +-static inline int au_rw_read_trylock(struct au_rwsem *rw) +-{ +- int ret = down_read_trylock(&rw->rwsem); +- if (ret) +- AuDbgRcntInc(rw); +- return ret; +-} +- +-static inline int au_rw_write_trylock(struct au_rwsem *rw) +-{ +- int ret = down_write_trylock(&rw->rwsem); +- if (ret) +- AuDbgWcntInc(rw); +- return ret; +-} +- +-#undef AuDbgCntInit +-#undef AuDbgRcntInc +-#undef AuDbgRcntDec +-#undef AuDbgWcntInc +-#undef AuDbgWcntDec +- +-#define AuSimpleLockRwsemFuncs(prefix, param, rwsem) \ +-static inline void prefix##_read_lock(param) \ +-{ au_rw_read_lock(rwsem); } \ +-static inline void prefix##_write_lock(param) \ +-{ au_rw_write_lock(rwsem); } \ +-static inline int prefix##_read_trylock(param) \ +-{ return au_rw_read_trylock(rwsem); } \ +-static inline int prefix##_write_trylock(param) \ +-{ return au_rw_write_trylock(rwsem); } +-/* why is not _nested version defined */ +-/* static inline void prefix##_read_trylock_nested(param, lsc) +-{ au_rw_read_trylock_nested(rwsem, lsc)); } +-static inline void prefix##_write_trylock_nestd(param, lsc) +-{ au_rw_write_trylock_nested(rwsem, lsc); } */ +- +-#define AuSimpleUnlockRwsemFuncs(prefix, param, rwsem) \ +-static inline void prefix##_read_unlock(param) \ +-{ au_rw_read_unlock(rwsem); } \ +-static inline void prefix##_write_unlock(param) \ +-{ au_rw_write_unlock(rwsem); } \ +-static inline void prefix##_downgrade_lock(param) \ +-{ au_rw_dgrade_lock(rwsem); } +- +-#define AuSimpleRwsemFuncs(prefix, param, rwsem) \ +- AuSimpleLockRwsemFuncs(prefix, param, rwsem) \ +- AuSimpleUnlockRwsemFuncs(prefix, param, rwsem) +- +-#endif /* __KERNEL__ */ +-#endif /* __AUFS_RWSEM_H__ */ +diff --git a/fs/aufs/sbinfo.c b/fs/aufs/sbinfo.c +deleted file mode 100644 +index b277607..0000000 +--- a/fs/aufs/sbinfo.c ++++ /dev/null +@@ -1,343 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * superblock private data +- */ +- +-#include "aufs.h" +- +-/* +- * they are necessary regardless sysfs is disabled. +- */ +-void au_si_free(struct kobject *kobj) +-{ +- struct au_sbinfo *sbinfo; +- char *locked __maybe_unused; /* debug only */ +- +- sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); +- AuDebugOn(!list_empty(&sbinfo->si_plink.head)); +- AuDebugOn(atomic_read(&sbinfo->si_nowait.nw_len)); +- +- au_rw_write_lock(&sbinfo->si_rwsem); +- au_br_free(sbinfo); +- au_rw_write_unlock(&sbinfo->si_rwsem); +- +- AuDebugOn(radix_tree_gang_lookup +- (&sbinfo->au_si_pid.tree, (void **)&locked, +- /*first_index*/PID_MAX_DEFAULT - 1, +- /*max_items*/sizeof(locked)/sizeof(*locked))); +- +- kfree(sbinfo->si_branch); +- kfree(sbinfo->au_si_pid.bitmap); +- mutex_destroy(&sbinfo->si_xib_mtx); +- AuRwDestroy(&sbinfo->si_rwsem); +- +- kfree(sbinfo); +-} +- +-int au_si_alloc(struct super_block *sb) +-{ +- int err; +- struct au_sbinfo *sbinfo; +- static struct lock_class_key aufs_si; +- +- err = -ENOMEM; +- sbinfo = kzalloc(sizeof(*sbinfo), GFP_NOFS); +- if (unlikely(!sbinfo)) +- goto out; +- +- BUILD_BUG_ON(sizeof(unsigned long) != +- sizeof(*sbinfo->au_si_pid.bitmap)); +- sbinfo->au_si_pid.bitmap = kcalloc(BITS_TO_LONGS(PID_MAX_DEFAULT), +- sizeof(*sbinfo->au_si_pid.bitmap), +- GFP_NOFS); +- if (unlikely(!sbinfo->au_si_pid.bitmap)) +- goto out_sbinfo; +- +- /* will be reallocated separately */ +- sbinfo->si_branch = kzalloc(sizeof(*sbinfo->si_branch), GFP_NOFS); +- if (unlikely(!sbinfo->si_branch)) +- goto out_pidmap; +- +- err = sysaufs_si_init(sbinfo); +- if (unlikely(err)) +- goto out_br; +- +- au_nwt_init(&sbinfo->si_nowait); +- au_rw_init_wlock(&sbinfo->si_rwsem); +- au_rw_class(&sbinfo->si_rwsem, &aufs_si); +- spin_lock_init(&sbinfo->au_si_pid.tree_lock); +- INIT_RADIX_TREE(&sbinfo->au_si_pid.tree, GFP_ATOMIC | __GFP_NOFAIL); +- +- atomic_long_set(&sbinfo->si_ninodes, 0); +- atomic_long_set(&sbinfo->si_nfiles, 0); +- +- sbinfo->si_bend = -1; +- +- sbinfo->si_wbr_copyup = AuWbrCopyup_Def; +- sbinfo->si_wbr_create = AuWbrCreate_Def; +- sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + sbinfo->si_wbr_copyup; +- sbinfo->si_wbr_create_ops = au_wbr_create_ops + sbinfo->si_wbr_create; +- +- sbinfo->si_mntflags = au_opts_plink(AuOpt_Def); +- +- mutex_init(&sbinfo->si_xib_mtx); +- sbinfo->si_xino_brid = -1; +- /* leave si_xib_last_pindex and si_xib_next_bit */ +- +- sbinfo->si_rdcache = msecs_to_jiffies(AUFS_RDCACHE_DEF * MSEC_PER_SEC); +- sbinfo->si_rdblk = AUFS_RDBLK_DEF; +- sbinfo->si_rdhash = AUFS_RDHASH_DEF; +- sbinfo->si_dirwh = AUFS_DIRWH_DEF; +- +- au_spl_init(&sbinfo->si_plink); +- init_waitqueue_head(&sbinfo->si_plink_wq); +- spin_lock_init(&sbinfo->si_plink_maint_lock); +- +- /* leave other members for sysaufs and si_mnt. */ +- sbinfo->si_sb = sb; +- sb->s_fs_info = sbinfo; +- si_pid_set(sb); +- au_debug_sbinfo_init(sbinfo); +- return 0; /* success */ +- +-out_br: +- kfree(sbinfo->si_branch); +-out_pidmap: +- kfree(sbinfo->au_si_pid.bitmap); +-out_sbinfo: +- kfree(sbinfo); +-out: +- return err; +-} +- +-int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr) +-{ +- int err, sz; +- struct au_branch **brp; +- +- AuRwMustWriteLock(&sbinfo->si_rwsem); +- +- err = -ENOMEM; +- sz = sizeof(*brp) * (sbinfo->si_bend + 1); +- if (unlikely(!sz)) +- sz = sizeof(*brp); +- brp = au_kzrealloc(sbinfo->si_branch, sz, sizeof(*brp) * nbr, GFP_NOFS); +- if (brp) { +- sbinfo->si_branch = brp; +- err = 0; +- } +- +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-unsigned int au_sigen_inc(struct super_block *sb) +-{ +- unsigned int gen; +- +- SiMustWriteLock(sb); +- +- gen = ++au_sbi(sb)->si_generation; +- au_update_digen(sb->s_root); +- au_update_iigen(sb->s_root->d_inode, /*half*/0); +- sb->s_root->d_inode->i_version++; +- return gen; +-} +- +-aufs_bindex_t au_new_br_id(struct super_block *sb) +-{ +- aufs_bindex_t br_id; +- int i; +- struct au_sbinfo *sbinfo; +- +- SiMustWriteLock(sb); +- +- sbinfo = au_sbi(sb); +- for (i = 0; i <= AUFS_BRANCH_MAX; i++) { +- br_id = ++sbinfo->si_last_br_id; +- AuDebugOn(br_id < 0); +- if (br_id && au_br_index(sb, br_id) < 0) +- return br_id; +- } +- +- return -1; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* it is ok that new 'nwt' tasks are appended while we are sleeping */ +-int si_read_lock(struct super_block *sb, int flags) +-{ +- int err; +- +- err = 0; +- if (au_ftest_lock(flags, FLUSH)) +- au_nwt_flush(&au_sbi(sb)->si_nowait); +- +- si_noflush_read_lock(sb); +- err = au_plink_maint(sb, flags); +- if (unlikely(err)) +- si_read_unlock(sb); +- +- return err; +-} +- +-int si_write_lock(struct super_block *sb, int flags) +-{ +- int err; +- +- if (au_ftest_lock(flags, FLUSH)) +- au_nwt_flush(&au_sbi(sb)->si_nowait); +- +- si_noflush_write_lock(sb); +- err = au_plink_maint(sb, flags); +- if (unlikely(err)) +- si_write_unlock(sb); +- +- return err; +-} +- +-/* dentry and super_block lock. call at entry point */ +-int aufs_read_lock(struct dentry *dentry, int flags) +-{ +- int err; +- struct super_block *sb; +- +- sb = dentry->d_sb; +- err = si_read_lock(sb, flags); +- if (unlikely(err)) +- goto out; +- +- if (au_ftest_lock(flags, DW)) +- di_write_lock_child(dentry); +- else +- di_read_lock_child(dentry, flags); +- +- if (au_ftest_lock(flags, GEN)) { +- err = au_digen_test(dentry, au_sigen(sb)); +- AuDebugOn(!err && au_dbrange_test(dentry)); +- if (unlikely(err)) +- aufs_read_unlock(dentry, flags); +- } +- +-out: +- return err; +-} +- +-void aufs_read_unlock(struct dentry *dentry, int flags) +-{ +- if (au_ftest_lock(flags, DW)) +- di_write_unlock(dentry); +- else +- di_read_unlock(dentry, flags); +- si_read_unlock(dentry->d_sb); +-} +- +-void aufs_write_lock(struct dentry *dentry) +-{ +- si_write_lock(dentry->d_sb, AuLock_FLUSH | AuLock_NOPLMW); +- di_write_lock_child(dentry); +-} +- +-void aufs_write_unlock(struct dentry *dentry) +-{ +- di_write_unlock(dentry); +- si_write_unlock(dentry->d_sb); +-} +- +-int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags) +-{ +- int err; +- unsigned int sigen; +- struct super_block *sb; +- +- sb = d1->d_sb; +- err = si_read_lock(sb, flags); +- if (unlikely(err)) +- goto out; +- +- di_write_lock2_child(d1, d2, au_ftest_lock(flags, DIR)); +- +- if (au_ftest_lock(flags, GEN)) { +- sigen = au_sigen(sb); +- err = au_digen_test(d1, sigen); +- AuDebugOn(!err && au_dbrange_test(d1)); +- if (!err) { +- err = au_digen_test(d2, sigen); +- AuDebugOn(!err && au_dbrange_test(d2)); +- } +- if (unlikely(err)) +- aufs_read_and_write_unlock2(d1, d2); +- } +- +-out: +- return err; +-} +- +-void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2) +-{ +- di_write_unlock2(d1, d2); +- si_read_unlock(d1->d_sb); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-int si_pid_test_slow(struct super_block *sb) +-{ +- void *p; +- +- rcu_read_lock(); +- p = radix_tree_lookup(&au_sbi(sb)->au_si_pid.tree, current->pid); +- rcu_read_unlock(); +- +- return (long)!!p; +-} +- +-void si_pid_set_slow(struct super_block *sb) +-{ +- int err; +- struct au_sbinfo *sbinfo; +- +- AuDebugOn(si_pid_test_slow(sb)); +- +- sbinfo = au_sbi(sb); +- err = radix_tree_preload(GFP_NOFS | __GFP_NOFAIL); +- AuDebugOn(err); +- spin_lock(&sbinfo->au_si_pid.tree_lock); +- err = radix_tree_insert(&sbinfo->au_si_pid.tree, current->pid, +- /*any valid ptr*/sb); +- spin_unlock(&sbinfo->au_si_pid.tree_lock); +- AuDebugOn(err); +- radix_tree_preload_end(); +-} +- +-void si_pid_clr_slow(struct super_block *sb) +-{ +- void *p; +- struct au_sbinfo *sbinfo; +- +- AuDebugOn(!si_pid_test_slow(sb)); +- +- sbinfo = au_sbi(sb); +- spin_lock(&sbinfo->au_si_pid.tree_lock); +- p = radix_tree_delete(&sbinfo->au_si_pid.tree, current->pid); +- spin_unlock(&sbinfo->au_si_pid.tree_lock); +-} +diff --git a/fs/aufs/spl.h b/fs/aufs/spl.h +deleted file mode 100644 +index fcbb514..0000000 +--- a/fs/aufs/spl.h ++++ /dev/null +@@ -1,62 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * simple list protected by a spinlock +- */ +- +-#ifndef __AUFS_SPL_H__ +-#define __AUFS_SPL_H__ +- +-#ifdef __KERNEL__ +- +-struct au_splhead { +- spinlock_t spin; +- struct list_head head; +-}; +- +-static inline void au_spl_init(struct au_splhead *spl) +-{ +- spin_lock_init(&spl->spin); +- INIT_LIST_HEAD(&spl->head); +-} +- +-static inline void au_spl_add(struct list_head *list, struct au_splhead *spl) +-{ +- spin_lock(&spl->spin); +- list_add(list, &spl->head); +- spin_unlock(&spl->spin); +-} +- +-static inline void au_spl_del(struct list_head *list, struct au_splhead *spl) +-{ +- spin_lock(&spl->spin); +- list_del(list); +- spin_unlock(&spl->spin); +-} +- +-static inline void au_spl_del_rcu(struct list_head *list, +- struct au_splhead *spl) +-{ +- spin_lock(&spl->spin); +- list_del_rcu(list); +- spin_unlock(&spl->spin); +-} +- +-#endif /* __KERNEL__ */ +-#endif /* __AUFS_SPL_H__ */ +diff --git a/fs/aufs/super.c b/fs/aufs/super.c +deleted file mode 100644 +index ab4c909..0000000 +--- a/fs/aufs/super.c ++++ /dev/null +@@ -1,993 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * mount and super_block operations +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include "aufs.h" +- +-/* +- * super_operations +- */ +-static struct inode *aufs_alloc_inode(struct super_block *sb __maybe_unused) +-{ +- struct au_icntnr *c; +- +- c = au_cache_alloc_icntnr(); +- if (c) { +- au_icntnr_init(c); +- c->vfs_inode.i_version = 1; /* sigen(sb); */ +- c->iinfo.ii_hinode = NULL; +- return &c->vfs_inode; +- } +- return NULL; +-} +- +-static void aufs_destroy_inode_cb(struct rcu_head *head) +-{ +- struct inode *inode = container_of(head, struct inode, i_rcu); +- +- INIT_HLIST_HEAD(&inode->i_dentry); +- au_cache_free_icntnr(container_of(inode, struct au_icntnr, vfs_inode)); +-} +- +-static void aufs_destroy_inode(struct inode *inode) +-{ +- au_iinfo_fin(inode); +- call_rcu(&inode->i_rcu, aufs_destroy_inode_cb); +-} +- +-struct inode *au_iget_locked(struct super_block *sb, ino_t ino) +-{ +- struct inode *inode; +- int err; +- +- inode = iget_locked(sb, ino); +- if (unlikely(!inode)) { +- inode = ERR_PTR(-ENOMEM); +- goto out; +- } +- if (!(inode->i_state & I_NEW)) +- goto out; +- +- err = au_xigen_new(inode); +- if (!err) +- err = au_iinfo_init(inode); +- if (!err) +- inode->i_version++; +- else { +- iget_failed(inode); +- inode = ERR_PTR(err); +- } +- +-out: +- /* never return NULL */ +- AuDebugOn(!inode); +- AuTraceErrPtr(inode); +- return inode; +-} +- +-/* lock free root dinfo */ +-static int au_show_brs(struct seq_file *seq, struct super_block *sb) +-{ +- int err; +- aufs_bindex_t bindex, bend; +- struct path path; +- struct au_hdentry *hdp; +- struct au_branch *br; +- char *perm; +- +- err = 0; +- bend = au_sbend(sb); +- hdp = au_di(sb->s_root)->di_hdentry; +- for (bindex = 0; !err && bindex <= bend; bindex++) { +- br = au_sbr(sb, bindex); +- path.mnt = br->br_mnt; +- path.dentry = hdp[bindex].hd_dentry; +- err = au_seq_path(seq, &path); +- if (err > 0) { +- perm = au_optstr_br_perm(br->br_perm); +- if (perm) { +- err = seq_printf(seq, "=%s", perm); +- kfree(perm); +- if (err == -1) +- err = -E2BIG; +- } else +- err = -ENOMEM; +- } +- if (!err && bindex != bend) +- err = seq_putc(seq, ':'); +- } +- +- return err; +-} +- +-static void au_show_wbr_create(struct seq_file *m, int v, +- struct au_sbinfo *sbinfo) +-{ +- const char *pat; +- +- AuRwMustAnyLock(&sbinfo->si_rwsem); +- +- seq_printf(m, ",create="); +- pat = au_optstr_wbr_create(v); +- switch (v) { +- case AuWbrCreate_TDP: +- case AuWbrCreate_RR: +- case AuWbrCreate_MFS: +- case AuWbrCreate_PMFS: +- seq_printf(m, pat); +- break; +- case AuWbrCreate_MFSV: +- seq_printf(m, /*pat*/"mfs:%lu", +- jiffies_to_msecs(sbinfo->si_wbr_mfs.mfs_expire) +- / MSEC_PER_SEC); +- break; +- case AuWbrCreate_PMFSV: +- seq_printf(m, /*pat*/"pmfs:%lu", +- jiffies_to_msecs(sbinfo->si_wbr_mfs.mfs_expire) +- / MSEC_PER_SEC); +- break; +- case AuWbrCreate_MFSRR: +- seq_printf(m, /*pat*/"mfsrr:%llu", +- sbinfo->si_wbr_mfs.mfsrr_watermark); +- break; +- case AuWbrCreate_MFSRRV: +- seq_printf(m, /*pat*/"mfsrr:%llu:%lu", +- sbinfo->si_wbr_mfs.mfsrr_watermark, +- jiffies_to_msecs(sbinfo->si_wbr_mfs.mfs_expire) +- / MSEC_PER_SEC); +- break; +- } +-} +- +-static int au_show_xino(struct seq_file *seq, struct super_block *sb) +-{ +-#ifdef CONFIG_SYSFS +- return 0; +-#else +- int err; +- const int len = sizeof(AUFS_XINO_FNAME) - 1; +- aufs_bindex_t bindex, brid; +- struct qstr *name; +- struct file *f; +- struct dentry *d, *h_root; +- struct au_hdentry *hdp; +- +- AuRwMustAnyLock(&sbinfo->si_rwsem); +- +- err = 0; +- f = au_sbi(sb)->si_xib; +- if (!f) +- goto out; +- +- /* stop printing the default xino path on the first writable branch */ +- h_root = NULL; +- brid = au_xino_brid(sb); +- if (brid >= 0) { +- bindex = au_br_index(sb, brid); +- hdp = au_di(sb->s_root)->di_hdentry; +- h_root = hdp[0 + bindex].hd_dentry; +- } +- d = f->f_dentry; +- name = &d->d_name; +- /* safe ->d_parent because the file is unlinked */ +- if (d->d_parent == h_root +- && name->len == len +- && !memcmp(name->name, AUFS_XINO_FNAME, len)) +- goto out; +- +- seq_puts(seq, ",xino="); +- err = au_xino_path(seq, f); +- +-out: +- return err; +-#endif +-} +- +-/* seq_file will re-call me in case of too long string */ +-static int aufs_show_options(struct seq_file *m, struct dentry *dentry) +-{ +- int err; +- unsigned int mnt_flags, v; +- struct super_block *sb; +- struct au_sbinfo *sbinfo; +- +-#define AuBool(name, str) do { \ +- v = au_opt_test(mnt_flags, name); \ +- if (v != au_opt_test(AuOpt_Def, name)) \ +- seq_printf(m, ",%s" #str, v ? "" : "no"); \ +-} while (0) +- +-#define AuStr(name, str) do { \ +- v = mnt_flags & AuOptMask_##name; \ +- if (v != (AuOpt_Def & AuOptMask_##name)) \ +- seq_printf(m, "," #str "=%s", au_optstr_##str(v)); \ +-} while (0) +- +-#define AuUInt(name, str, val) do { \ +- if (val != AUFS_##name##_DEF) \ +- seq_printf(m, "," #str "=%u", val); \ +-} while (0) +- +- /* lock free root dinfo */ +- sb = dentry->d_sb; +- si_noflush_read_lock(sb); +- sbinfo = au_sbi(sb); +- seq_printf(m, ",si=%lx", sysaufs_si_id(sbinfo)); +- +- mnt_flags = au_mntflags(sb); +- if (au_opt_test(mnt_flags, XINO)) { +- err = au_show_xino(m, sb); +- if (unlikely(err)) +- goto out; +- } else +- seq_puts(m, ",noxino"); +- +- AuBool(TRUNC_XINO, trunc_xino); +- AuStr(UDBA, udba); +- AuBool(SHWH, shwh); +- AuBool(PLINK, plink); +- AuBool(DIO, dio); +- /* AuBool(DIRPERM1, dirperm1); */ +- /* AuBool(REFROF, refrof); */ +- +- v = sbinfo->si_wbr_create; +- if (v != AuWbrCreate_Def) +- au_show_wbr_create(m, v, sbinfo); +- +- v = sbinfo->si_wbr_copyup; +- if (v != AuWbrCopyup_Def) +- seq_printf(m, ",cpup=%s", au_optstr_wbr_copyup(v)); +- +- v = au_opt_test(mnt_flags, ALWAYS_DIROPQ); +- if (v != au_opt_test(AuOpt_Def, ALWAYS_DIROPQ)) +- seq_printf(m, ",diropq=%c", v ? 'a' : 'w'); +- +- AuUInt(DIRWH, dirwh, sbinfo->si_dirwh); +- +- v = jiffies_to_msecs(sbinfo->si_rdcache) / MSEC_PER_SEC; +- AuUInt(RDCACHE, rdcache, v); +- +- AuUInt(RDBLK, rdblk, sbinfo->si_rdblk); +- AuUInt(RDHASH, rdhash, sbinfo->si_rdhash); +- +- AuBool(SUM, sum); +- /* AuBool(SUM_W, wsum); */ +- AuBool(WARN_PERM, warn_perm); +- AuBool(VERBOSE, verbose); +- +-out: +- /* be sure to print "br:" last */ +- if (!sysaufs_brs) { +- seq_puts(m, ",br:"); +- au_show_brs(m, sb); +- } +- si_read_unlock(sb); +- return 0; +- +-#undef AuBool +-#undef AuStr +-#undef AuUInt +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* sum mode which returns the summation for statfs(2) */ +- +-static u64 au_add_till_max(u64 a, u64 b) +-{ +- u64 old; +- +- old = a; +- a += b; +- if (old <= a) +- return a; +- return ULLONG_MAX; +-} +- +-static u64 au_mul_till_max(u64 a, long mul) +-{ +- u64 old; +- +- old = a; +- a *= mul; +- if (old <= a) +- return a; +- return ULLONG_MAX; +-} +- +-static int au_statfs_sum(struct super_block *sb, struct kstatfs *buf) +-{ +- int err; +- long bsize, factor; +- u64 blocks, bfree, bavail, files, ffree; +- aufs_bindex_t bend, bindex, i; +- unsigned char shared; +- struct path h_path; +- struct super_block *h_sb; +- +- err = 0; +- bsize = LONG_MAX; +- files = 0; +- ffree = 0; +- blocks = 0; +- bfree = 0; +- bavail = 0; +- bend = au_sbend(sb); +- for (bindex = 0; bindex <= bend; bindex++) { +- h_path.mnt = au_sbr_mnt(sb, bindex); +- h_sb = h_path.mnt->mnt_sb; +- shared = 0; +- for (i = 0; !shared && i < bindex; i++) +- shared = (au_sbr_sb(sb, i) == h_sb); +- if (shared) +- continue; +- +- /* sb->s_root for NFS is unreliable */ +- h_path.dentry = h_path.mnt->mnt_root; +- err = vfs_statfs(&h_path, buf); +- if (unlikely(err)) +- goto out; +- +- if (bsize > buf->f_bsize) { +- /* +- * we will reduce bsize, so we have to expand blocks +- * etc. to match them again +- */ +- factor = (bsize / buf->f_bsize); +- blocks = au_mul_till_max(blocks, factor); +- bfree = au_mul_till_max(bfree, factor); +- bavail = au_mul_till_max(bavail, factor); +- bsize = buf->f_bsize; +- } +- +- factor = (buf->f_bsize / bsize); +- blocks = au_add_till_max(blocks, +- au_mul_till_max(buf->f_blocks, factor)); +- bfree = au_add_till_max(bfree, +- au_mul_till_max(buf->f_bfree, factor)); +- bavail = au_add_till_max(bavail, +- au_mul_till_max(buf->f_bavail, factor)); +- files = au_add_till_max(files, buf->f_files); +- ffree = au_add_till_max(ffree, buf->f_ffree); +- } +- +- buf->f_bsize = bsize; +- buf->f_blocks = blocks; +- buf->f_bfree = bfree; +- buf->f_bavail = bavail; +- buf->f_files = files; +- buf->f_ffree = ffree; +- buf->f_frsize = 0; +- +-out: +- return err; +-} +- +-static int aufs_statfs(struct dentry *dentry, struct kstatfs *buf) +-{ +- int err; +- struct path h_path; +- struct super_block *sb; +- +- /* lock free root dinfo */ +- sb = dentry->d_sb; +- si_noflush_read_lock(sb); +- if (!au_opt_test(au_mntflags(sb), SUM)) { +- /* sb->s_root for NFS is unreliable */ +- h_path.mnt = au_sbr_mnt(sb, 0); +- h_path.dentry = h_path.mnt->mnt_root; +- err = vfs_statfs(&h_path, buf); +- } else +- err = au_statfs_sum(sb, buf); +- si_read_unlock(sb); +- +- if (!err) { +- buf->f_type = AUFS_SUPER_MAGIC; +- buf->f_namelen = AUFS_MAX_NAMELEN; +- memset(&buf->f_fsid, 0, sizeof(buf->f_fsid)); +- } +- /* buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1; */ +- +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static int aufs_sync_fs(struct super_block *sb, int wait) +-{ +- int err, e; +- aufs_bindex_t bend, bindex; +- struct au_branch *br; +- struct super_block *h_sb; +- +- err = 0; +- si_noflush_read_lock(sb); +- bend = au_sbend(sb); +- for (bindex = 0; bindex <= bend; bindex++) { +- br = au_sbr(sb, bindex); +- if (!au_br_writable(br->br_perm)) +- continue; +- +- h_sb = au_sbr_sb(sb, bindex); +- if (h_sb->s_op->sync_fs) { +- e = h_sb->s_op->sync_fs(h_sb, wait); +- if (unlikely(e && !err)) +- err = e; +- /* go on even if an error happens */ +- } +- } +- si_read_unlock(sb); +- +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* final actions when unmounting a file system */ +-static void aufs_put_super(struct super_block *sb) +-{ +- struct au_sbinfo *sbinfo; +- +- sbinfo = au_sbi(sb); +- if (!sbinfo) +- return; +- +- dbgaufs_si_fin(sbinfo); +- kobject_put(&sbinfo->si_kobj); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-void au_array_free(void *array) +-{ +- if (array) { +- if (!is_vmalloc_addr(array)) +- kfree(array); +- else +- vfree(array); +- } +-} +- +-void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, void *arg) +-{ +- void *array; +- unsigned long long n; +- +- array = NULL; +- n = 0; +- if (!*hint) +- goto out; +- +- if (*hint > ULLONG_MAX / sizeof(array)) { +- array = ERR_PTR(-EMFILE); +- pr_err("hint %llu\n", *hint); +- goto out; +- } +- +- array = kmalloc(sizeof(array) * *hint, GFP_NOFS); +- if (unlikely(!array)) +- array = vmalloc(sizeof(array) * *hint); +- if (unlikely(!array)) { +- array = ERR_PTR(-ENOMEM); +- goto out; +- } +- +- n = cb(array, *hint, arg); +- AuDebugOn(n > *hint); +- +-out: +- *hint = n; +- return array; +-} +- +-static unsigned long long au_iarray_cb(void *a, +- unsigned long long max __maybe_unused, +- void *arg) +-{ +- unsigned long long n; +- struct inode **p, *inode; +- struct list_head *head; +- +- n = 0; +- p = a; +- head = arg; +- spin_lock(&inode_sb_list_lock); +- list_for_each_entry(inode, head, i_sb_list) { +- if (!is_bad_inode(inode) +- && au_ii(inode)->ii_bstart >= 0) { +- spin_lock(&inode->i_lock); +- if (atomic_read(&inode->i_count)) { +- au_igrab(inode); +- *p++ = inode; +- n++; +- AuDebugOn(n > max); +- } +- spin_unlock(&inode->i_lock); +- } +- } +- spin_unlock(&inode_sb_list_lock); +- +- return n; +-} +- +-struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max) +-{ +- *max = atomic_long_read(&au_sbi(sb)->si_ninodes); +- return au_array_alloc(max, au_iarray_cb, &sb->s_inodes); +-} +- +-void au_iarray_free(struct inode **a, unsigned long long max) +-{ +- unsigned long long ull; +- +- for (ull = 0; ull < max; ull++) +- iput(a[ull]); +- au_array_free(a); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* +- * refresh dentry and inode at remount time. +- */ +-/* todo: consolidate with simple_reval_dpath() and au_reval_for_attr() */ +-static int au_do_refresh(struct dentry *dentry, unsigned int dir_flags, +- struct dentry *parent) +-{ +- int err; +- +- di_write_lock_child(dentry); +- di_read_lock_parent(parent, AuLock_IR); +- err = au_refresh_dentry(dentry, parent); +- if (!err && dir_flags) +- au_hn_reset(dentry->d_inode, dir_flags); +- di_read_unlock(parent, AuLock_IR); +- di_write_unlock(dentry); +- +- return err; +-} +- +-static int au_do_refresh_d(struct dentry *dentry, unsigned int sigen, +- struct au_sbinfo *sbinfo, +- const unsigned int dir_flags) +-{ +- int err; +- struct dentry *parent; +- struct inode *inode; +- +- err = 0; +- parent = dget_parent(dentry); +- if (!au_digen_test(parent, sigen) && au_digen_test(dentry, sigen)) { +- inode = dentry->d_inode; +- if (inode) { +- if (!S_ISDIR(inode->i_mode)) +- err = au_do_refresh(dentry, /*dir_flags*/0, +- parent); +- else { +- err = au_do_refresh(dentry, dir_flags, parent); +- if (unlikely(err)) +- au_fset_si(sbinfo, FAILED_REFRESH_DIR); +- } +- } else +- err = au_do_refresh(dentry, /*dir_flags*/0, parent); +- AuDbgDentry(dentry); +- } +- dput(parent); +- +- AuTraceErr(err); +- return err; +-} +- +-static int au_refresh_d(struct super_block *sb) +-{ +- int err, i, j, ndentry, e; +- unsigned int sigen; +- struct au_dcsub_pages dpages; +- struct au_dpage *dpage; +- struct dentry **dentries, *d; +- struct au_sbinfo *sbinfo; +- struct dentry *root = sb->s_root; +- const unsigned int dir_flags = au_hi_flags(root->d_inode, /*isdir*/1); +- +- err = au_dpages_init(&dpages, GFP_NOFS); +- if (unlikely(err)) +- goto out; +- err = au_dcsub_pages(&dpages, root, NULL, NULL); +- if (unlikely(err)) +- goto out_dpages; +- +- sigen = au_sigen(sb); +- sbinfo = au_sbi(sb); +- for (i = 0; i < dpages.ndpage; i++) { +- dpage = dpages.dpages + i; +- dentries = dpage->dentries; +- ndentry = dpage->ndentry; +- for (j = 0; j < ndentry; j++) { +- d = dentries[j]; +- e = au_do_refresh_d(d, sigen, sbinfo, dir_flags); +- if (unlikely(e && !err)) +- err = e; +- /* go on even err */ +- } +- } +- +-out_dpages: +- au_dpages_free(&dpages); +-out: +- return err; +-} +- +-static int au_refresh_i(struct super_block *sb) +-{ +- int err, e; +- unsigned int sigen; +- unsigned long long max, ull; +- struct inode *inode, **array; +- +- array = au_iarray_alloc(sb, &max); +- err = PTR_ERR(array); +- if (IS_ERR(array)) +- goto out; +- +- err = 0; +- sigen = au_sigen(sb); +- for (ull = 0; ull < max; ull++) { +- inode = array[ull]; +- if (au_iigen(inode, NULL) != sigen) { +- ii_write_lock_child(inode); +- e = au_refresh_hinode_self(inode); +- ii_write_unlock(inode); +- if (unlikely(e)) { +- pr_err("error %d, i%lu\n", e, inode->i_ino); +- if (!err) +- err = e; +- /* go on even if err */ +- } +- } +- } +- +- au_iarray_free(array, max); +- +-out: +- return err; +-} +- +-static void au_remount_refresh(struct super_block *sb) +-{ +- int err, e; +- unsigned int udba; +- aufs_bindex_t bindex, bend; +- struct dentry *root; +- struct inode *inode; +- struct au_branch *br; +- +- au_sigen_inc(sb); +- au_fclr_si(au_sbi(sb), FAILED_REFRESH_DIR); +- +- root = sb->s_root; +- DiMustNoWaiters(root); +- inode = root->d_inode; +- IiMustNoWaiters(inode); +- +- udba = au_opt_udba(sb); +- bend = au_sbend(sb); +- for (bindex = 0; bindex <= bend; bindex++) { +- br = au_sbr(sb, bindex); +- err = au_hnotify_reset_br(udba, br, br->br_perm); +- if (unlikely(err)) +- AuIOErr("hnotify failed on br %d, %d, ignored\n", +- bindex, err); +- /* go on even if err */ +- } +- au_hn_reset(inode, au_hi_flags(inode, /*isdir*/1)); +- +- di_write_unlock(root); +- err = au_refresh_d(sb); +- e = au_refresh_i(sb); +- if (unlikely(e && !err)) +- err = e; +- /* aufs_write_lock() calls ..._child() */ +- di_write_lock_child(root); +- +- au_cpup_attr_all(inode, /*force*/1); +- +- if (unlikely(err)) +- AuIOErr("refresh failed, ignored, %d\n", err); +-} +- +-/* stop extra interpretation of errno in mount(8), and strange error messages */ +-static int cvt_err(int err) +-{ +- AuTraceErr(err); +- +- switch (err) { +- case -ENOENT: +- case -ENOTDIR: +- case -EEXIST: +- case -EIO: +- err = -EINVAL; +- } +- return err; +-} +- +-static int aufs_remount_fs(struct super_block *sb, int *flags, char *data) +-{ +- int err, do_dx; +- unsigned int mntflags; +- struct au_opts opts; +- struct dentry *root; +- struct inode *inode; +- struct au_sbinfo *sbinfo; +- +- err = 0; +- root = sb->s_root; +- if (!data || !*data) { +- err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM); +- if (!err) { +- di_write_lock_child(root); +- err = au_opts_verify(sb, *flags, /*pending*/0); +- aufs_write_unlock(root); +- } +- goto out; +- } +- +- err = -ENOMEM; +- memset(&opts, 0, sizeof(opts)); +- opts.opt = (void *)__get_free_page(GFP_NOFS); +- if (unlikely(!opts.opt)) +- goto out; +- opts.max_opt = PAGE_SIZE / sizeof(*opts.opt); +- opts.flags = AuOpts_REMOUNT; +- opts.sb_flags = *flags; +- +- /* parse it before aufs lock */ +- err = au_opts_parse(sb, data, &opts); +- if (unlikely(err)) +- goto out_opts; +- +- sbinfo = au_sbi(sb); +- inode = root->d_inode; +- mutex_lock(&inode->i_mutex); +- err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM); +- if (unlikely(err)) +- goto out_mtx; +- di_write_lock_child(root); +- +- /* au_opts_remount() may return an error */ +- err = au_opts_remount(sb, &opts); +- au_opts_free(&opts); +- +- if (au_ftest_opts(opts.flags, REFRESH)) +- au_remount_refresh(sb); +- +- if (au_ftest_opts(opts.flags, REFRESH_DYAOP)) { +- mntflags = au_mntflags(sb); +- do_dx = !!au_opt_test(mntflags, DIO); +- au_dy_arefresh(do_dx); +- } +- +- aufs_write_unlock(root); +- +-out_mtx: +- mutex_unlock(&inode->i_mutex); +-out_opts: +- free_page((unsigned long)opts.opt); +-out: +- err = cvt_err(err); +- AuTraceErr(err); +- return err; +-} +- +-static const struct super_operations aufs_sop = { +- .alloc_inode = aufs_alloc_inode, +- .destroy_inode = aufs_destroy_inode, +- /* always deleting, no clearing */ +- .drop_inode = generic_delete_inode, +- .show_options = aufs_show_options, +- .statfs = aufs_statfs, +- .put_super = aufs_put_super, +- .sync_fs = aufs_sync_fs, +- .remount_fs = aufs_remount_fs +-}; +- +-/* ---------------------------------------------------------------------- */ +- +-static int alloc_root(struct super_block *sb) +-{ +- int err; +- struct inode *inode; +- struct dentry *root; +- +- err = -ENOMEM; +- inode = au_iget_locked(sb, AUFS_ROOT_INO); +- err = PTR_ERR(inode); +- if (IS_ERR(inode)) +- goto out; +- +- inode->i_op = &aufs_dir_iop; +- inode->i_fop = &aufs_dir_fop; +- inode->i_mode = S_IFDIR; +- set_nlink(inode, 2); +- unlock_new_inode(inode); +- +- root = d_make_root(inode); +- if (unlikely(!root)) +- goto out; +- err = PTR_ERR(root); +- if (IS_ERR(root)) +- goto out; +- +- err = au_di_init(root); +- if (!err) { +- sb->s_root = root; +- return 0; /* success */ +- } +- dput(root); +- +-out: +- return err; +-} +- +-static int aufs_fill_super(struct super_block *sb, void *raw_data, +- int silent __maybe_unused) +-{ +- int err; +- struct au_opts opts; +- struct dentry *root; +- struct inode *inode; +- char *arg = raw_data; +- +- if (unlikely(!arg || !*arg)) { +- err = -EINVAL; +- pr_err("no arg\n"); +- goto out; +- } +- +- err = -ENOMEM; +- memset(&opts, 0, sizeof(opts)); +- opts.opt = (void *)__get_free_page(GFP_NOFS); +- if (unlikely(!opts.opt)) +- goto out; +- opts.max_opt = PAGE_SIZE / sizeof(*opts.opt); +- opts.sb_flags = sb->s_flags; +- +- err = au_si_alloc(sb); +- if (unlikely(err)) +- goto out_opts; +- +- /* all timestamps always follow the ones on the branch */ +- sb->s_flags |= MS_NOATIME | MS_NODIRATIME; +- sb->s_op = &aufs_sop; +- sb->s_d_op = &aufs_dop; +- sb->s_magic = AUFS_SUPER_MAGIC; +- sb->s_maxbytes = 0; +- au_export_init(sb); +- +- err = alloc_root(sb); +- if (unlikely(err)) { +- si_write_unlock(sb); +- goto out_info; +- } +- root = sb->s_root; +- inode = root->d_inode; +- +- /* +- * actually we can parse options regardless aufs lock here. +- * but at remount time, parsing must be done before aufs lock. +- * so we follow the same rule. +- */ +- ii_write_lock_parent(inode); +- aufs_write_unlock(root); +- err = au_opts_parse(sb, arg, &opts); +- if (unlikely(err)) +- goto out_root; +- +- /* lock vfs_inode first, then aufs. */ +- mutex_lock(&inode->i_mutex); +- aufs_write_lock(root); +- err = au_opts_mount(sb, &opts); +- au_opts_free(&opts); +- aufs_write_unlock(root); +- mutex_unlock(&inode->i_mutex); +- if (!err) +- goto out_opts; /* success */ +- +-out_root: +- dput(root); +- sb->s_root = NULL; +-out_info: +- dbgaufs_si_fin(au_sbi(sb)); +- kobject_put(&au_sbi(sb)->si_kobj); +- sb->s_fs_info = NULL; +-out_opts: +- free_page((unsigned long)opts.opt); +-out: +- AuTraceErr(err); +- err = cvt_err(err); +- AuTraceErr(err); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static struct dentry *aufs_mount(struct file_system_type *fs_type, int flags, +- const char *dev_name __maybe_unused, +- void *raw_data) +-{ +- struct dentry *root; +- struct super_block *sb; +- +- /* all timestamps always follow the ones on the branch */ +- /* mnt->mnt_flags |= MNT_NOATIME | MNT_NODIRATIME; */ +- root = mount_nodev(fs_type, flags, raw_data, aufs_fill_super); +- if (IS_ERR(root)) +- goto out; +- +- sb = root->d_sb; +- si_write_lock(sb, !AuLock_FLUSH); +- sysaufs_brs_add(sb, 0); +- si_write_unlock(sb); +- au_sbilist_add(sb); +- +-out: +- return root; +-} +- +-static void aufs_kill_sb(struct super_block *sb) +-{ +- struct au_sbinfo *sbinfo; +- +- sbinfo = au_sbi(sb); +- if (sbinfo) { +- au_sbilist_del(sb); +- aufs_write_lock(sb->s_root); +- if (sbinfo->si_wbr_create_ops->fin) +- sbinfo->si_wbr_create_ops->fin(sb); +- if (au_opt_test(sbinfo->si_mntflags, UDBA_HNOTIFY)) { +- au_opt_set_udba(sbinfo->si_mntflags, UDBA_NONE); +- au_remount_refresh(sb); +- } +- if (au_opt_test(sbinfo->si_mntflags, PLINK)) +- au_plink_put(sb, /*verbose*/1); +- au_xino_clr(sb); +- sbinfo->si_sb = NULL; +- aufs_write_unlock(sb->s_root); +- au_nwt_flush(&sbinfo->si_nowait); +- } +- generic_shutdown_super(sb); +-} +- +-struct file_system_type aufs_fs_type = { +- .name = AUFS_FSTYPE, +- .fs_flags = +- FS_RENAME_DOES_D_MOVE /* a race between rename and others */ +- | FS_REVAL_DOT, /* for NFS branch and udba */ +- .mount = aufs_mount, +- .kill_sb = aufs_kill_sb, +- /* no need to __module_get() and module_put(). */ +- .owner = THIS_MODULE, +-}; +diff --git a/fs/aufs/super.h b/fs/aufs/super.h +deleted file mode 100644 +index 33cd929..0000000 +--- a/fs/aufs/super.h ++++ /dev/null +@@ -1,538 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * super_block operations +- */ +- +-#ifndef __AUFS_SUPER_H__ +-#define __AUFS_SUPER_H__ +- +-#ifdef __KERNEL__ +- +-#include +-#include "rwsem.h" +-#include "spl.h" +-#include "wkq.h" +- +-typedef ssize_t (*au_readf_t)(struct file *, char __user *, size_t, loff_t *); +-typedef ssize_t (*au_writef_t)(struct file *, const char __user *, size_t, +- loff_t *); +- +-/* policies to select one among multiple writable branches */ +-struct au_wbr_copyup_operations { +- int (*copyup)(struct dentry *dentry); +-}; +- +-struct au_wbr_create_operations { +- int (*create)(struct dentry *dentry, int isdir); +- int (*init)(struct super_block *sb); +- int (*fin)(struct super_block *sb); +-}; +- +-struct au_wbr_mfs { +- struct mutex mfs_lock; /* protect this structure */ +- unsigned long mfs_jiffy; +- unsigned long mfs_expire; +- aufs_bindex_t mfs_bindex; +- +- unsigned long long mfsrr_bytes; +- unsigned long long mfsrr_watermark; +-}; +- +-struct au_branch; +-struct au_sbinfo { +- /* nowait tasks in the system-wide workqueue */ +- struct au_nowait_tasks si_nowait; +- +- /* +- * tried sb->s_umount, but failed due to the dependecy between i_mutex. +- * rwsem for au_sbinfo is necessary. +- */ +- struct au_rwsem si_rwsem; +- +- /* prevent recursive locking in deleting inode */ +- struct { +- unsigned long *bitmap; +- spinlock_t tree_lock; +- struct radix_tree_root tree; +- } au_si_pid; +- +- /* +- * dirty approach to protect sb->sb_inodes and ->s_files from remount. +- */ +- atomic_long_t si_ninodes, si_nfiles; +- +- /* branch management */ +- unsigned int si_generation; +- +- /* see above flags */ +- unsigned char au_si_status; +- +- aufs_bindex_t si_bend; +- +- /* dirty trick to keep br_id plus */ +- unsigned int si_last_br_id : +- sizeof(aufs_bindex_t) * BITS_PER_BYTE - 1; +- struct au_branch **si_branch; +- +- /* policy to select a writable branch */ +- unsigned char si_wbr_copyup; +- unsigned char si_wbr_create; +- struct au_wbr_copyup_operations *si_wbr_copyup_ops; +- struct au_wbr_create_operations *si_wbr_create_ops; +- +- /* round robin */ +- atomic_t si_wbr_rr_next; +- +- /* most free space */ +- struct au_wbr_mfs si_wbr_mfs; +- +- /* mount flags */ +- /* include/asm-ia64/siginfo.h defines a macro named si_flags */ +- unsigned int si_mntflags; +- +- /* external inode number (bitmap and translation table) */ +- au_readf_t si_xread; +- au_writef_t si_xwrite; +- struct file *si_xib; +- struct mutex si_xib_mtx; /* protect xib members */ +- unsigned long *si_xib_buf; +- unsigned long si_xib_last_pindex; +- int si_xib_next_bit; +- aufs_bindex_t si_xino_brid; +- /* reserved for future use */ +- /* unsigned long long si_xib_limit; */ /* Max xib file size */ +- +-#ifdef CONFIG_AUFS_EXPORT +- /* i_generation */ +- struct file *si_xigen; +- atomic_t si_xigen_next; +-#endif +- +- /* vdir parameters */ +- unsigned long si_rdcache; /* max cache time in jiffies */ +- unsigned int si_rdblk; /* deblk size */ +- unsigned int si_rdhash; /* hash size */ +- +- /* +- * If the number of whiteouts are larger than si_dirwh, leave all of +- * them after au_whtmp_ren to reduce the cost of rmdir(2). +- * future fsck.aufs or kernel thread will remove them later. +- * Otherwise, remove all whiteouts and the dir in rmdir(2). +- */ +- unsigned int si_dirwh; +- +- /* +- * rename(2) a directory with all children. +- */ +- /* reserved for future use */ +- /* int si_rendir; */ +- +- /* pseudo_link list */ +- struct au_splhead si_plink; +- wait_queue_head_t si_plink_wq; +- spinlock_t si_plink_maint_lock; +- pid_t si_plink_maint_pid; +- +- /* +- * sysfs and lifetime management. +- * this is not a small structure and it may be a waste of memory in case +- * of sysfs is disabled, particulary when many aufs-es are mounted. +- * but using sysfs is majority. +- */ +- struct kobject si_kobj; +-#ifdef CONFIG_DEBUG_FS +- struct dentry *si_dbgaufs, *si_dbgaufs_xib; +-#ifdef CONFIG_AUFS_EXPORT +- struct dentry *si_dbgaufs_xigen; +-#endif +-#endif +- +-#ifdef CONFIG_AUFS_SBILIST +- struct list_head si_list; +-#endif +- +- /* dirty, necessary for unmounting, sysfs and sysrq */ +- struct super_block *si_sb; +-}; +- +-/* sbinfo status flags */ +-/* +- * set true when refresh_dirs() failed at remount time. +- * then try refreshing dirs at access time again. +- * if it is false, refreshing dirs at access time is unnecesary +- */ +-#define AuSi_FAILED_REFRESH_DIR 1 +-static inline unsigned char au_do_ftest_si(struct au_sbinfo *sbi, +- unsigned int flag) +-{ +- AuRwMustAnyLock(&sbi->si_rwsem); +- return sbi->au_si_status & flag; +-} +-#define au_ftest_si(sbinfo, name) au_do_ftest_si(sbinfo, AuSi_##name) +-#define au_fset_si(sbinfo, name) do { \ +- AuRwMustWriteLock(&(sbinfo)->si_rwsem); \ +- (sbinfo)->au_si_status |= AuSi_##name; \ +-} while (0) +-#define au_fclr_si(sbinfo, name) do { \ +- AuRwMustWriteLock(&(sbinfo)->si_rwsem); \ +- (sbinfo)->au_si_status &= ~AuSi_##name; \ +-} while (0) +- +-/* ---------------------------------------------------------------------- */ +- +-/* policy to select one among writable branches */ +-#define AuWbrCopyup(sbinfo, ...) \ +- ((sbinfo)->si_wbr_copyup_ops->copyup(__VA_ARGS__)) +-#define AuWbrCreate(sbinfo, ...) \ +- ((sbinfo)->si_wbr_create_ops->create(__VA_ARGS__)) +- +-/* flags for si_read_lock()/aufs_read_lock()/di_read_lock() */ +-#define AuLock_DW 1 /* write-lock dentry */ +-#define AuLock_IR (1 << 1) /* read-lock inode */ +-#define AuLock_IW (1 << 2) /* write-lock inode */ +-#define AuLock_FLUSH (1 << 3) /* wait for 'nowait' tasks */ +-#define AuLock_DIR (1 << 4) /* target is a dir */ +-#define AuLock_NOPLM (1 << 5) /* return err in plm mode */ +-#define AuLock_NOPLMW (1 << 6) /* wait for plm mode ends */ +-#define AuLock_GEN (1 << 7) /* test digen/iigen */ +-#define au_ftest_lock(flags, name) ((flags) & AuLock_##name) +-#define au_fset_lock(flags, name) \ +- do { (flags) |= AuLock_##name; } while (0) +-#define au_fclr_lock(flags, name) \ +- do { (flags) &= ~AuLock_##name; } while (0) +- +-/* ---------------------------------------------------------------------- */ +- +-/* super.c */ +-extern struct file_system_type aufs_fs_type; +-struct inode *au_iget_locked(struct super_block *sb, ino_t ino); +-typedef unsigned long long (*au_arraycb_t)(void *array, unsigned long long max, +- void *arg); +-void au_array_free(void *array); +-void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, void *arg); +-struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max); +-void au_iarray_free(struct inode **a, unsigned long long max); +- +-/* sbinfo.c */ +-void au_si_free(struct kobject *kobj); +-int au_si_alloc(struct super_block *sb); +-int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr); +- +-unsigned int au_sigen_inc(struct super_block *sb); +-aufs_bindex_t au_new_br_id(struct super_block *sb); +- +-int si_read_lock(struct super_block *sb, int flags); +-int si_write_lock(struct super_block *sb, int flags); +-int aufs_read_lock(struct dentry *dentry, int flags); +-void aufs_read_unlock(struct dentry *dentry, int flags); +-void aufs_write_lock(struct dentry *dentry); +-void aufs_write_unlock(struct dentry *dentry); +-int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags); +-void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2); +- +-int si_pid_test_slow(struct super_block *sb); +-void si_pid_set_slow(struct super_block *sb); +-void si_pid_clr_slow(struct super_block *sb); +- +-/* wbr_policy.c */ +-extern struct au_wbr_copyup_operations au_wbr_copyup_ops[]; +-extern struct au_wbr_create_operations au_wbr_create_ops[]; +-int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst); +- +-/* ---------------------------------------------------------------------- */ +- +-static inline struct au_sbinfo *au_sbi(struct super_block *sb) +-{ +- return sb->s_fs_info; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-#ifdef CONFIG_AUFS_EXPORT +-int au_test_nfsd(void); +-void au_export_init(struct super_block *sb); +-void au_xigen_inc(struct inode *inode); +-int au_xigen_new(struct inode *inode); +-int au_xigen_set(struct super_block *sb, struct file *base); +-void au_xigen_clr(struct super_block *sb); +- +-static inline int au_busy_or_stale(void) +-{ +- if (!au_test_nfsd()) +- return -EBUSY; +- return -ESTALE; +-} +-#else +-AuStubInt0(au_test_nfsd, void) +-AuStubVoid(au_export_init, struct super_block *sb) +-AuStubVoid(au_xigen_inc, struct inode *inode) +-AuStubInt0(au_xigen_new, struct inode *inode) +-AuStubInt0(au_xigen_set, struct super_block *sb, struct file *base) +-AuStubVoid(au_xigen_clr, struct super_block *sb) +-static inline int au_busy_or_stale(void) +-{ +- return -EBUSY; +-} +-#endif /* CONFIG_AUFS_EXPORT */ +- +-/* ---------------------------------------------------------------------- */ +- +-#ifdef CONFIG_AUFS_SBILIST +-/* module.c */ +-extern struct au_splhead au_sbilist; +- +-static inline void au_sbilist_init(void) +-{ +- au_spl_init(&au_sbilist); +-} +- +-static inline void au_sbilist_add(struct super_block *sb) +-{ +- au_spl_add(&au_sbi(sb)->si_list, &au_sbilist); +-} +- +-static inline void au_sbilist_del(struct super_block *sb) +-{ +- au_spl_del(&au_sbi(sb)->si_list, &au_sbilist); +-} +- +-#ifdef CONFIG_AUFS_MAGIC_SYSRQ +-static inline void au_sbilist_lock(void) +-{ +- spin_lock(&au_sbilist.spin); +-} +- +-static inline void au_sbilist_unlock(void) +-{ +- spin_unlock(&au_sbilist.spin); +-} +-#define AuGFP_SBILIST GFP_ATOMIC +-#else +-AuStubVoid(au_sbilist_lock, void) +-AuStubVoid(au_sbilist_unlock, void) +-#define AuGFP_SBILIST GFP_NOFS +-#endif /* CONFIG_AUFS_MAGIC_SYSRQ */ +-#else +-AuStubVoid(au_sbilist_init, void) +-AuStubVoid(au_sbilist_add, struct super_block*) +-AuStubVoid(au_sbilist_del, struct super_block*) +-AuStubVoid(au_sbilist_lock, void) +-AuStubVoid(au_sbilist_unlock, void) +-#define AuGFP_SBILIST GFP_NOFS +-#endif +- +-/* ---------------------------------------------------------------------- */ +- +-static inline void dbgaufs_si_null(struct au_sbinfo *sbinfo) +-{ +- /* +- * This function is a dynamic '__init' fucntion actually, +- * so the tiny check for si_rwsem is unnecessary. +- */ +- /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ +-#ifdef CONFIG_DEBUG_FS +- sbinfo->si_dbgaufs = NULL; +- sbinfo->si_dbgaufs_xib = NULL; +-#ifdef CONFIG_AUFS_EXPORT +- sbinfo->si_dbgaufs_xigen = NULL; +-#endif +-#endif +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static inline pid_t si_pid_bit(void) +-{ +- /* the origin of pid is 1, but the bitmap's is 0 */ +- return current->pid - 1; +-} +- +-static inline int si_pid_test(struct super_block *sb) +-{ +- pid_t bit = si_pid_bit(); +- if (bit < PID_MAX_DEFAULT) +- return test_bit(bit, au_sbi(sb)->au_si_pid.bitmap); +- else +- return si_pid_test_slow(sb); +-} +- +-static inline void si_pid_set(struct super_block *sb) +-{ +- pid_t bit = si_pid_bit(); +- if (bit < PID_MAX_DEFAULT) { +- AuDebugOn(test_bit(bit, au_sbi(sb)->au_si_pid.bitmap)); +- set_bit(bit, au_sbi(sb)->au_si_pid.bitmap); +- /* smp_mb(); */ +- } else +- si_pid_set_slow(sb); +-} +- +-static inline void si_pid_clr(struct super_block *sb) +-{ +- pid_t bit = si_pid_bit(); +- if (bit < PID_MAX_DEFAULT) { +- AuDebugOn(!test_bit(bit, au_sbi(sb)->au_si_pid.bitmap)); +- clear_bit(bit, au_sbi(sb)->au_si_pid.bitmap); +- /* smp_mb(); */ +- } else +- si_pid_clr_slow(sb); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* lock superblock. mainly for entry point functions */ +-/* +- * __si_read_lock, __si_write_lock, +- * __si_read_unlock, __si_write_unlock, __si_downgrade_lock +- */ +-AuSimpleRwsemFuncs(__si, struct super_block *sb, &au_sbi(sb)->si_rwsem); +- +-#define SiMustNoWaiters(sb) AuRwMustNoWaiters(&au_sbi(sb)->si_rwsem) +-#define SiMustAnyLock(sb) AuRwMustAnyLock(&au_sbi(sb)->si_rwsem) +-#define SiMustWriteLock(sb) AuRwMustWriteLock(&au_sbi(sb)->si_rwsem) +- +-static inline void si_noflush_read_lock(struct super_block *sb) +-{ +- __si_read_lock(sb); +- si_pid_set(sb); +-} +- +-static inline int si_noflush_read_trylock(struct super_block *sb) +-{ +- int locked = __si_read_trylock(sb); +- if (locked) +- si_pid_set(sb); +- return locked; +-} +- +-static inline void si_noflush_write_lock(struct super_block *sb) +-{ +- __si_write_lock(sb); +- si_pid_set(sb); +-} +- +-static inline int si_noflush_write_trylock(struct super_block *sb) +-{ +- int locked = __si_write_trylock(sb); +- if (locked) +- si_pid_set(sb); +- return locked; +-} +- +-#if 0 /* unused */ +-static inline int si_read_trylock(struct super_block *sb, int flags) +-{ +- if (au_ftest_lock(flags, FLUSH)) +- au_nwt_flush(&au_sbi(sb)->si_nowait); +- return si_noflush_read_trylock(sb); +-} +-#endif +- +-static inline void si_read_unlock(struct super_block *sb) +-{ +- si_pid_clr(sb); +- __si_read_unlock(sb); +-} +- +-#if 0 /* unused */ +-static inline int si_write_trylock(struct super_block *sb, int flags) +-{ +- if (au_ftest_lock(flags, FLUSH)) +- au_nwt_flush(&au_sbi(sb)->si_nowait); +- return si_noflush_write_trylock(sb); +-} +-#endif +- +-static inline void si_write_unlock(struct super_block *sb) +-{ +- si_pid_clr(sb); +- __si_write_unlock(sb); +-} +- +-#if 0 /* unused */ +-static inline void si_downgrade_lock(struct super_block *sb) +-{ +- __si_downgrade_lock(sb); +-} +-#endif +- +-/* ---------------------------------------------------------------------- */ +- +-static inline aufs_bindex_t au_sbend(struct super_block *sb) +-{ +- SiMustAnyLock(sb); +- return au_sbi(sb)->si_bend; +-} +- +-static inline unsigned int au_mntflags(struct super_block *sb) +-{ +- SiMustAnyLock(sb); +- return au_sbi(sb)->si_mntflags; +-} +- +-static inline unsigned int au_sigen(struct super_block *sb) +-{ +- SiMustAnyLock(sb); +- return au_sbi(sb)->si_generation; +-} +- +-static inline void au_ninodes_inc(struct super_block *sb) +-{ +- atomic_long_inc(&au_sbi(sb)->si_ninodes); +-} +- +-static inline void au_ninodes_dec(struct super_block *sb) +-{ +- AuDebugOn(!atomic_long_read(&au_sbi(sb)->si_ninodes)); +- atomic_long_dec(&au_sbi(sb)->si_ninodes); +-} +- +-static inline void au_nfiles_inc(struct super_block *sb) +-{ +- atomic_long_inc(&au_sbi(sb)->si_nfiles); +-} +- +-static inline void au_nfiles_dec(struct super_block *sb) +-{ +- AuDebugOn(!atomic_long_read(&au_sbi(sb)->si_nfiles)); +- atomic_long_dec(&au_sbi(sb)->si_nfiles); +-} +- +-static inline struct au_branch *au_sbr(struct super_block *sb, +- aufs_bindex_t bindex) +-{ +- SiMustAnyLock(sb); +- return au_sbi(sb)->si_branch[0 + bindex]; +-} +- +-static inline void au_xino_brid_set(struct super_block *sb, aufs_bindex_t brid) +-{ +- SiMustWriteLock(sb); +- au_sbi(sb)->si_xino_brid = brid; +-} +- +-static inline aufs_bindex_t au_xino_brid(struct super_block *sb) +-{ +- SiMustAnyLock(sb); +- return au_sbi(sb)->si_xino_brid; +-} +- +-#endif /* __KERNEL__ */ +-#endif /* __AUFS_SUPER_H__ */ +diff --git a/fs/aufs/sysaufs.c b/fs/aufs/sysaufs.c +deleted file mode 100644 +index f68e844..0000000 +--- a/fs/aufs/sysaufs.c ++++ /dev/null +@@ -1,105 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * sysfs interface and lifetime management +- * they are necessary regardless sysfs is disabled. +- */ +- +-#include +-#include "aufs.h" +- +-unsigned long sysaufs_si_mask; +-struct kset *sysaufs_kset; +- +-#define AuSiAttr(_name) { \ +- .attr = { .name = __stringify(_name), .mode = 0444 }, \ +- .show = sysaufs_si_##_name, \ +-} +- +-static struct sysaufs_si_attr sysaufs_si_attr_xi_path = AuSiAttr(xi_path); +-struct attribute *sysaufs_si_attrs[] = { +- &sysaufs_si_attr_xi_path.attr, +- NULL, +-}; +- +-static const struct sysfs_ops au_sbi_ops = { +- .show = sysaufs_si_show +-}; +- +-static struct kobj_type au_sbi_ktype = { +- .release = au_si_free, +- .sysfs_ops = &au_sbi_ops, +- .default_attrs = sysaufs_si_attrs +-}; +- +-/* ---------------------------------------------------------------------- */ +- +-int sysaufs_si_init(struct au_sbinfo *sbinfo) +-{ +- int err; +- +- sbinfo->si_kobj.kset = sysaufs_kset; +- /* cf. sysaufs_name() */ +- err = kobject_init_and_add +- (&sbinfo->si_kobj, &au_sbi_ktype, /*&sysaufs_kset->kobj*/NULL, +- SysaufsSiNamePrefix "%lx", sysaufs_si_id(sbinfo)); +- +- dbgaufs_si_null(sbinfo); +- if (!err) { +- err = dbgaufs_si_init(sbinfo); +- if (unlikely(err)) +- kobject_put(&sbinfo->si_kobj); +- } +- return err; +-} +- +-void sysaufs_fin(void) +-{ +- dbgaufs_fin(); +- sysfs_remove_group(&sysaufs_kset->kobj, sysaufs_attr_group); +- kset_unregister(sysaufs_kset); +-} +- +-int __init sysaufs_init(void) +-{ +- int err; +- +- do { +- get_random_bytes(&sysaufs_si_mask, sizeof(sysaufs_si_mask)); +- } while (!sysaufs_si_mask); +- +- err = -EINVAL; +- sysaufs_kset = kset_create_and_add(AUFS_NAME, NULL, fs_kobj); +- if (unlikely(!sysaufs_kset)) +- goto out; +- err = PTR_ERR(sysaufs_kset); +- if (IS_ERR(sysaufs_kset)) +- goto out; +- err = sysfs_create_group(&sysaufs_kset->kobj, sysaufs_attr_group); +- if (unlikely(err)) { +- kset_unregister(sysaufs_kset); +- goto out; +- } +- +- err = dbgaufs_init(); +- if (unlikely(err)) +- sysaufs_fin(); +-out: +- return err; +-} +diff --git a/fs/aufs/sysaufs.h b/fs/aufs/sysaufs.h +deleted file mode 100644 +index 2fc17d9..0000000 +--- a/fs/aufs/sysaufs.h ++++ /dev/null +@@ -1,104 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * sysfs interface and mount lifetime management +- */ +- +-#ifndef __SYSAUFS_H__ +-#define __SYSAUFS_H__ +- +-#ifdef __KERNEL__ +- +-#include +-#include "module.h" +- +-struct super_block; +-struct au_sbinfo; +- +-struct sysaufs_si_attr { +- struct attribute attr; +- int (*show)(struct seq_file *seq, struct super_block *sb); +-}; +- +-/* ---------------------------------------------------------------------- */ +- +-/* sysaufs.c */ +-extern unsigned long sysaufs_si_mask; +-extern struct kset *sysaufs_kset; +-extern struct attribute *sysaufs_si_attrs[]; +-int sysaufs_si_init(struct au_sbinfo *sbinfo); +-int __init sysaufs_init(void); +-void sysaufs_fin(void); +- +-/* ---------------------------------------------------------------------- */ +- +-/* some people doesn't like to show a pointer in kernel */ +-static inline unsigned long sysaufs_si_id(struct au_sbinfo *sbinfo) +-{ +- return sysaufs_si_mask ^ (unsigned long)sbinfo; +-} +- +-#define SysaufsSiNamePrefix "si_" +-#define SysaufsSiNameLen (sizeof(SysaufsSiNamePrefix) + 16) +-static inline void sysaufs_name(struct au_sbinfo *sbinfo, char *name) +-{ +- snprintf(name, SysaufsSiNameLen, SysaufsSiNamePrefix "%lx", +- sysaufs_si_id(sbinfo)); +-} +- +-struct au_branch; +-#ifdef CONFIG_SYSFS +-/* sysfs.c */ +-extern struct attribute_group *sysaufs_attr_group; +- +-int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb); +-ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, +- char *buf); +- +-void sysaufs_br_init(struct au_branch *br); +-void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex); +-void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex); +- +-#define sysaufs_brs_init() do {} while (0) +- +-#else +-#define sysaufs_attr_group NULL +- +-AuStubInt0(sysaufs_si_xi_path, struct seq_file *seq, struct super_block *sb) +- +-static inline +-ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, +- char *buf) +-{ +- return 0; +-} +- +-AuStubVoid(sysaufs_br_init, struct au_branch *br) +-AuStubVoid(sysaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex) +-AuStubVoid(sysaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex) +- +-static inline void sysaufs_brs_init(void) +-{ +- sysaufs_brs = 0; +-} +- +-#endif /* CONFIG_SYSFS */ +- +-#endif /* __KERNEL__ */ +-#endif /* __SYSAUFS_H__ */ +diff --git a/fs/aufs/sysfs.c b/fs/aufs/sysfs.c +deleted file mode 100644 +index 2d73ab0..0000000 +--- a/fs/aufs/sysfs.c ++++ /dev/null +@@ -1,257 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * sysfs interface +- */ +- +-#include +-#include "aufs.h" +- +-#ifdef CONFIG_AUFS_FS_MODULE +-/* this entry violates the "one line per file" policy of sysfs */ +-static ssize_t config_show(struct kobject *kobj, struct kobj_attribute *attr, +- char *buf) +-{ +- ssize_t err; +- static char *conf = +-/* this file is generated at compiling */ +-#include "conf.str" +- ; +- +- err = snprintf(buf, PAGE_SIZE, conf); +- if (unlikely(err >= PAGE_SIZE)) +- err = -EFBIG; +- return err; +-} +- +-static struct kobj_attribute au_config_attr = __ATTR_RO(config); +-#endif +- +-static struct attribute *au_attr[] = { +-#ifdef CONFIG_AUFS_FS_MODULE +- &au_config_attr.attr, +-#endif +- NULL, /* need to NULL terminate the list of attributes */ +-}; +- +-static struct attribute_group sysaufs_attr_group_body = { +- .attrs = au_attr +-}; +- +-struct attribute_group *sysaufs_attr_group = &sysaufs_attr_group_body; +- +-/* ---------------------------------------------------------------------- */ +- +-int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb) +-{ +- int err; +- +- SiMustAnyLock(sb); +- +- err = 0; +- if (au_opt_test(au_mntflags(sb), XINO)) { +- err = au_xino_path(seq, au_sbi(sb)->si_xib); +- seq_putc(seq, '\n'); +- } +- return err; +-} +- +-/* +- * the lifetime of branch is independent from the entry under sysfs. +- * sysfs handles the lifetime of the entry, and never call ->show() after it is +- * unlinked. +- */ +-static int sysaufs_si_br(struct seq_file *seq, struct super_block *sb, +- aufs_bindex_t bindex) +-{ +- int err; +- struct path path; +- struct dentry *root; +- struct au_branch *br; +- char *perm; +- +- AuDbg("b%d\n", bindex); +- +- err = 0; +- root = sb->s_root; +- di_read_lock_parent(root, !AuLock_IR); +- br = au_sbr(sb, bindex); +- path.mnt = br->br_mnt; +- path.dentry = au_h_dptr(root, bindex); +- au_seq_path(seq, &path); +- di_read_unlock(root, !AuLock_IR); +- perm = au_optstr_br_perm(br->br_perm); +- if (perm) { +- err = seq_printf(seq, "=%s\n", perm); +- kfree(perm); +- if (err == -1) +- err = -E2BIG; +- } else +- err = -ENOMEM; +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static struct seq_file *au_seq(char *p, ssize_t len) +-{ +- struct seq_file *seq; +- +- seq = kzalloc(sizeof(*seq), GFP_NOFS); +- if (seq) { +- /* mutex_init(&seq.lock); */ +- seq->buf = p; +- seq->size = len; +- return seq; /* success */ +- } +- +- seq = ERR_PTR(-ENOMEM); +- return seq; +-} +- +-#define SysaufsBr_PREFIX "br" +- +-/* todo: file size may exceed PAGE_SIZE */ +-ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, +- char *buf) +-{ +- ssize_t err; +- long l; +- aufs_bindex_t bend; +- struct au_sbinfo *sbinfo; +- struct super_block *sb; +- struct seq_file *seq; +- char *name; +- struct attribute **cattr; +- +- sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); +- sb = sbinfo->si_sb; +- +- /* +- * prevent a race condition between sysfs and aufs. +- * for instance, sysfs_file_read() calls sysfs_get_active_two() which +- * prohibits maintaining the sysfs entries. +- * hew we acquire read lock after sysfs_get_active_two(). +- * on the other hand, the remount process may maintain the sysfs/aufs +- * entries after acquiring write lock. +- * it can cause a deadlock. +- * simply we gave up processing read here. +- */ +- err = -EBUSY; +- if (unlikely(!si_noflush_read_trylock(sb))) +- goto out; +- +- seq = au_seq(buf, PAGE_SIZE); +- err = PTR_ERR(seq); +- if (IS_ERR(seq)) +- goto out_unlock; +- +- name = (void *)attr->name; +- cattr = sysaufs_si_attrs; +- while (*cattr) { +- if (!strcmp(name, (*cattr)->name)) { +- err = container_of(*cattr, struct sysaufs_si_attr, attr) +- ->show(seq, sb); +- goto out_seq; +- } +- cattr++; +- } +- +- bend = au_sbend(sb); +- if (!strncmp(name, SysaufsBr_PREFIX, sizeof(SysaufsBr_PREFIX) - 1)) { +- name += sizeof(SysaufsBr_PREFIX) - 1; +- err = kstrtol(name, 10, &l); +- if (!err) { +- if (l <= bend) +- err = sysaufs_si_br(seq, sb, (aufs_bindex_t)l); +- else +- err = -ENOENT; +- } +- goto out_seq; +- } +- BUG(); +- +-out_seq: +- if (!err) { +- err = seq->count; +- /* sysfs limit */ +- if (unlikely(err == PAGE_SIZE)) +- err = -EFBIG; +- } +- kfree(seq); +-out_unlock: +- si_read_unlock(sb); +-out: +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-void sysaufs_br_init(struct au_branch *br) +-{ +- struct attribute *attr = &br->br_attr; +- +- sysfs_attr_init(attr); +- attr->name = br->br_name; +- attr->mode = S_IRUGO; +-} +- +-void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) +-{ +- struct au_branch *br; +- struct kobject *kobj; +- aufs_bindex_t bend; +- +- dbgaufs_brs_del(sb, bindex); +- +- if (!sysaufs_brs) +- return; +- +- kobj = &au_sbi(sb)->si_kobj; +- bend = au_sbend(sb); +- for (; bindex <= bend; bindex++) { +- br = au_sbr(sb, bindex); +- sysfs_remove_file(kobj, &br->br_attr); +- } +-} +- +-void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex) +-{ +- int err; +- aufs_bindex_t bend; +- struct kobject *kobj; +- struct au_branch *br; +- +- dbgaufs_brs_add(sb, bindex); +- +- if (!sysaufs_brs) +- return; +- +- kobj = &au_sbi(sb)->si_kobj; +- bend = au_sbend(sb); +- for (; bindex <= bend; bindex++) { +- br = au_sbr(sb, bindex); +- snprintf(br->br_name, sizeof(br->br_name), SysaufsBr_PREFIX +- "%d", bindex); +- err = sysfs_create_file(kobj, &br->br_attr); +- if (unlikely(err)) +- pr_warn("failed %s under sysfs(%d)\n", +- br->br_name, err); +- } +-} +diff --git a/fs/aufs/sysrq.c b/fs/aufs/sysrq.c +deleted file mode 100644 +index 86ff120..0000000 +--- a/fs/aufs/sysrq.c ++++ /dev/null +@@ -1,151 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * magic sysrq hanlder +- */ +- +-/* #include */ +-#include +-#include "aufs.h" +- +-/* ---------------------------------------------------------------------- */ +- +-static void sysrq_sb(struct super_block *sb) +-{ +- char *plevel; +- struct au_sbinfo *sbinfo; +- struct file *file; +- +- plevel = au_plevel; +- au_plevel = KERN_WARNING; +- +- /* since we define pr_fmt, call printk directly */ +-#define pr(str) printk(KERN_WARNING AUFS_NAME ": " str) +- +- sbinfo = au_sbi(sb); +- printk(KERN_WARNING "si=%lx\n", sysaufs_si_id(sbinfo)); +- pr("superblock\n"); +- au_dpri_sb(sb); +- +-#if 0 +- pr("root dentry\n"); +- au_dpri_dentry(sb->s_root); +- pr("root inode\n"); +- au_dpri_inode(sb->s_root->d_inode); +-#endif +- +-#if 0 +- do { +- int err, i, j, ndentry; +- struct au_dcsub_pages dpages; +- struct au_dpage *dpage; +- +- err = au_dpages_init(&dpages, GFP_ATOMIC); +- if (unlikely(err)) +- break; +- err = au_dcsub_pages(&dpages, sb->s_root, NULL, NULL); +- if (!err) +- for (i = 0; i < dpages.ndpage; i++) { +- dpage = dpages.dpages + i; +- ndentry = dpage->ndentry; +- for (j = 0; j < ndentry; j++) +- au_dpri_dentry(dpage->dentries[j]); +- } +- au_dpages_free(&dpages); +- } while (0); +-#endif +- +-#if 1 +- { +- struct inode *i; +- pr("isolated inode\n"); +- spin_lock(&inode_sb_list_lock); +- list_for_each_entry(i, &sb->s_inodes, i_sb_list) { +- spin_lock(&i->i_lock); +- if (1 || hlist_empty(&i->i_dentry)) +- au_dpri_inode(i); +- spin_unlock(&i->i_lock); +- } +- spin_unlock(&inode_sb_list_lock); +- } +-#endif +- pr("files\n"); +- lg_global_lock(&files_lglock); +- do_file_list_for_each_entry(sb, file) { +- umode_t mode; +- mode = file->f_dentry->d_inode->i_mode; +- if (!special_file(mode) || au_special_file(mode)) +- au_dpri_file(file); +- } while_file_list_for_each_entry; +- lg_global_unlock(&files_lglock); +- pr("done\n"); +- +-#undef pr +- au_plevel = plevel; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* module parameter */ +-static char *aufs_sysrq_key = "a"; +-module_param_named(sysrq, aufs_sysrq_key, charp, S_IRUGO); +-MODULE_PARM_DESC(sysrq, "MagicSysRq key for " AUFS_NAME); +- +-static void au_sysrq(int key __maybe_unused) +-{ +- struct au_sbinfo *sbinfo; +- +- lockdep_off(); +- au_sbilist_lock(); +- list_for_each_entry(sbinfo, &au_sbilist.head, si_list) +- sysrq_sb(sbinfo->si_sb); +- au_sbilist_unlock(); +- lockdep_on(); +-} +- +-static struct sysrq_key_op au_sysrq_op = { +- .handler = au_sysrq, +- .help_msg = "Aufs", +- .action_msg = "Aufs", +- .enable_mask = SYSRQ_ENABLE_DUMP +-}; +- +-/* ---------------------------------------------------------------------- */ +- +-int __init au_sysrq_init(void) +-{ +- int err; +- char key; +- +- err = -1; +- key = *aufs_sysrq_key; +- if ('a' <= key && key <= 'z') +- err = register_sysrq_key(key, &au_sysrq_op); +- if (unlikely(err)) +- pr_err("err %d, sysrq=%c\n", err, key); +- return err; +-} +- +-void au_sysrq_fin(void) +-{ +- int err; +- err = unregister_sysrq_key(*aufs_sysrq_key, &au_sysrq_op); +- if (unlikely(err)) +- pr_err("err %d (ignored)\n", err); +-} +diff --git a/fs/aufs/vdir.c b/fs/aufs/vdir.c +deleted file mode 100644 +index 998acff..0000000 +--- a/fs/aufs/vdir.c ++++ /dev/null +@@ -1,885 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * virtual or vertical directory +- */ +- +-#include "aufs.h" +- +-static unsigned int calc_size(int nlen) +-{ +- return ALIGN(sizeof(struct au_vdir_de) + nlen, sizeof(ino_t)); +-} +- +-static int set_deblk_end(union au_vdir_deblk_p *p, +- union au_vdir_deblk_p *deblk_end) +-{ +- if (calc_size(0) <= deblk_end->deblk - p->deblk) { +- p->de->de_str.len = 0; +- /* smp_mb(); */ +- return 0; +- } +- return -1; /* error */ +-} +- +-/* returns true or false */ +-static int is_deblk_end(union au_vdir_deblk_p *p, +- union au_vdir_deblk_p *deblk_end) +-{ +- if (calc_size(0) <= deblk_end->deblk - p->deblk) +- return !p->de->de_str.len; +- return 1; +-} +- +-static unsigned char *last_deblk(struct au_vdir *vdir) +-{ +- return vdir->vd_deblk[vdir->vd_nblk - 1]; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* estimate the apropriate size for name hash table */ +-unsigned int au_rdhash_est(loff_t sz) +-{ +- unsigned int n; +- +- n = UINT_MAX; +- sz >>= 10; +- if (sz < n) +- n = sz; +- if (sz < AUFS_RDHASH_DEF) +- n = AUFS_RDHASH_DEF; +- /* pr_info("n %u\n", n); */ +- return n; +-} +- +-/* +- * the allocated memory has to be freed by +- * au_nhash_wh_free() or au_nhash_de_free(). +- */ +-int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp) +-{ +- struct hlist_head *head; +- unsigned int u; +- +- head = kmalloc(sizeof(*nhash->nh_head) * num_hash, gfp); +- if (head) { +- nhash->nh_num = num_hash; +- nhash->nh_head = head; +- for (u = 0; u < num_hash; u++) +- INIT_HLIST_HEAD(head++); +- return 0; /* success */ +- } +- +- return -ENOMEM; +-} +- +-static void nhash_count(struct hlist_head *head) +-{ +-#if 0 +- unsigned long n; +- struct hlist_node *pos; +- +- n = 0; +- hlist_for_each(pos, head) +- n++; +- pr_info("%lu\n", n); +-#endif +-} +- +-static void au_nhash_wh_do_free(struct hlist_head *head) +-{ +- struct au_vdir_wh *tpos; +- struct hlist_node *pos, *node; +- +- hlist_for_each_entry_safe(tpos, pos, node, head, wh_hash) { +- /* hlist_del(pos); */ +- kfree(tpos); +- } +-} +- +-static void au_nhash_de_do_free(struct hlist_head *head) +-{ +- struct au_vdir_dehstr *tpos; +- struct hlist_node *pos, *node; +- +- hlist_for_each_entry_safe(tpos, pos, node, head, hash) { +- /* hlist_del(pos); */ +- au_cache_free_vdir_dehstr(tpos); +- } +-} +- +-static void au_nhash_do_free(struct au_nhash *nhash, +- void (*free)(struct hlist_head *head)) +-{ +- unsigned int n; +- struct hlist_head *head; +- +- n = nhash->nh_num; +- if (!n) +- return; +- +- head = nhash->nh_head; +- while (n-- > 0) { +- nhash_count(head); +- free(head++); +- } +- kfree(nhash->nh_head); +-} +- +-void au_nhash_wh_free(struct au_nhash *whlist) +-{ +- au_nhash_do_free(whlist, au_nhash_wh_do_free); +-} +- +-static void au_nhash_de_free(struct au_nhash *delist) +-{ +- au_nhash_do_free(delist, au_nhash_de_do_free); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt, +- int limit) +-{ +- int num; +- unsigned int u, n; +- struct hlist_head *head; +- struct au_vdir_wh *tpos; +- struct hlist_node *pos; +- +- num = 0; +- n = whlist->nh_num; +- head = whlist->nh_head; +- for (u = 0; u < n; u++, head++) +- hlist_for_each_entry(tpos, pos, head, wh_hash) +- if (tpos->wh_bindex == btgt && ++num > limit) +- return 1; +- return 0; +-} +- +-static struct hlist_head *au_name_hash(struct au_nhash *nhash, +- unsigned char *name, +- unsigned int len) +-{ +- unsigned int v; +- /* const unsigned int magic_bit = 12; */ +- +- AuDebugOn(!nhash->nh_num || !nhash->nh_head); +- +- v = 0; +- while (len--) +- v += *name++; +- /* v = hash_long(v, magic_bit); */ +- v %= nhash->nh_num; +- return nhash->nh_head + v; +-} +- +-static int au_nhash_test_name(struct au_vdir_destr *str, const char *name, +- int nlen) +-{ +- return str->len == nlen && !memcmp(str->name, name, nlen); +-} +- +-/* returns found or not */ +-int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen) +-{ +- struct hlist_head *head; +- struct au_vdir_wh *tpos; +- struct hlist_node *pos; +- struct au_vdir_destr *str; +- +- head = au_name_hash(whlist, name, nlen); +- hlist_for_each_entry(tpos, pos, head, wh_hash) { +- str = &tpos->wh_str; +- AuDbg("%.*s\n", str->len, str->name); +- if (au_nhash_test_name(str, name, nlen)) +- return 1; +- } +- return 0; +-} +- +-/* returns found(true) or not */ +-static int test_known(struct au_nhash *delist, char *name, int nlen) +-{ +- struct hlist_head *head; +- struct au_vdir_dehstr *tpos; +- struct hlist_node *pos; +- struct au_vdir_destr *str; +- +- head = au_name_hash(delist, name, nlen); +- hlist_for_each_entry(tpos, pos, head, hash) { +- str = tpos->str; +- AuDbg("%.*s\n", str->len, str->name); +- if (au_nhash_test_name(str, name, nlen)) +- return 1; +- } +- return 0; +-} +- +-static void au_shwh_init_wh(struct au_vdir_wh *wh, ino_t ino, +- unsigned char d_type) +-{ +-#ifdef CONFIG_AUFS_SHWH +- wh->wh_ino = ino; +- wh->wh_type = d_type; +-#endif +-} +- +-/* ---------------------------------------------------------------------- */ +- +-int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino, +- unsigned int d_type, aufs_bindex_t bindex, +- unsigned char shwh) +-{ +- int err; +- struct au_vdir_destr *str; +- struct au_vdir_wh *wh; +- +- AuDbg("%.*s\n", nlen, name); +- AuDebugOn(!whlist->nh_num || !whlist->nh_head); +- +- err = -ENOMEM; +- wh = kmalloc(sizeof(*wh) + nlen, GFP_NOFS); +- if (unlikely(!wh)) +- goto out; +- +- err = 0; +- wh->wh_bindex = bindex; +- if (shwh) +- au_shwh_init_wh(wh, ino, d_type); +- str = &wh->wh_str; +- str->len = nlen; +- memcpy(str->name, name, nlen); +- hlist_add_head(&wh->wh_hash, au_name_hash(whlist, name, nlen)); +- /* smp_mb(); */ +- +-out: +- return err; +-} +- +-static int append_deblk(struct au_vdir *vdir) +-{ +- int err; +- unsigned long ul; +- const unsigned int deblk_sz = vdir->vd_deblk_sz; +- union au_vdir_deblk_p p, deblk_end; +- unsigned char **o; +- +- err = -ENOMEM; +- o = krealloc(vdir->vd_deblk, sizeof(*o) * (vdir->vd_nblk + 1), +- GFP_NOFS); +- if (unlikely(!o)) +- goto out; +- +- vdir->vd_deblk = o; +- p.deblk = kmalloc(deblk_sz, GFP_NOFS); +- if (p.deblk) { +- ul = vdir->vd_nblk++; +- vdir->vd_deblk[ul] = p.deblk; +- vdir->vd_last.ul = ul; +- vdir->vd_last.p.deblk = p.deblk; +- deblk_end.deblk = p.deblk + deblk_sz; +- err = set_deblk_end(&p, &deblk_end); +- } +- +-out: +- return err; +-} +- +-static int append_de(struct au_vdir *vdir, char *name, int nlen, ino_t ino, +- unsigned int d_type, struct au_nhash *delist) +-{ +- int err; +- unsigned int sz; +- const unsigned int deblk_sz = vdir->vd_deblk_sz; +- union au_vdir_deblk_p p, *room, deblk_end; +- struct au_vdir_dehstr *dehstr; +- +- p.deblk = last_deblk(vdir); +- deblk_end.deblk = p.deblk + deblk_sz; +- room = &vdir->vd_last.p; +- AuDebugOn(room->deblk < p.deblk || deblk_end.deblk <= room->deblk +- || !is_deblk_end(room, &deblk_end)); +- +- sz = calc_size(nlen); +- if (unlikely(sz > deblk_end.deblk - room->deblk)) { +- err = append_deblk(vdir); +- if (unlikely(err)) +- goto out; +- +- p.deblk = last_deblk(vdir); +- deblk_end.deblk = p.deblk + deblk_sz; +- /* smp_mb(); */ +- AuDebugOn(room->deblk != p.deblk); +- } +- +- err = -ENOMEM; +- dehstr = au_cache_alloc_vdir_dehstr(); +- if (unlikely(!dehstr)) +- goto out; +- +- dehstr->str = &room->de->de_str; +- hlist_add_head(&dehstr->hash, au_name_hash(delist, name, nlen)); +- room->de->de_ino = ino; +- room->de->de_type = d_type; +- room->de->de_str.len = nlen; +- memcpy(room->de->de_str.name, name, nlen); +- +- err = 0; +- room->deblk += sz; +- if (unlikely(set_deblk_end(room, &deblk_end))) +- err = append_deblk(vdir); +- /* smp_mb(); */ +- +-out: +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-void au_vdir_free(struct au_vdir *vdir) +-{ +- unsigned char **deblk; +- +- deblk = vdir->vd_deblk; +- while (vdir->vd_nblk--) +- kfree(*deblk++); +- kfree(vdir->vd_deblk); +- au_cache_free_vdir(vdir); +-} +- +-static struct au_vdir *alloc_vdir(struct file *file) +-{ +- struct au_vdir *vdir; +- struct super_block *sb; +- int err; +- +- sb = file->f_dentry->d_sb; +- SiMustAnyLock(sb); +- +- err = -ENOMEM; +- vdir = au_cache_alloc_vdir(); +- if (unlikely(!vdir)) +- goto out; +- +- vdir->vd_deblk = kzalloc(sizeof(*vdir->vd_deblk), GFP_NOFS); +- if (unlikely(!vdir->vd_deblk)) +- goto out_free; +- +- vdir->vd_deblk_sz = au_sbi(sb)->si_rdblk; +- if (!vdir->vd_deblk_sz) { +- /* estimate the apropriate size for deblk */ +- vdir->vd_deblk_sz = au_dir_size(file, /*dentry*/NULL); +- /* pr_info("vd_deblk_sz %u\n", vdir->vd_deblk_sz); */ +- } +- vdir->vd_nblk = 0; +- vdir->vd_version = 0; +- vdir->vd_jiffy = 0; +- err = append_deblk(vdir); +- if (!err) +- return vdir; /* success */ +- +- kfree(vdir->vd_deblk); +- +-out_free: +- au_cache_free_vdir(vdir); +-out: +- vdir = ERR_PTR(err); +- return vdir; +-} +- +-static int reinit_vdir(struct au_vdir *vdir) +-{ +- int err; +- union au_vdir_deblk_p p, deblk_end; +- +- while (vdir->vd_nblk > 1) { +- kfree(vdir->vd_deblk[vdir->vd_nblk - 1]); +- /* vdir->vd_deblk[vdir->vd_nblk - 1] = NULL; */ +- vdir->vd_nblk--; +- } +- p.deblk = vdir->vd_deblk[0]; +- deblk_end.deblk = p.deblk + vdir->vd_deblk_sz; +- err = set_deblk_end(&p, &deblk_end); +- /* keep vd_dblk_sz */ +- vdir->vd_last.ul = 0; +- vdir->vd_last.p.deblk = vdir->vd_deblk[0]; +- vdir->vd_version = 0; +- vdir->vd_jiffy = 0; +- /* smp_mb(); */ +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-#define AuFillVdir_CALLED 1 +-#define AuFillVdir_WHABLE (1 << 1) +-#define AuFillVdir_SHWH (1 << 2) +-#define au_ftest_fillvdir(flags, name) ((flags) & AuFillVdir_##name) +-#define au_fset_fillvdir(flags, name) \ +- do { (flags) |= AuFillVdir_##name; } while (0) +-#define au_fclr_fillvdir(flags, name) \ +- do { (flags) &= ~AuFillVdir_##name; } while (0) +- +-#ifndef CONFIG_AUFS_SHWH +-#undef AuFillVdir_SHWH +-#define AuFillVdir_SHWH 0 +-#endif +- +-struct fillvdir_arg { +- struct file *file; +- struct au_vdir *vdir; +- struct au_nhash delist; +- struct au_nhash whlist; +- aufs_bindex_t bindex; +- unsigned int flags; +- int err; +-}; +- +-static int fillvdir(void *__arg, const char *__name, int nlen, +- loff_t offset __maybe_unused, u64 h_ino, +- unsigned int d_type) +-{ +- struct fillvdir_arg *arg = __arg; +- char *name = (void *)__name; +- struct super_block *sb; +- ino_t ino; +- const unsigned char shwh = !!au_ftest_fillvdir(arg->flags, SHWH); +- +- arg->err = 0; +- sb = arg->file->f_dentry->d_sb; +- au_fset_fillvdir(arg->flags, CALLED); +- /* smp_mb(); */ +- if (nlen <= AUFS_WH_PFX_LEN +- || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { +- if (test_known(&arg->delist, name, nlen) +- || au_nhash_test_known_wh(&arg->whlist, name, nlen)) +- goto out; /* already exists or whiteouted */ +- +- sb = arg->file->f_dentry->d_sb; +- arg->err = au_ino(sb, arg->bindex, h_ino, d_type, &ino); +- if (!arg->err) { +- if (unlikely(nlen > AUFS_MAX_NAMELEN)) +- d_type = DT_UNKNOWN; +- arg->err = append_de(arg->vdir, name, nlen, ino, +- d_type, &arg->delist); +- } +- } else if (au_ftest_fillvdir(arg->flags, WHABLE)) { +- name += AUFS_WH_PFX_LEN; +- nlen -= AUFS_WH_PFX_LEN; +- if (au_nhash_test_known_wh(&arg->whlist, name, nlen)) +- goto out; /* already whiteouted */ +- +- if (shwh) +- arg->err = au_wh_ino(sb, arg->bindex, h_ino, d_type, +- &ino); +- if (!arg->err) { +- if (nlen <= AUFS_MAX_NAMELEN + AUFS_WH_PFX_LEN) +- d_type = DT_UNKNOWN; +- arg->err = au_nhash_append_wh +- (&arg->whlist, name, nlen, ino, d_type, +- arg->bindex, shwh); +- } +- } +- +-out: +- if (!arg->err) +- arg->vdir->vd_jiffy = jiffies; +- /* smp_mb(); */ +- AuTraceErr(arg->err); +- return arg->err; +-} +- +-static int au_handle_shwh(struct super_block *sb, struct au_vdir *vdir, +- struct au_nhash *whlist, struct au_nhash *delist) +-{ +-#ifdef CONFIG_AUFS_SHWH +- int err; +- unsigned int nh, u; +- struct hlist_head *head; +- struct au_vdir_wh *tpos; +- struct hlist_node *pos, *n; +- char *p, *o; +- struct au_vdir_destr *destr; +- +- AuDebugOn(!au_opt_test(au_mntflags(sb), SHWH)); +- +- err = -ENOMEM; +- o = p = (void *)__get_free_page(GFP_NOFS); +- if (unlikely(!p)) +- goto out; +- +- err = 0; +- nh = whlist->nh_num; +- memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); +- p += AUFS_WH_PFX_LEN; +- for (u = 0; u < nh; u++) { +- head = whlist->nh_head + u; +- hlist_for_each_entry_safe(tpos, pos, n, head, wh_hash) { +- destr = &tpos->wh_str; +- memcpy(p, destr->name, destr->len); +- err = append_de(vdir, o, destr->len + AUFS_WH_PFX_LEN, +- tpos->wh_ino, tpos->wh_type, delist); +- if (unlikely(err)) +- break; +- } +- } +- +- free_page((unsigned long)o); +- +-out: +- AuTraceErr(err); +- return err; +-#else +- return 0; +-#endif +-} +- +-static int au_do_read_vdir(struct fillvdir_arg *arg) +-{ +- int err; +- unsigned int rdhash; +- loff_t offset; +- aufs_bindex_t bend, bindex, bstart; +- unsigned char shwh; +- struct file *hf, *file; +- struct super_block *sb; +- +- file = arg->file; +- sb = file->f_dentry->d_sb; +- SiMustAnyLock(sb); +- +- rdhash = au_sbi(sb)->si_rdhash; +- if (!rdhash) +- rdhash = au_rdhash_est(au_dir_size(file, /*dentry*/NULL)); +- err = au_nhash_alloc(&arg->delist, rdhash, GFP_NOFS); +- if (unlikely(err)) +- goto out; +- err = au_nhash_alloc(&arg->whlist, rdhash, GFP_NOFS); +- if (unlikely(err)) +- goto out_delist; +- +- err = 0; +- arg->flags = 0; +- shwh = 0; +- if (au_opt_test(au_mntflags(sb), SHWH)) { +- shwh = 1; +- au_fset_fillvdir(arg->flags, SHWH); +- } +- bstart = au_fbstart(file); +- bend = au_fbend_dir(file); +- for (bindex = bstart; !err && bindex <= bend; bindex++) { +- hf = au_hf_dir(file, bindex); +- if (!hf) +- continue; +- +- offset = vfsub_llseek(hf, 0, SEEK_SET); +- err = offset; +- if (unlikely(offset)) +- break; +- +- arg->bindex = bindex; +- au_fclr_fillvdir(arg->flags, WHABLE); +- if (shwh +- || (bindex != bend +- && au_br_whable(au_sbr_perm(sb, bindex)))) +- au_fset_fillvdir(arg->flags, WHABLE); +- do { +- arg->err = 0; +- au_fclr_fillvdir(arg->flags, CALLED); +- /* smp_mb(); */ +- err = vfsub_readdir(hf, fillvdir, arg); +- if (err >= 0) +- err = arg->err; +- } while (!err && au_ftest_fillvdir(arg->flags, CALLED)); +- } +- +- if (!err && shwh) +- err = au_handle_shwh(sb, arg->vdir, &arg->whlist, &arg->delist); +- +- au_nhash_wh_free(&arg->whlist); +- +-out_delist: +- au_nhash_de_free(&arg->delist); +-out: +- return err; +-} +- +-static int read_vdir(struct file *file, int may_read) +-{ +- int err; +- unsigned long expire; +- unsigned char do_read; +- struct fillvdir_arg arg; +- struct inode *inode; +- struct au_vdir *vdir, *allocated; +- +- err = 0; +- inode = file->f_dentry->d_inode; +- IMustLock(inode); +- SiMustAnyLock(inode->i_sb); +- +- allocated = NULL; +- do_read = 0; +- expire = au_sbi(inode->i_sb)->si_rdcache; +- vdir = au_ivdir(inode); +- if (!vdir) { +- do_read = 1; +- vdir = alloc_vdir(file); +- err = PTR_ERR(vdir); +- if (IS_ERR(vdir)) +- goto out; +- err = 0; +- allocated = vdir; +- } else if (may_read +- && (inode->i_version != vdir->vd_version +- || time_after(jiffies, vdir->vd_jiffy + expire))) { +- do_read = 1; +- err = reinit_vdir(vdir); +- if (unlikely(err)) +- goto out; +- } +- +- if (!do_read) +- return 0; /* success */ +- +- arg.file = file; +- arg.vdir = vdir; +- err = au_do_read_vdir(&arg); +- if (!err) { +- /* file->f_pos = 0; */ +- vdir->vd_version = inode->i_version; +- vdir->vd_last.ul = 0; +- vdir->vd_last.p.deblk = vdir->vd_deblk[0]; +- if (allocated) +- au_set_ivdir(inode, allocated); +- } else if (allocated) +- au_vdir_free(allocated); +- +-out: +- return err; +-} +- +-static int copy_vdir(struct au_vdir *tgt, struct au_vdir *src) +-{ +- int err, rerr; +- unsigned long ul, n; +- const unsigned int deblk_sz = src->vd_deblk_sz; +- +- AuDebugOn(tgt->vd_nblk != 1); +- +- err = -ENOMEM; +- if (tgt->vd_nblk < src->vd_nblk) { +- unsigned char **p; +- +- p = krealloc(tgt->vd_deblk, sizeof(*p) * src->vd_nblk, +- GFP_NOFS); +- if (unlikely(!p)) +- goto out; +- tgt->vd_deblk = p; +- } +- +- if (tgt->vd_deblk_sz != deblk_sz) { +- unsigned char *p; +- +- tgt->vd_deblk_sz = deblk_sz; +- p = krealloc(tgt->vd_deblk[0], deblk_sz, GFP_NOFS); +- if (unlikely(!p)) +- goto out; +- tgt->vd_deblk[0] = p; +- } +- memcpy(tgt->vd_deblk[0], src->vd_deblk[0], deblk_sz); +- tgt->vd_version = src->vd_version; +- tgt->vd_jiffy = src->vd_jiffy; +- +- n = src->vd_nblk; +- for (ul = 1; ul < n; ul++) { +- tgt->vd_deblk[ul] = kmemdup(src->vd_deblk[ul], deblk_sz, +- GFP_NOFS); +- if (unlikely(!tgt->vd_deblk[ul])) +- goto out; +- tgt->vd_nblk++; +- } +- tgt->vd_nblk = n; +- tgt->vd_last.ul = tgt->vd_last.ul; +- tgt->vd_last.p.deblk = tgt->vd_deblk[tgt->vd_last.ul]; +- tgt->vd_last.p.deblk += src->vd_last.p.deblk +- - src->vd_deblk[src->vd_last.ul]; +- /* smp_mb(); */ +- return 0; /* success */ +- +-out: +- rerr = reinit_vdir(tgt); +- BUG_ON(rerr); +- return err; +-} +- +-int au_vdir_init(struct file *file) +-{ +- int err; +- struct inode *inode; +- struct au_vdir *vdir_cache, *allocated; +- +- err = read_vdir(file, !file->f_pos); +- if (unlikely(err)) +- goto out; +- +- allocated = NULL; +- vdir_cache = au_fvdir_cache(file); +- if (!vdir_cache) { +- vdir_cache = alloc_vdir(file); +- err = PTR_ERR(vdir_cache); +- if (IS_ERR(vdir_cache)) +- goto out; +- allocated = vdir_cache; +- } else if (!file->f_pos && vdir_cache->vd_version != file->f_version) { +- err = reinit_vdir(vdir_cache); +- if (unlikely(err)) +- goto out; +- } else +- return 0; /* success */ +- +- inode = file->f_dentry->d_inode; +- err = copy_vdir(vdir_cache, au_ivdir(inode)); +- if (!err) { +- file->f_version = inode->i_version; +- if (allocated) +- au_set_fvdir_cache(file, allocated); +- } else if (allocated) +- au_vdir_free(allocated); +- +-out: +- return err; +-} +- +-static loff_t calc_offset(struct au_vdir *vdir) +-{ +- loff_t offset; +- union au_vdir_deblk_p p; +- +- p.deblk = vdir->vd_deblk[vdir->vd_last.ul]; +- offset = vdir->vd_last.p.deblk - p.deblk; +- offset += vdir->vd_deblk_sz * vdir->vd_last.ul; +- return offset; +-} +- +-/* returns true or false */ +-static int seek_vdir(struct file *file) +-{ +- int valid; +- unsigned int deblk_sz; +- unsigned long ul, n; +- loff_t offset; +- union au_vdir_deblk_p p, deblk_end; +- struct au_vdir *vdir_cache; +- +- valid = 1; +- vdir_cache = au_fvdir_cache(file); +- offset = calc_offset(vdir_cache); +- AuDbg("offset %lld\n", offset); +- if (file->f_pos == offset) +- goto out; +- +- vdir_cache->vd_last.ul = 0; +- vdir_cache->vd_last.p.deblk = vdir_cache->vd_deblk[0]; +- if (!file->f_pos) +- goto out; +- +- valid = 0; +- deblk_sz = vdir_cache->vd_deblk_sz; +- ul = div64_u64(file->f_pos, deblk_sz); +- AuDbg("ul %lu\n", ul); +- if (ul >= vdir_cache->vd_nblk) +- goto out; +- +- n = vdir_cache->vd_nblk; +- for (; ul < n; ul++) { +- p.deblk = vdir_cache->vd_deblk[ul]; +- deblk_end.deblk = p.deblk + deblk_sz; +- offset = ul; +- offset *= deblk_sz; +- while (!is_deblk_end(&p, &deblk_end) && offset < file->f_pos) { +- unsigned int l; +- +- l = calc_size(p.de->de_str.len); +- offset += l; +- p.deblk += l; +- } +- if (!is_deblk_end(&p, &deblk_end)) { +- valid = 1; +- vdir_cache->vd_last.ul = ul; +- vdir_cache->vd_last.p = p; +- break; +- } +- } +- +-out: +- /* smp_mb(); */ +- AuTraceErr(!valid); +- return valid; +-} +- +-int au_vdir_fill_de(struct file *file, void *dirent, filldir_t filldir) +-{ +- int err; +- unsigned int l, deblk_sz; +- union au_vdir_deblk_p deblk_end; +- struct au_vdir *vdir_cache; +- struct au_vdir_de *de; +- +- vdir_cache = au_fvdir_cache(file); +- if (!seek_vdir(file)) +- return 0; +- +- deblk_sz = vdir_cache->vd_deblk_sz; +- while (1) { +- deblk_end.deblk = vdir_cache->vd_deblk[vdir_cache->vd_last.ul]; +- deblk_end.deblk += deblk_sz; +- while (!is_deblk_end(&vdir_cache->vd_last.p, &deblk_end)) { +- de = vdir_cache->vd_last.p.de; +- AuDbg("%.*s, off%lld, i%lu, dt%d\n", +- de->de_str.len, de->de_str.name, file->f_pos, +- (unsigned long)de->de_ino, de->de_type); +- err = filldir(dirent, de->de_str.name, de->de_str.len, +- file->f_pos, de->de_ino, de->de_type); +- if (unlikely(err)) { +- AuTraceErr(err); +- /* todo: ignore the error caused by udba? */ +- /* return err; */ +- return 0; +- } +- +- l = calc_size(de->de_str.len); +- vdir_cache->vd_last.p.deblk += l; +- file->f_pos += l; +- } +- if (vdir_cache->vd_last.ul < vdir_cache->vd_nblk - 1) { +- vdir_cache->vd_last.ul++; +- vdir_cache->vd_last.p.deblk +- = vdir_cache->vd_deblk[vdir_cache->vd_last.ul]; +- file->f_pos = deblk_sz * vdir_cache->vd_last.ul; +- continue; +- } +- break; +- } +- +- /* smp_mb(); */ +- return 0; +-} +diff --git a/fs/aufs/vfsub.c b/fs/aufs/vfsub.c +deleted file mode 100644 +index 6d34b27..0000000 +--- a/fs/aufs/vfsub.c ++++ /dev/null +@@ -1,769 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * sub-routines for VFS +- */ +- +-#include +-#include +-#include +-#include +-#include "aufs.h" +- +-int vfsub_update_h_iattr(struct path *h_path, int *did) +-{ +- int err; +- struct kstat st; +- struct super_block *h_sb; +- +- /* for remote fs, leave work for its getattr or d_revalidate */ +- /* for bad i_attr fs, handle them in aufs_getattr() */ +- /* still some fs may acquire i_mutex. we need to skip them */ +- err = 0; +- if (!did) +- did = &err; +- h_sb = h_path->dentry->d_sb; +- *did = (!au_test_fs_remote(h_sb) && au_test_fs_refresh_iattr(h_sb)); +- if (*did) +- err = vfs_getattr(h_path->mnt, h_path->dentry, &st); +- +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-struct file *vfsub_dentry_open(struct path *path, int flags) +-{ +- struct file *file; +- +- file = dentry_open(path, flags /* | __FMODE_NONOTIFY */, +- current_cred()); +- if (!IS_ERR_OR_NULL(file) +- && (file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) +- i_readcount_inc(path->dentry->d_inode); +- +- return file; +-} +- +-struct file *vfsub_filp_open(const char *path, int oflags, int mode) +-{ +- struct file *file; +- +- lockdep_off(); +- file = filp_open(path, +- oflags /* | __FMODE_NONOTIFY */, +- mode); +- lockdep_on(); +- if (IS_ERR(file)) +- goto out; +- vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ +- +-out: +- return file; +-} +- +-int vfsub_kern_path(const char *name, unsigned int flags, struct path *path) +-{ +- int err; +- +- err = kern_path(name, flags, path); +- if (!err && path->dentry->d_inode) +- vfsub_update_h_iattr(path, /*did*/NULL); /*ignore*/ +- return err; +-} +- +-struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent, +- int len) +-{ +- struct path path = { +- .mnt = NULL +- }; +- +- /* VFS checks it too, but by WARN_ON_ONCE() */ +- IMustLock(parent->d_inode); +- +- path.dentry = lookup_one_len(name, parent, len); +- if (IS_ERR(path.dentry)) +- goto out; +- if (path.dentry->d_inode) +- vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/ +- +-out: +- AuTraceErrPtr(path.dentry); +- return path.dentry; +-} +- +-void vfsub_call_lkup_one(void *args) +-{ +- struct vfsub_lkup_one_args *a = args; +- *a->errp = vfsub_lkup_one(a->name, a->parent); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1, +- struct dentry *d2, struct au_hinode *hdir2) +-{ +- struct dentry *d; +- +- lockdep_off(); +- d = lock_rename(d1, d2); +- lockdep_on(); +- au_hn_suspend(hdir1); +- if (hdir1 != hdir2) +- au_hn_suspend(hdir2); +- +- return d; +-} +- +-void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1, +- struct dentry *d2, struct au_hinode *hdir2) +-{ +- au_hn_resume(hdir1); +- if (hdir1 != hdir2) +- au_hn_resume(hdir2); +- lockdep_off(); +- unlock_rename(d1, d2); +- lockdep_on(); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-int vfsub_create(struct inode *dir, struct path *path, int mode, bool want_excl) +-{ +- int err; +- struct dentry *d; +- +- IMustLock(dir); +- +- d = path->dentry; +- path->dentry = d->d_parent; +- err = security_path_mknod(path, d, mode, 0); +- path->dentry = d; +- if (unlikely(err)) +- goto out; +- +- err = vfs_create(dir, path->dentry, mode, want_excl); +- if (!err) { +- struct path tmp = *path; +- int did; +- +- vfsub_update_h_iattr(&tmp, &did); +- if (did) { +- tmp.dentry = path->dentry->d_parent; +- vfsub_update_h_iattr(&tmp, /*did*/NULL); +- } +- /*ignore*/ +- } +- +-out: +- return err; +-} +- +-int vfsub_symlink(struct inode *dir, struct path *path, const char *symname) +-{ +- int err; +- struct dentry *d; +- +- IMustLock(dir); +- +- d = path->dentry; +- path->dentry = d->d_parent; +- err = security_path_symlink(path, d, symname); +- path->dentry = d; +- if (unlikely(err)) +- goto out; +- +- err = vfs_symlink(dir, path->dentry, symname); +- if (!err) { +- struct path tmp = *path; +- int did; +- +- vfsub_update_h_iattr(&tmp, &did); +- if (did) { +- tmp.dentry = path->dentry->d_parent; +- vfsub_update_h_iattr(&tmp, /*did*/NULL); +- } +- /*ignore*/ +- } +- +-out: +- return err; +-} +- +-int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev) +-{ +- int err; +- struct dentry *d; +- +- IMustLock(dir); +- +- d = path->dentry; +- path->dentry = d->d_parent; +- err = security_path_mknod(path, d, mode, new_encode_dev(dev)); +- path->dentry = d; +- if (unlikely(err)) +- goto out; +- +- err = vfs_mknod(dir, path->dentry, mode, dev); +- if (!err) { +- struct path tmp = *path; +- int did; +- +- vfsub_update_h_iattr(&tmp, &did); +- if (did) { +- tmp.dentry = path->dentry->d_parent; +- vfsub_update_h_iattr(&tmp, /*did*/NULL); +- } +- /*ignore*/ +- } +- +-out: +- return err; +-} +- +-static int au_test_nlink(struct inode *inode) +-{ +- const unsigned int link_max = UINT_MAX >> 1; /* rough margin */ +- +- if (!au_test_fs_no_limit_nlink(inode->i_sb) +- || inode->i_nlink < link_max) +- return 0; +- return -EMLINK; +-} +- +-int vfsub_link(struct dentry *src_dentry, struct inode *dir, struct path *path) +-{ +- int err; +- struct dentry *d; +- +- IMustLock(dir); +- +- err = au_test_nlink(src_dentry->d_inode); +- if (unlikely(err)) +- return err; +- +- /* we don't call may_linkat() */ +- d = path->dentry; +- path->dentry = d->d_parent; +- err = security_path_link(src_dentry, path, d); +- path->dentry = d; +- if (unlikely(err)) +- goto out; +- +- lockdep_off(); +- err = vfs_link(src_dentry, dir, path->dentry); +- lockdep_on(); +- if (!err) { +- struct path tmp = *path; +- int did; +- +- /* fuse has different memory inode for the same inumber */ +- vfsub_update_h_iattr(&tmp, &did); +- if (did) { +- tmp.dentry = path->dentry->d_parent; +- vfsub_update_h_iattr(&tmp, /*did*/NULL); +- tmp.dentry = src_dentry; +- vfsub_update_h_iattr(&tmp, /*did*/NULL); +- } +- /*ignore*/ +- } +- +-out: +- return err; +-} +- +-int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry, +- struct inode *dir, struct path *path) +-{ +- int err; +- struct path tmp = { +- .mnt = path->mnt +- }; +- struct dentry *d; +- +- IMustLock(dir); +- IMustLock(src_dir); +- +- d = path->dentry; +- path->dentry = d->d_parent; +- tmp.dentry = src_dentry->d_parent; +- err = security_path_rename(&tmp, src_dentry, path, d); +- path->dentry = d; +- if (unlikely(err)) +- goto out; +- +- lockdep_off(); +- err = vfs_rename(src_dir, src_dentry, dir, path->dentry); +- lockdep_on(); +- if (!err) { +- int did; +- +- tmp.dentry = d->d_parent; +- vfsub_update_h_iattr(&tmp, &did); +- if (did) { +- tmp.dentry = src_dentry; +- vfsub_update_h_iattr(&tmp, /*did*/NULL); +- tmp.dentry = src_dentry->d_parent; +- vfsub_update_h_iattr(&tmp, /*did*/NULL); +- } +- /*ignore*/ +- } +- +-out: +- return err; +-} +- +-int vfsub_mkdir(struct inode *dir, struct path *path, int mode) +-{ +- int err; +- struct dentry *d; +- +- IMustLock(dir); +- +- d = path->dentry; +- path->dentry = d->d_parent; +- err = security_path_mkdir(path, d, mode); +- path->dentry = d; +- if (unlikely(err)) +- goto out; +- +- err = vfs_mkdir(dir, path->dentry, mode); +- if (!err) { +- struct path tmp = *path; +- int did; +- +- vfsub_update_h_iattr(&tmp, &did); +- if (did) { +- tmp.dentry = path->dentry->d_parent; +- vfsub_update_h_iattr(&tmp, /*did*/NULL); +- } +- /*ignore*/ +- } +- +-out: +- return err; +-} +- +-int vfsub_rmdir(struct inode *dir, struct path *path) +-{ +- int err; +- struct dentry *d; +- +- IMustLock(dir); +- +- d = path->dentry; +- path->dentry = d->d_parent; +- err = security_path_rmdir(path, d); +- path->dentry = d; +- if (unlikely(err)) +- goto out; +- +- lockdep_off(); +- err = vfs_rmdir(dir, path->dentry); +- lockdep_on(); +- if (!err) { +- struct path tmp = { +- .dentry = path->dentry->d_parent, +- .mnt = path->mnt +- }; +- +- vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/ +- } +- +-out: +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* todo: support mmap_sem? */ +-ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, +- loff_t *ppos) +-{ +- ssize_t err; +- +- lockdep_off(); +- err = vfs_read(file, ubuf, count, ppos); +- lockdep_on(); +- if (err >= 0) +- vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ +- return err; +-} +- +-/* todo: kernel_read()? */ +-ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, +- loff_t *ppos) +-{ +- ssize_t err; +- mm_segment_t oldfs; +- union { +- void *k; +- char __user *u; +- } buf; +- +- buf.k = kbuf; +- oldfs = get_fs(); +- set_fs(KERNEL_DS); +- err = vfsub_read_u(file, buf.u, count, ppos); +- set_fs(oldfs); +- return err; +-} +- +-ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, +- loff_t *ppos) +-{ +- ssize_t err; +- +- lockdep_off(); +- err = vfs_write(file, ubuf, count, ppos); +- lockdep_on(); +- if (err >= 0) +- vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ +- return err; +-} +- +-ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, loff_t *ppos) +-{ +- ssize_t err; +- mm_segment_t oldfs; +- union { +- void *k; +- const char __user *u; +- } buf; +- +- buf.k = kbuf; +- oldfs = get_fs(); +- set_fs(KERNEL_DS); +- err = vfsub_write_u(file, buf.u, count, ppos); +- set_fs(oldfs); +- return err; +-} +- +-int vfsub_flush(struct file *file, fl_owner_t id) +-{ +- int err; +- +- err = 0; +- if (file->f_op && file->f_op->flush) { +- if (!au_test_nfs(file->f_dentry->d_sb)) +- err = file->f_op->flush(file, id); +- else { +- lockdep_off(); +- err = file->f_op->flush(file, id); +- lockdep_on(); +- } +- if (!err) +- vfsub_update_h_iattr(&file->f_path, /*did*/NULL); +- /*ignore*/ +- } +- return err; +-} +- +-int vfsub_readdir(struct file *file, filldir_t filldir, void *arg) +-{ +- int err; +- +- lockdep_off(); +- err = vfs_readdir(file, filldir, arg); +- lockdep_on(); +- if (err >= 0) +- vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ +- return err; +-} +- +-long vfsub_splice_to(struct file *in, loff_t *ppos, +- struct pipe_inode_info *pipe, size_t len, +- unsigned int flags) +-{ +- long err; +- +- lockdep_off(); +- err = do_splice_to(in, ppos, pipe, len, flags); +- lockdep_on(); +- file_accessed(in); +- if (err >= 0) +- vfsub_update_h_iattr(&in->f_path, /*did*/NULL); /*ignore*/ +- return err; +-} +- +-long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, +- loff_t *ppos, size_t len, unsigned int flags) +-{ +- long err; +- +- lockdep_off(); +- err = do_splice_from(pipe, out, ppos, len, flags); +- lockdep_on(); +- if (err >= 0) +- vfsub_update_h_iattr(&out->f_path, /*did*/NULL); /*ignore*/ +- return err; +-} +- +-int vfsub_fsync(struct file *file, struct path *path, int datasync) +-{ +- int err; +- +- /* file can be NULL */ +- lockdep_off(); +- err = vfs_fsync(file, datasync); +- lockdep_on(); +- if (!err) { +- if (!path) { +- AuDebugOn(!file); +- path = &file->f_path; +- } +- vfsub_update_h_iattr(path, /*did*/NULL); /*ignore*/ +- } +- return err; +-} +- +-/* cf. open.c:do_sys_truncate() and do_sys_ftruncate() */ +-int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr, +- struct file *h_file) +-{ +- int err; +- struct inode *h_inode; +- struct super_block *h_sb; +- +- if (!h_file) { +- err = vfsub_truncate(h_path, length); +- goto out; +- } +- +- h_inode = h_path->dentry->d_inode; +- h_sb = h_inode->i_sb; +- lockdep_off(); +- sb_start_write(h_sb); +- lockdep_on(); +- err = locks_verify_truncate(h_inode, h_file, length); +- if (!err) +- err = security_path_truncate(h_path); +- if (!err) { +- lockdep_off(); +- err = do_truncate(h_path->dentry, length, attr, h_file); +- lockdep_on(); +- } +- lockdep_off(); +- sb_end_write(h_sb); +- lockdep_on(); +- +-out: +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-struct au_vfsub_mkdir_args { +- int *errp; +- struct inode *dir; +- struct path *path; +- int mode; +-}; +- +-static void au_call_vfsub_mkdir(void *args) +-{ +- struct au_vfsub_mkdir_args *a = args; +- *a->errp = vfsub_mkdir(a->dir, a->path, a->mode); +-} +- +-int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode) +-{ +- int err, do_sio, wkq_err; +- +- do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE); +- if (!do_sio) +- err = vfsub_mkdir(dir, path, mode); +- else { +- struct au_vfsub_mkdir_args args = { +- .errp = &err, +- .dir = dir, +- .path = path, +- .mode = mode +- }; +- wkq_err = au_wkq_wait(au_call_vfsub_mkdir, &args); +- if (unlikely(wkq_err)) +- err = wkq_err; +- } +- +- return err; +-} +- +-struct au_vfsub_rmdir_args { +- int *errp; +- struct inode *dir; +- struct path *path; +-}; +- +-static void au_call_vfsub_rmdir(void *args) +-{ +- struct au_vfsub_rmdir_args *a = args; +- *a->errp = vfsub_rmdir(a->dir, a->path); +-} +- +-int vfsub_sio_rmdir(struct inode *dir, struct path *path) +-{ +- int err, do_sio, wkq_err; +- +- do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE); +- if (!do_sio) +- err = vfsub_rmdir(dir, path); +- else { +- struct au_vfsub_rmdir_args args = { +- .errp = &err, +- .dir = dir, +- .path = path +- }; +- wkq_err = au_wkq_wait(au_call_vfsub_rmdir, &args); +- if (unlikely(wkq_err)) +- err = wkq_err; +- } +- +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-struct notify_change_args { +- int *errp; +- struct path *path; +- struct iattr *ia; +-}; +- +-static void call_notify_change(void *args) +-{ +- struct notify_change_args *a = args; +- struct inode *h_inode; +- +- h_inode = a->path->dentry->d_inode; +- IMustLock(h_inode); +- +- *a->errp = -EPERM; +- if (!IS_IMMUTABLE(h_inode) && !IS_APPEND(h_inode)) { +- *a->errp = notify_change(a->path->dentry, a->ia); +- if (!*a->errp) +- vfsub_update_h_iattr(a->path, /*did*/NULL); /*ignore*/ +- } +- AuTraceErr(*a->errp); +-} +- +-int vfsub_notify_change(struct path *path, struct iattr *ia) +-{ +- int err; +- struct notify_change_args args = { +- .errp = &err, +- .path = path, +- .ia = ia +- }; +- +- call_notify_change(&args); +- +- return err; +-} +- +-int vfsub_sio_notify_change(struct path *path, struct iattr *ia) +-{ +- int err, wkq_err; +- struct notify_change_args args = { +- .errp = &err, +- .path = path, +- .ia = ia +- }; +- +- wkq_err = au_wkq_wait(call_notify_change, &args); +- if (unlikely(wkq_err)) +- err = wkq_err; +- +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-struct unlink_args { +- int *errp; +- struct inode *dir; +- struct path *path; +-}; +- +-static void call_unlink(void *args) +-{ +- struct unlink_args *a = args; +- struct dentry *d = a->path->dentry; +- struct inode *h_inode; +- const int stop_sillyrename = (au_test_nfs(d->d_sb) +- && d->d_count == 1); +- +- IMustLock(a->dir); +- +- a->path->dentry = d->d_parent; +- *a->errp = security_path_unlink(a->path, d); +- a->path->dentry = d; +- if (unlikely(*a->errp)) +- return; +- +- if (!stop_sillyrename) +- dget(d); +- h_inode = d->d_inode; +- if (h_inode) +- ihold(h_inode); +- +- lockdep_off(); +- *a->errp = vfs_unlink(a->dir, d); +- lockdep_on(); +- if (!*a->errp) { +- struct path tmp = { +- .dentry = d->d_parent, +- .mnt = a->path->mnt +- }; +- vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/ +- } +- +- if (!stop_sillyrename) +- dput(d); +- if (h_inode) +- iput(h_inode); +- +- AuTraceErr(*a->errp); +-} +- +-/* +- * @dir: must be locked. +- * @dentry: target dentry. +- */ +-int vfsub_unlink(struct inode *dir, struct path *path, int force) +-{ +- int err; +- struct unlink_args args = { +- .errp = &err, +- .dir = dir, +- .path = path +- }; +- +- if (!force) +- call_unlink(&args); +- else { +- int wkq_err; +- +- wkq_err = au_wkq_wait(call_unlink, &args); +- if (unlikely(wkq_err)) +- err = wkq_err; +- } +- +- return err; +-} +diff --git a/fs/aufs/vfsub.h b/fs/aufs/vfsub.h +deleted file mode 100644 +index 1665600..0000000 +--- a/fs/aufs/vfsub.h ++++ /dev/null +@@ -1,302 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * sub-routines for VFS +- */ +- +-#ifndef __AUFS_VFSUB_H__ +-#define __AUFS_VFSUB_H__ +- +-#ifdef __KERNEL__ +- +-#include +-#include +-#include +-#include "debug.h" +- +-/* copied from linux/fs/internal.h */ +-/* todo: BAD approach!! */ +-extern struct lglock vfsmount_lock; +-extern void __mnt_drop_write(struct vfsmount *); +-extern spinlock_t inode_sb_list_lock; +- +-/* copied from linux/fs/file_table.c */ +-extern struct lglock files_lglock; +-#ifdef CONFIG_SMP +-/* +- * These macros iterate all files on all CPUs for a given superblock. +- * files_lglock must be held globally. +- */ +-#define do_file_list_for_each_entry(__sb, __file) \ +-{ \ +- int i; \ +- for_each_possible_cpu(i) { \ +- struct list_head *list; \ +- list = per_cpu_ptr((__sb)->s_files, i); \ +- list_for_each_entry((__file), list, f_u.fu_list) +- +-#define while_file_list_for_each_entry \ +- } \ +-} +- +-#else +- +-#define do_file_list_for_each_entry(__sb, __file) \ +-{ \ +- struct list_head *list; \ +- list = &(sb)->s_files; \ +- list_for_each_entry((__file), list, f_u.fu_list) +- +-#define while_file_list_for_each_entry \ +-} +-#endif +- +-/* ---------------------------------------------------------------------- */ +- +-/* lock subclass for lower inode */ +-/* default MAX_LOCKDEP_SUBCLASSES(8) is not enough */ +-/* reduce? gave up. */ +-enum { +- AuLsc_I_Begin = I_MUTEX_QUOTA, /* 4 */ +- AuLsc_I_PARENT, /* lower inode, parent first */ +- AuLsc_I_PARENT2, /* copyup dirs */ +- AuLsc_I_PARENT3, /* copyup wh */ +- AuLsc_I_CHILD, +- AuLsc_I_CHILD2, +- AuLsc_I_End +-}; +- +-/* to debug easier, do not make them inlined functions */ +-#define MtxMustLock(mtx) AuDebugOn(!mutex_is_locked(mtx)) +-#define IMustLock(i) MtxMustLock(&(i)->i_mutex) +- +-/* ---------------------------------------------------------------------- */ +- +-static inline void vfsub_drop_nlink(struct inode *inode) +-{ +- AuDebugOn(!inode->i_nlink); +- drop_nlink(inode); +-} +- +-static inline void vfsub_dead_dir(struct inode *inode) +-{ +- AuDebugOn(!S_ISDIR(inode->i_mode)); +- inode->i_flags |= S_DEAD; +- clear_nlink(inode); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* cf. i_[ug]id_read() in linux/include/fs.h */ +-static inline uid_t vfsub_ia_uid(struct iattr *ia) +-{ +- return from_kuid(&init_user_ns, ia->ia_uid); +-} +- +-static inline gid_t vfsub_ia_gid(struct iattr *ia) +-{ +- return from_kgid(&init_user_ns, ia->ia_gid); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-int vfsub_update_h_iattr(struct path *h_path, int *did); +-struct file *vfsub_dentry_open(struct path *path, int flags); +-struct file *vfsub_filp_open(const char *path, int oflags, int mode); +-int vfsub_kern_path(const char *name, unsigned int flags, struct path *path); +- +-struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent, +- int len); +- +-struct vfsub_lkup_one_args { +- struct dentry **errp; +- struct qstr *name; +- struct dentry *parent; +-}; +- +-static inline struct dentry *vfsub_lkup_one(struct qstr *name, +- struct dentry *parent) +-{ +- return vfsub_lookup_one_len(name->name, parent, name->len); +-} +- +-void vfsub_call_lkup_one(void *args); +- +-/* ---------------------------------------------------------------------- */ +- +-static inline int vfsub_mnt_want_write(struct vfsmount *mnt) +-{ +- int err; +- lockdep_off(); +- err = mnt_want_write(mnt); +- lockdep_on(); +- return err; +-} +- +-static inline void vfsub_mnt_drop_write(struct vfsmount *mnt) +-{ +- lockdep_off(); +- mnt_drop_write(mnt); +- lockdep_on(); +-} +- +-static inline void vfsub_mnt_drop_write_file(struct file *file) +-{ +- lockdep_off(); +- mnt_drop_write_file(file); +- lockdep_on(); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-struct au_hinode; +-struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1, +- struct dentry *d2, struct au_hinode *hdir2); +-void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1, +- struct dentry *d2, struct au_hinode *hdir2); +- +-int vfsub_create(struct inode *dir, struct path *path, int mode, +- bool want_excl); +-int vfsub_symlink(struct inode *dir, struct path *path, +- const char *symname); +-int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev); +-int vfsub_link(struct dentry *src_dentry, struct inode *dir, +- struct path *path); +-int vfsub_rename(struct inode *src_hdir, struct dentry *src_dentry, +- struct inode *hdir, struct path *path); +-int vfsub_mkdir(struct inode *dir, struct path *path, int mode); +-int vfsub_rmdir(struct inode *dir, struct path *path); +- +-/* ---------------------------------------------------------------------- */ +- +-ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, +- loff_t *ppos); +-ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, +- loff_t *ppos); +-ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, +- loff_t *ppos); +-ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, +- loff_t *ppos); +-int vfsub_flush(struct file *file, fl_owner_t id); +-int vfsub_readdir(struct file *file, filldir_t filldir, void *arg); +- +-static inline unsigned int vfsub_file_flags(struct file *file) +-{ +- unsigned int flags; +- +- spin_lock(&file->f_lock); +- flags = file->f_flags; +- spin_unlock(&file->f_lock); +- +- return flags; +-} +- +-static inline void vfsub_file_accessed(struct file *h_file) +-{ +- file_accessed(h_file); +- vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); /*ignore*/ +-} +- +-static inline void vfsub_touch_atime(struct vfsmount *h_mnt, +- struct dentry *h_dentry) +-{ +- struct path h_path = { +- .dentry = h_dentry, +- .mnt = h_mnt +- }; +- touch_atime(&h_path); +- vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/ +-} +- +-static inline int vfsub_update_time(struct inode *h_inode, struct timespec *ts, +- int flags) +-{ +- return update_time(h_inode, ts, flags); +- /* no vfsub_update_h_iattr() since we don't have struct path */ +-} +- +-long vfsub_splice_to(struct file *in, loff_t *ppos, +- struct pipe_inode_info *pipe, size_t len, +- unsigned int flags); +-long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, +- loff_t *ppos, size_t len, unsigned int flags); +- +-static inline long vfsub_truncate(struct path *path, loff_t length) +-{ +- long err; +- lockdep_off(); +- err = vfs_truncate(path, length); +- lockdep_on(); +- return err; +-} +- +-int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr, +- struct file *h_file); +-int vfsub_fsync(struct file *file, struct path *path, int datasync); +- +-/* ---------------------------------------------------------------------- */ +- +-static inline loff_t vfsub_llseek(struct file *file, loff_t offset, int origin) +-{ +- loff_t err; +- +- lockdep_off(); +- err = vfs_llseek(file, offset, origin); +- lockdep_on(); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* dirty workaround for strict type of fmode_t */ +-union vfsub_fmu { +- fmode_t fm; +- unsigned int ui; +-}; +- +-static inline unsigned int vfsub_fmode_to_uint(fmode_t fm) +-{ +- union vfsub_fmu u = { +- .fm = fm +- }; +- +- BUILD_BUG_ON(sizeof(u.fm) != sizeof(u.ui)); +- +- return u.ui; +-} +- +-static inline fmode_t vfsub_uint_to_fmode(unsigned int ui) +-{ +- union vfsub_fmu u = { +- .ui = ui +- }; +- +- return u.fm; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode); +-int vfsub_sio_rmdir(struct inode *dir, struct path *path); +-int vfsub_sio_notify_change(struct path *path, struct iattr *ia); +-int vfsub_notify_change(struct path *path, struct iattr *ia); +-int vfsub_unlink(struct inode *dir, struct path *path, int force); +- +-#endif /* __KERNEL__ */ +-#endif /* __AUFS_VFSUB_H__ */ +diff --git a/fs/aufs/wbr_policy.c b/fs/aufs/wbr_policy.c +deleted file mode 100644 +index 605317d..0000000 +--- a/fs/aufs/wbr_policy.c ++++ /dev/null +@@ -1,700 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * policies for selecting one among multiple writable branches +- */ +- +-#include +-#include "aufs.h" +- +-/* subset of cpup_attr() */ +-static noinline_for_stack +-int au_cpdown_attr(struct path *h_path, struct dentry *h_src) +-{ +- int err, sbits; +- struct iattr ia; +- struct inode *h_isrc; +- +- h_isrc = h_src->d_inode; +- ia.ia_valid = ATTR_FORCE | ATTR_MODE | ATTR_UID | ATTR_GID; +- ia.ia_mode = h_isrc->i_mode; +- ia.ia_uid = h_isrc->i_uid; +- ia.ia_gid = h_isrc->i_gid; +- sbits = !!(ia.ia_mode & (S_ISUID | S_ISGID)); +- au_cpup_attr_flags(h_path->dentry->d_inode, h_isrc); +- err = vfsub_sio_notify_change(h_path, &ia); +- +- /* is this nfs only? */ +- if (!err && sbits && au_test_nfs(h_path->dentry->d_sb)) { +- ia.ia_valid = ATTR_FORCE | ATTR_MODE; +- ia.ia_mode = h_isrc->i_mode; +- err = vfsub_sio_notify_change(h_path, &ia); +- } +- +- return err; +-} +- +-#define AuCpdown_PARENT_OPQ 1 +-#define AuCpdown_WHED (1 << 1) +-#define AuCpdown_MADE_DIR (1 << 2) +-#define AuCpdown_DIROPQ (1 << 3) +-#define au_ftest_cpdown(flags, name) ((flags) & AuCpdown_##name) +-#define au_fset_cpdown(flags, name) \ +- do { (flags) |= AuCpdown_##name; } while (0) +-#define au_fclr_cpdown(flags, name) \ +- do { (flags) &= ~AuCpdown_##name; } while (0) +- +-struct au_cpdown_dir_args { +- struct dentry *parent; +- unsigned int flags; +-}; +- +-static int au_cpdown_dir_opq(struct dentry *dentry, aufs_bindex_t bdst, +- struct au_cpdown_dir_args *a) +-{ +- int err; +- struct dentry *opq_dentry; +- +- opq_dentry = au_diropq_create(dentry, bdst); +- err = PTR_ERR(opq_dentry); +- if (IS_ERR(opq_dentry)) +- goto out; +- dput(opq_dentry); +- au_fset_cpdown(a->flags, DIROPQ); +- +-out: +- return err; +-} +- +-static int au_cpdown_dir_wh(struct dentry *dentry, struct dentry *h_parent, +- struct inode *dir, aufs_bindex_t bdst) +-{ +- int err; +- struct path h_path; +- struct au_branch *br; +- +- br = au_sbr(dentry->d_sb, bdst); +- h_path.dentry = au_wh_lkup(h_parent, &dentry->d_name, br); +- err = PTR_ERR(h_path.dentry); +- if (IS_ERR(h_path.dentry)) +- goto out; +- +- err = 0; +- if (h_path.dentry->d_inode) { +- h_path.mnt = br->br_mnt; +- err = au_wh_unlink_dentry(au_h_iptr(dir, bdst), &h_path, +- dentry); +- } +- dput(h_path.dentry); +- +-out: +- return err; +-} +- +-static int au_cpdown_dir(struct dentry *dentry, aufs_bindex_t bdst, +- struct dentry *h_parent, void *arg) +-{ +- int err, rerr; +- aufs_bindex_t bopq, bstart; +- struct path h_path; +- struct dentry *parent; +- struct inode *h_dir, *h_inode, *inode, *dir; +- struct au_cpdown_dir_args *args = arg; +- +- bstart = au_dbstart(dentry); +- /* dentry is di-locked */ +- parent = dget_parent(dentry); +- dir = parent->d_inode; +- h_dir = h_parent->d_inode; +- AuDebugOn(h_dir != au_h_iptr(dir, bdst)); +- IMustLock(h_dir); +- +- err = au_lkup_neg(dentry, bdst); +- if (unlikely(err < 0)) +- goto out; +- h_path.dentry = au_h_dptr(dentry, bdst); +- h_path.mnt = au_sbr_mnt(dentry->d_sb, bdst); +- err = vfsub_sio_mkdir(au_h_iptr(dir, bdst), &h_path, +- S_IRWXU | S_IRUGO | S_IXUGO); +- if (unlikely(err)) +- goto out_put; +- au_fset_cpdown(args->flags, MADE_DIR); +- +- bopq = au_dbdiropq(dentry); +- au_fclr_cpdown(args->flags, WHED); +- au_fclr_cpdown(args->flags, DIROPQ); +- if (au_dbwh(dentry) == bdst) +- au_fset_cpdown(args->flags, WHED); +- if (!au_ftest_cpdown(args->flags, PARENT_OPQ) && bopq <= bdst) +- au_fset_cpdown(args->flags, PARENT_OPQ); +- h_inode = h_path.dentry->d_inode; +- mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); +- if (au_ftest_cpdown(args->flags, WHED)) { +- err = au_cpdown_dir_opq(dentry, bdst, args); +- if (unlikely(err)) { +- mutex_unlock(&h_inode->i_mutex); +- goto out_dir; +- } +- } +- +- err = au_cpdown_attr(&h_path, au_h_dptr(dentry, bstart)); +- mutex_unlock(&h_inode->i_mutex); +- if (unlikely(err)) +- goto out_opq; +- +- if (au_ftest_cpdown(args->flags, WHED)) { +- err = au_cpdown_dir_wh(dentry, h_parent, dir, bdst); +- if (unlikely(err)) +- goto out_opq; +- } +- +- inode = dentry->d_inode; +- if (au_ibend(inode) < bdst) +- au_set_ibend(inode, bdst); +- au_set_h_iptr(inode, bdst, au_igrab(h_inode), +- au_hi_flags(inode, /*isdir*/1)); +- goto out; /* success */ +- +- /* revert */ +-out_opq: +- if (au_ftest_cpdown(args->flags, DIROPQ)) { +- mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); +- rerr = au_diropq_remove(dentry, bdst); +- mutex_unlock(&h_inode->i_mutex); +- if (unlikely(rerr)) { +- AuIOErr("failed removing diropq for %.*s b%d (%d)\n", +- AuDLNPair(dentry), bdst, rerr); +- err = -EIO; +- goto out; +- } +- } +-out_dir: +- if (au_ftest_cpdown(args->flags, MADE_DIR)) { +- rerr = vfsub_sio_rmdir(au_h_iptr(dir, bdst), &h_path); +- if (unlikely(rerr)) { +- AuIOErr("failed removing %.*s b%d (%d)\n", +- AuDLNPair(dentry), bdst, rerr); +- err = -EIO; +- } +- } +-out_put: +- au_set_h_dptr(dentry, bdst, NULL); +- if (au_dbend(dentry) == bdst) +- au_update_dbend(dentry); +-out: +- dput(parent); +- return err; +-} +- +-int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst) +-{ +- int err; +- struct au_cpdown_dir_args args = { +- .parent = dget_parent(dentry), +- .flags = 0 +- }; +- +- err = au_cp_dirs(dentry, bdst, au_cpdown_dir, &args); +- dput(args.parent); +- +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* policies for create */ +- +-static int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex) +-{ +- int err, i, j, ndentry; +- aufs_bindex_t bopq; +- struct au_dcsub_pages dpages; +- struct au_dpage *dpage; +- struct dentry **dentries, *parent, *d; +- +- err = au_dpages_init(&dpages, GFP_NOFS); +- if (unlikely(err)) +- goto out; +- parent = dget_parent(dentry); +- err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/0); +- if (unlikely(err)) +- goto out_free; +- +- err = bindex; +- for (i = 0; i < dpages.ndpage; i++) { +- dpage = dpages.dpages + i; +- dentries = dpage->dentries; +- ndentry = dpage->ndentry; +- for (j = 0; j < ndentry; j++) { +- d = dentries[j]; +- di_read_lock_parent2(d, !AuLock_IR); +- bopq = au_dbdiropq(d); +- di_read_unlock(d, !AuLock_IR); +- if (bopq >= 0 && bopq < err) +- err = bopq; +- } +- } +- +-out_free: +- dput(parent); +- au_dpages_free(&dpages); +-out: +- return err; +-} +- +-static int au_wbr_bu(struct super_block *sb, aufs_bindex_t bindex) +-{ +- for (; bindex >= 0; bindex--) +- if (!au_br_rdonly(au_sbr(sb, bindex))) +- return bindex; +- return -EROFS; +-} +- +-/* top down parent */ +-static int au_wbr_create_tdp(struct dentry *dentry, int isdir __maybe_unused) +-{ +- int err; +- aufs_bindex_t bstart, bindex; +- struct super_block *sb; +- struct dentry *parent, *h_parent; +- +- sb = dentry->d_sb; +- bstart = au_dbstart(dentry); +- err = bstart; +- if (!au_br_rdonly(au_sbr(sb, bstart))) +- goto out; +- +- err = -EROFS; +- parent = dget_parent(dentry); +- for (bindex = au_dbstart(parent); bindex < bstart; bindex++) { +- h_parent = au_h_dptr(parent, bindex); +- if (!h_parent || !h_parent->d_inode) +- continue; +- +- if (!au_br_rdonly(au_sbr(sb, bindex))) { +- err = bindex; +- break; +- } +- } +- dput(parent); +- +- /* bottom up here */ +- if (unlikely(err < 0)) { +- err = au_wbr_bu(sb, bstart - 1); +- if (err >= 0) +- err = au_wbr_nonopq(dentry, err); +- } +- +-out: +- AuDbg("b%d\n", err); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* an exception for the policy other than tdp */ +-static int au_wbr_create_exp(struct dentry *dentry) +-{ +- int err; +- aufs_bindex_t bwh, bdiropq; +- struct dentry *parent; +- +- err = -1; +- bwh = au_dbwh(dentry); +- parent = dget_parent(dentry); +- bdiropq = au_dbdiropq(parent); +- if (bwh >= 0) { +- if (bdiropq >= 0) +- err = min(bdiropq, bwh); +- else +- err = bwh; +- AuDbg("%d\n", err); +- } else if (bdiropq >= 0) { +- err = bdiropq; +- AuDbg("%d\n", err); +- } +- dput(parent); +- +- if (err >= 0) +- err = au_wbr_nonopq(dentry, err); +- +- if (err >= 0 && au_br_rdonly(au_sbr(dentry->d_sb, err))) +- err = -1; +- +- AuDbg("%d\n", err); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* round robin */ +-static int au_wbr_create_init_rr(struct super_block *sb) +-{ +- int err; +- +- err = au_wbr_bu(sb, au_sbend(sb)); +- atomic_set(&au_sbi(sb)->si_wbr_rr_next, -err); /* less important */ +- /* smp_mb(); */ +- +- AuDbg("b%d\n", err); +- return err; +-} +- +-static int au_wbr_create_rr(struct dentry *dentry, int isdir) +-{ +- int err, nbr; +- unsigned int u; +- aufs_bindex_t bindex, bend; +- struct super_block *sb; +- atomic_t *next; +- +- err = au_wbr_create_exp(dentry); +- if (err >= 0) +- goto out; +- +- sb = dentry->d_sb; +- next = &au_sbi(sb)->si_wbr_rr_next; +- bend = au_sbend(sb); +- nbr = bend + 1; +- for (bindex = 0; bindex <= bend; bindex++) { +- if (!isdir) { +- err = atomic_dec_return(next) + 1; +- /* modulo for 0 is meaningless */ +- if (unlikely(!err)) +- err = atomic_dec_return(next) + 1; +- } else +- err = atomic_read(next); +- AuDbg("%d\n", err); +- u = err; +- err = u % nbr; +- AuDbg("%d\n", err); +- if (!au_br_rdonly(au_sbr(sb, err))) +- break; +- err = -EROFS; +- } +- +- if (err >= 0) +- err = au_wbr_nonopq(dentry, err); +- +-out: +- AuDbg("%d\n", err); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* most free space */ +-static void au_mfs(struct dentry *dentry) +-{ +- struct super_block *sb; +- struct au_branch *br; +- struct au_wbr_mfs *mfs; +- aufs_bindex_t bindex, bend; +- int err; +- unsigned long long b, bavail; +- struct path h_path; +- /* reduce the stack usage */ +- struct kstatfs *st; +- +- st = kmalloc(sizeof(*st), GFP_NOFS); +- if (unlikely(!st)) { +- AuWarn1("failed updating mfs(%d), ignored\n", -ENOMEM); +- return; +- } +- +- bavail = 0; +- sb = dentry->d_sb; +- mfs = &au_sbi(sb)->si_wbr_mfs; +- MtxMustLock(&mfs->mfs_lock); +- mfs->mfs_bindex = -EROFS; +- mfs->mfsrr_bytes = 0; +- bend = au_sbend(sb); +- for (bindex = 0; bindex <= bend; bindex++) { +- br = au_sbr(sb, bindex); +- if (au_br_rdonly(br)) +- continue; +- +- /* sb->s_root for NFS is unreliable */ +- h_path.mnt = br->br_mnt; +- h_path.dentry = h_path.mnt->mnt_root; +- err = vfs_statfs(&h_path, st); +- if (unlikely(err)) { +- AuWarn1("failed statfs, b%d, %d\n", bindex, err); +- continue; +- } +- +- /* when the available size is equal, select the lower one */ +- BUILD_BUG_ON(sizeof(b) < sizeof(st->f_bavail) +- || sizeof(b) < sizeof(st->f_bsize)); +- b = st->f_bavail * st->f_bsize; +- br->br_wbr->wbr_bytes = b; +- if (b >= bavail) { +- bavail = b; +- mfs->mfs_bindex = bindex; +- mfs->mfs_jiffy = jiffies; +- } +- } +- +- mfs->mfsrr_bytes = bavail; +- AuDbg("b%d\n", mfs->mfs_bindex); +- kfree(st); +-} +- +-static int au_wbr_create_mfs(struct dentry *dentry, int isdir __maybe_unused) +-{ +- int err; +- struct super_block *sb; +- struct au_wbr_mfs *mfs; +- +- err = au_wbr_create_exp(dentry); +- if (err >= 0) +- goto out; +- +- sb = dentry->d_sb; +- mfs = &au_sbi(sb)->si_wbr_mfs; +- mutex_lock(&mfs->mfs_lock); +- if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire) +- || mfs->mfs_bindex < 0 +- || au_br_rdonly(au_sbr(sb, mfs->mfs_bindex))) +- au_mfs(dentry); +- mutex_unlock(&mfs->mfs_lock); +- err = mfs->mfs_bindex; +- +- if (err >= 0) +- err = au_wbr_nonopq(dentry, err); +- +-out: +- AuDbg("b%d\n", err); +- return err; +-} +- +-static int au_wbr_create_init_mfs(struct super_block *sb) +-{ +- struct au_wbr_mfs *mfs; +- +- mfs = &au_sbi(sb)->si_wbr_mfs; +- mutex_init(&mfs->mfs_lock); +- mfs->mfs_jiffy = 0; +- mfs->mfs_bindex = -EROFS; +- +- return 0; +-} +- +-static int au_wbr_create_fin_mfs(struct super_block *sb __maybe_unused) +-{ +- mutex_destroy(&au_sbi(sb)->si_wbr_mfs.mfs_lock); +- return 0; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* most free space and then round robin */ +-static int au_wbr_create_mfsrr(struct dentry *dentry, int isdir) +-{ +- int err; +- struct au_wbr_mfs *mfs; +- +- err = au_wbr_create_mfs(dentry, isdir); +- if (err >= 0) { +- mfs = &au_sbi(dentry->d_sb)->si_wbr_mfs; +- mutex_lock(&mfs->mfs_lock); +- if (mfs->mfsrr_bytes < mfs->mfsrr_watermark) +- err = au_wbr_create_rr(dentry, isdir); +- mutex_unlock(&mfs->mfs_lock); +- } +- +- AuDbg("b%d\n", err); +- return err; +-} +- +-static int au_wbr_create_init_mfsrr(struct super_block *sb) +-{ +- int err; +- +- au_wbr_create_init_mfs(sb); /* ignore */ +- err = au_wbr_create_init_rr(sb); +- +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* top down parent and most free space */ +-static int au_wbr_create_pmfs(struct dentry *dentry, int isdir) +-{ +- int err, e2; +- unsigned long long b; +- aufs_bindex_t bindex, bstart, bend; +- struct super_block *sb; +- struct dentry *parent, *h_parent; +- struct au_branch *br; +- +- err = au_wbr_create_tdp(dentry, isdir); +- if (unlikely(err < 0)) +- goto out; +- parent = dget_parent(dentry); +- bstart = au_dbstart(parent); +- bend = au_dbtaildir(parent); +- if (bstart == bend) +- goto out_parent; /* success */ +- +- e2 = au_wbr_create_mfs(dentry, isdir); +- if (e2 < 0) +- goto out_parent; /* success */ +- +- /* when the available size is equal, select upper one */ +- sb = dentry->d_sb; +- br = au_sbr(sb, err); +- b = br->br_wbr->wbr_bytes; +- AuDbg("b%d, %llu\n", err, b); +- +- for (bindex = bstart; bindex <= bend; bindex++) { +- h_parent = au_h_dptr(parent, bindex); +- if (!h_parent || !h_parent->d_inode) +- continue; +- +- br = au_sbr(sb, bindex); +- if (!au_br_rdonly(br) && br->br_wbr->wbr_bytes > b) { +- b = br->br_wbr->wbr_bytes; +- err = bindex; +- AuDbg("b%d, %llu\n", err, b); +- } +- } +- +- if (err >= 0) +- err = au_wbr_nonopq(dentry, err); +- +-out_parent: +- dput(parent); +-out: +- AuDbg("b%d\n", err); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* policies for copyup */ +- +-/* top down parent */ +-static int au_wbr_copyup_tdp(struct dentry *dentry) +-{ +- return au_wbr_create_tdp(dentry, /*isdir, anything is ok*/0); +-} +- +-/* bottom up parent */ +-static int au_wbr_copyup_bup(struct dentry *dentry) +-{ +- int err; +- aufs_bindex_t bindex, bstart; +- struct dentry *parent, *h_parent; +- struct super_block *sb; +- +- err = -EROFS; +- sb = dentry->d_sb; +- parent = dget_parent(dentry); +- bstart = au_dbstart(parent); +- for (bindex = au_dbstart(dentry); bindex >= bstart; bindex--) { +- h_parent = au_h_dptr(parent, bindex); +- if (!h_parent || !h_parent->d_inode) +- continue; +- +- if (!au_br_rdonly(au_sbr(sb, bindex))) { +- err = bindex; +- break; +- } +- } +- dput(parent); +- +- /* bottom up here */ +- if (unlikely(err < 0)) +- err = au_wbr_bu(sb, bstart - 1); +- +- AuDbg("b%d\n", err); +- return err; +-} +- +-/* bottom up */ +-static int au_wbr_copyup_bu(struct dentry *dentry) +-{ +- int err; +- aufs_bindex_t bstart; +- +- bstart = au_dbstart(dentry); +- err = au_wbr_bu(dentry->d_sb, bstart); +- AuDbg("b%d\n", err); +- if (err > bstart) +- err = au_wbr_nonopq(dentry, err); +- +- AuDbg("b%d\n", err); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-struct au_wbr_copyup_operations au_wbr_copyup_ops[] = { +- [AuWbrCopyup_TDP] = { +- .copyup = au_wbr_copyup_tdp +- }, +- [AuWbrCopyup_BUP] = { +- .copyup = au_wbr_copyup_bup +- }, +- [AuWbrCopyup_BU] = { +- .copyup = au_wbr_copyup_bu +- } +-}; +- +-struct au_wbr_create_operations au_wbr_create_ops[] = { +- [AuWbrCreate_TDP] = { +- .create = au_wbr_create_tdp +- }, +- [AuWbrCreate_RR] = { +- .create = au_wbr_create_rr, +- .init = au_wbr_create_init_rr +- }, +- [AuWbrCreate_MFS] = { +- .create = au_wbr_create_mfs, +- .init = au_wbr_create_init_mfs, +- .fin = au_wbr_create_fin_mfs +- }, +- [AuWbrCreate_MFSV] = { +- .create = au_wbr_create_mfs, +- .init = au_wbr_create_init_mfs, +- .fin = au_wbr_create_fin_mfs +- }, +- [AuWbrCreate_MFSRR] = { +- .create = au_wbr_create_mfsrr, +- .init = au_wbr_create_init_mfsrr, +- .fin = au_wbr_create_fin_mfs +- }, +- [AuWbrCreate_MFSRRV] = { +- .create = au_wbr_create_mfsrr, +- .init = au_wbr_create_init_mfsrr, +- .fin = au_wbr_create_fin_mfs +- }, +- [AuWbrCreate_PMFS] = { +- .create = au_wbr_create_pmfs, +- .init = au_wbr_create_init_mfs, +- .fin = au_wbr_create_fin_mfs +- }, +- [AuWbrCreate_PMFSV] = { +- .create = au_wbr_create_pmfs, +- .init = au_wbr_create_init_mfs, +- .fin = au_wbr_create_fin_mfs +- } +-}; +diff --git a/fs/aufs/whout.c b/fs/aufs/whout.c +deleted file mode 100644 +index 433c290..0000000 +--- a/fs/aufs/whout.c ++++ /dev/null +@@ -1,1042 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * whiteout for logical deletion and opaque directory +- */ +- +-#include "aufs.h" +- +-#define WH_MASK S_IRUGO +- +-/* +- * If a directory contains this file, then it is opaque. We start with the +- * .wh. flag so that it is blocked by lookup. +- */ +-static struct qstr diropq_name = QSTR_INIT(AUFS_WH_DIROPQ, +- sizeof(AUFS_WH_DIROPQ) - 1); +- +-/* +- * generate whiteout name, which is NOT terminated by NULL. +- * @name: original d_name.name +- * @len: original d_name.len +- * @wh: whiteout qstr +- * returns zero when succeeds, otherwise error. +- * succeeded value as wh->name should be freed by kfree(). +- */ +-int au_wh_name_alloc(struct qstr *wh, const struct qstr *name) +-{ +- char *p; +- +- if (unlikely(name->len > PATH_MAX - AUFS_WH_PFX_LEN)) +- return -ENAMETOOLONG; +- +- wh->len = name->len + AUFS_WH_PFX_LEN; +- p = kmalloc(wh->len, GFP_NOFS); +- wh->name = p; +- if (p) { +- memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); +- memcpy(p + AUFS_WH_PFX_LEN, name->name, name->len); +- /* smp_mb(); */ +- return 0; +- } +- return -ENOMEM; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* +- * test if the @wh_name exists under @h_parent. +- * @try_sio specifies the necessary of super-io. +- */ +-int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, +- struct au_branch *br, int try_sio) +-{ +- int err; +- struct dentry *wh_dentry; +- +- if (!try_sio) +- wh_dentry = vfsub_lkup_one(wh_name, h_parent); +- else +- wh_dentry = au_sio_lkup_one(wh_name, h_parent, br); +- err = PTR_ERR(wh_dentry); +- if (IS_ERR(wh_dentry)) +- goto out; +- +- err = 0; +- if (!wh_dentry->d_inode) +- goto out_wh; /* success */ +- +- err = 1; +- if (S_ISREG(wh_dentry->d_inode->i_mode)) +- goto out_wh; /* success */ +- +- err = -EIO; +- AuIOErr("%.*s Invalid whiteout entry type 0%o.\n", +- AuDLNPair(wh_dentry), wh_dentry->d_inode->i_mode); +- +-out_wh: +- dput(wh_dentry); +-out: +- return err; +-} +- +-/* +- * test if the @h_dentry sets opaque or not. +- */ +-int au_diropq_test(struct dentry *h_dentry, struct au_branch *br) +-{ +- int err; +- struct inode *h_dir; +- +- h_dir = h_dentry->d_inode; +- err = au_wh_test(h_dentry, &diropq_name, br, +- au_test_h_perm_sio(h_dir, MAY_EXEC)); +- return err; +-} +- +-/* +- * returns a negative dentry whose name is unique and temporary. +- */ +-struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br, +- struct qstr *prefix) +-{ +- struct dentry *dentry; +- int i; +- char defname[NAME_MAX - AUFS_MAX_NAMELEN + DNAME_INLINE_LEN + 1], +- *name, *p; +- /* strict atomic_t is unnecessary here */ +- static unsigned short cnt; +- struct qstr qs; +- +- BUILD_BUG_ON(sizeof(cnt) * 2 > AUFS_WH_TMP_LEN); +- +- name = defname; +- qs.len = sizeof(defname) - DNAME_INLINE_LEN + prefix->len - 1; +- if (unlikely(prefix->len > DNAME_INLINE_LEN)) { +- dentry = ERR_PTR(-ENAMETOOLONG); +- if (unlikely(qs.len > NAME_MAX)) +- goto out; +- dentry = ERR_PTR(-ENOMEM); +- name = kmalloc(qs.len + 1, GFP_NOFS); +- if (unlikely(!name)) +- goto out; +- } +- +- /* doubly whiteout-ed */ +- memcpy(name, AUFS_WH_PFX AUFS_WH_PFX, AUFS_WH_PFX_LEN * 2); +- p = name + AUFS_WH_PFX_LEN * 2; +- memcpy(p, prefix->name, prefix->len); +- p += prefix->len; +- *p++ = '.'; +- AuDebugOn(name + qs.len + 1 - p <= AUFS_WH_TMP_LEN); +- +- qs.name = name; +- for (i = 0; i < 3; i++) { +- sprintf(p, "%.*x", AUFS_WH_TMP_LEN, cnt++); +- dentry = au_sio_lkup_one(&qs, h_parent, br); +- if (IS_ERR(dentry) || !dentry->d_inode) +- goto out_name; +- dput(dentry); +- } +- /* pr_warn("could not get random name\n"); */ +- dentry = ERR_PTR(-EEXIST); +- AuDbg("%.*s\n", AuLNPair(&qs)); +- BUG(); +- +-out_name: +- if (name != defname) +- kfree(name); +-out: +- AuTraceErrPtr(dentry); +- return dentry; +-} +- +-/* +- * rename the @h_dentry on @br to the whiteouted temporary name. +- */ +-int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br) +-{ +- int err; +- struct path h_path = { +- .mnt = br->br_mnt +- }; +- struct inode *h_dir; +- struct dentry *h_parent; +- +- h_parent = h_dentry->d_parent; /* dir inode is locked */ +- h_dir = h_parent->d_inode; +- IMustLock(h_dir); +- +- h_path.dentry = au_whtmp_lkup(h_parent, br, &h_dentry->d_name); +- err = PTR_ERR(h_path.dentry); +- if (IS_ERR(h_path.dentry)) +- goto out; +- +- /* under the same dir, no need to lock_rename() */ +- err = vfsub_rename(h_dir, h_dentry, h_dir, &h_path); +- AuTraceErr(err); +- dput(h_path.dentry); +- +-out: +- AuTraceErr(err); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +-/* +- * functions for removing a whiteout +- */ +- +-static int do_unlink_wh(struct inode *h_dir, struct path *h_path) +-{ +- int force; +- +- /* +- * forces superio when the dir has a sticky bit. +- * this may be a violation of unix fs semantics. +- */ +- force = (h_dir->i_mode & S_ISVTX) +- && !uid_eq(current_fsuid(), h_path->dentry->d_inode->i_uid); +- return vfsub_unlink(h_dir, h_path, force); +-} +- +-int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path, +- struct dentry *dentry) +-{ +- int err; +- +- err = do_unlink_wh(h_dir, h_path); +- if (!err && dentry) +- au_set_dbwh(dentry, -1); +- +- return err; +-} +- +-static int unlink_wh_name(struct dentry *h_parent, struct qstr *wh, +- struct au_branch *br) +-{ +- int err; +- struct path h_path = { +- .mnt = br->br_mnt +- }; +- +- err = 0; +- h_path.dentry = vfsub_lkup_one(wh, h_parent); +- if (IS_ERR(h_path.dentry)) +- err = PTR_ERR(h_path.dentry); +- else { +- if (h_path.dentry->d_inode +- && S_ISREG(h_path.dentry->d_inode->i_mode)) +- err = do_unlink_wh(h_parent->d_inode, &h_path); +- dput(h_path.dentry); +- } +- +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +-/* +- * initialize/clean whiteout for a branch +- */ +- +-static void au_wh_clean(struct inode *h_dir, struct path *whpath, +- const int isdir) +-{ +- int err; +- +- if (!whpath->dentry->d_inode) +- return; +- +- err = vfsub_mnt_want_write(whpath->mnt); +- if (!err) { +- if (isdir) +- err = vfsub_rmdir(h_dir, whpath); +- else +- err = vfsub_unlink(h_dir, whpath, /*force*/0); +- vfsub_mnt_drop_write(whpath->mnt); +- } +- if (unlikely(err)) +- pr_warn("failed removing %.*s (%d), ignored.\n", +- AuDLNPair(whpath->dentry), err); +-} +- +-static int test_linkable(struct dentry *h_root) +-{ +- struct inode *h_dir = h_root->d_inode; +- +- if (h_dir->i_op->link) +- return 0; +- +- pr_err("%.*s (%s) doesn't support link(2), use noplink and rw+nolwh\n", +- AuDLNPair(h_root), au_sbtype(h_root->d_sb)); +- return -ENOSYS; +-} +- +-/* todo: should this mkdir be done in /sbin/mount.aufs helper? */ +-static int au_whdir(struct inode *h_dir, struct path *path) +-{ +- int err; +- +- err = -EEXIST; +- if (!path->dentry->d_inode) { +- int mode = S_IRWXU; +- +- if (au_test_nfs(path->dentry->d_sb)) +- mode |= S_IXUGO; +- err = vfsub_mnt_want_write(path->mnt); +- if (!err) { +- err = vfsub_mkdir(h_dir, path, mode); +- vfsub_mnt_drop_write(path->mnt); +- } +- } else if (S_ISDIR(path->dentry->d_inode->i_mode)) +- err = 0; +- else +- pr_err("unknown %.*s exists\n", AuDLNPair(path->dentry)); +- +- return err; +-} +- +-struct au_wh_base { +- const struct qstr *name; +- struct dentry *dentry; +-}; +- +-static void au_wh_init_ro(struct inode *h_dir, struct au_wh_base base[], +- struct path *h_path) +-{ +- h_path->dentry = base[AuBrWh_BASE].dentry; +- au_wh_clean(h_dir, h_path, /*isdir*/0); +- h_path->dentry = base[AuBrWh_PLINK].dentry; +- au_wh_clean(h_dir, h_path, /*isdir*/1); +- h_path->dentry = base[AuBrWh_ORPH].dentry; +- au_wh_clean(h_dir, h_path, /*isdir*/1); +-} +- +-/* +- * returns tri-state, +- * minus: error, caller should print the mesage +- * zero: succuess +- * plus: error, caller should NOT print the mesage +- */ +-static int au_wh_init_rw_nolink(struct dentry *h_root, struct au_wbr *wbr, +- int do_plink, struct au_wh_base base[], +- struct path *h_path) +-{ +- int err; +- struct inode *h_dir; +- +- h_dir = h_root->d_inode; +- h_path->dentry = base[AuBrWh_BASE].dentry; +- au_wh_clean(h_dir, h_path, /*isdir*/0); +- h_path->dentry = base[AuBrWh_PLINK].dentry; +- if (do_plink) { +- err = test_linkable(h_root); +- if (unlikely(err)) { +- err = 1; +- goto out; +- } +- +- err = au_whdir(h_dir, h_path); +- if (unlikely(err)) +- goto out; +- wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry); +- } else +- au_wh_clean(h_dir, h_path, /*isdir*/1); +- h_path->dentry = base[AuBrWh_ORPH].dentry; +- err = au_whdir(h_dir, h_path); +- if (unlikely(err)) +- goto out; +- wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry); +- +-out: +- return err; +-} +- +-/* +- * for the moment, aufs supports the branch filesystem which does not support +- * link(2). testing on FAT which does not support i_op->setattr() fully either, +- * copyup failed. finally, such filesystem will not be used as the writable +- * branch. +- * +- * returns tri-state, see above. +- */ +-static int au_wh_init_rw(struct dentry *h_root, struct au_wbr *wbr, +- int do_plink, struct au_wh_base base[], +- struct path *h_path) +-{ +- int err; +- struct inode *h_dir; +- +- WbrWhMustWriteLock(wbr); +- +- err = test_linkable(h_root); +- if (unlikely(err)) { +- err = 1; +- goto out; +- } +- +- /* +- * todo: should this create be done in /sbin/mount.aufs helper? +- */ +- err = -EEXIST; +- h_dir = h_root->d_inode; +- if (!base[AuBrWh_BASE].dentry->d_inode) { +- err = vfsub_mnt_want_write(h_path->mnt); +- if (!err) { +- h_path->dentry = base[AuBrWh_BASE].dentry; +- err = vfsub_create(h_dir, h_path, WH_MASK, +- /*want_excl*/true); +- vfsub_mnt_drop_write(h_path->mnt); +- } +- } else if (S_ISREG(base[AuBrWh_BASE].dentry->d_inode->i_mode)) +- err = 0; +- else +- pr_err("unknown %.*s/%.*s exists\n", +- AuDLNPair(h_root), AuDLNPair(base[AuBrWh_BASE].dentry)); +- if (unlikely(err)) +- goto out; +- +- h_path->dentry = base[AuBrWh_PLINK].dentry; +- if (do_plink) { +- err = au_whdir(h_dir, h_path); +- if (unlikely(err)) +- goto out; +- wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry); +- } else +- au_wh_clean(h_dir, h_path, /*isdir*/1); +- wbr->wbr_whbase = dget(base[AuBrWh_BASE].dentry); +- +- h_path->dentry = base[AuBrWh_ORPH].dentry; +- err = au_whdir(h_dir, h_path); +- if (unlikely(err)) +- goto out; +- wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry); +- +-out: +- return err; +-} +- +-/* +- * initialize the whiteout base file/dir for @br. +- */ +-int au_wh_init(struct dentry *h_root, struct au_branch *br, +- struct super_block *sb) +-{ +- int err, i; +- const unsigned char do_plink +- = !!au_opt_test(au_mntflags(sb), PLINK); +- struct path path = { +- .mnt = br->br_mnt +- }; +- struct inode *h_dir; +- struct au_wbr *wbr = br->br_wbr; +- static const struct qstr base_name[] = { +- [AuBrWh_BASE] = QSTR_INIT(AUFS_BASE_NAME, +- sizeof(AUFS_BASE_NAME) - 1), +- [AuBrWh_PLINK] = QSTR_INIT(AUFS_PLINKDIR_NAME, +- sizeof(AUFS_PLINKDIR_NAME) - 1), +- [AuBrWh_ORPH] = QSTR_INIT(AUFS_ORPHDIR_NAME, +- sizeof(AUFS_ORPHDIR_NAME) - 1) +- }; +- struct au_wh_base base[] = { +- [AuBrWh_BASE] = { +- .name = base_name + AuBrWh_BASE, +- .dentry = NULL +- }, +- [AuBrWh_PLINK] = { +- .name = base_name + AuBrWh_PLINK, +- .dentry = NULL +- }, +- [AuBrWh_ORPH] = { +- .name = base_name + AuBrWh_ORPH, +- .dentry = NULL +- } +- }; +- +- if (wbr) +- WbrWhMustWriteLock(wbr); +- +- for (i = 0; i < AuBrWh_Last; i++) { +- /* doubly whiteouted */ +- struct dentry *d; +- +- d = au_wh_lkup(h_root, (void *)base[i].name, br); +- err = PTR_ERR(d); +- if (IS_ERR(d)) +- goto out; +- +- base[i].dentry = d; +- AuDebugOn(wbr +- && wbr->wbr_wh[i] +- && wbr->wbr_wh[i] != base[i].dentry); +- } +- +- if (wbr) +- for (i = 0; i < AuBrWh_Last; i++) { +- dput(wbr->wbr_wh[i]); +- wbr->wbr_wh[i] = NULL; +- } +- +- err = 0; +- if (!au_br_writable(br->br_perm)) { +- h_dir = h_root->d_inode; +- au_wh_init_ro(h_dir, base, &path); +- } else if (!au_br_wh_linkable(br->br_perm)) { +- err = au_wh_init_rw_nolink(h_root, wbr, do_plink, base, &path); +- if (err > 0) +- goto out; +- else if (err) +- goto out_err; +- } else { +- err = au_wh_init_rw(h_root, wbr, do_plink, base, &path); +- if (err > 0) +- goto out; +- else if (err) +- goto out_err; +- } +- goto out; /* success */ +- +-out_err: +- pr_err("an error(%d) on the writable branch %.*s(%s)\n", +- err, AuDLNPair(h_root), au_sbtype(h_root->d_sb)); +-out: +- for (i = 0; i < AuBrWh_Last; i++) +- dput(base[i].dentry); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +-/* +- * whiteouts are all hard-linked usually. +- * when its link count reaches a ceiling, we create a new whiteout base +- * asynchronously. +- */ +- +-struct reinit_br_wh { +- struct super_block *sb; +- struct au_branch *br; +-}; +- +-static void reinit_br_wh(void *arg) +-{ +- int err; +- aufs_bindex_t bindex; +- struct path h_path; +- struct reinit_br_wh *a = arg; +- struct au_wbr *wbr; +- struct inode *dir; +- struct dentry *h_root; +- struct au_hinode *hdir; +- +- err = 0; +- wbr = a->br->br_wbr; +- /* big aufs lock */ +- si_noflush_write_lock(a->sb); +- if (!au_br_writable(a->br->br_perm)) +- goto out; +- bindex = au_br_index(a->sb, a->br->br_id); +- if (unlikely(bindex < 0)) +- goto out; +- +- di_read_lock_parent(a->sb->s_root, AuLock_IR); +- dir = a->sb->s_root->d_inode; +- hdir = au_hi(dir, bindex); +- h_root = au_h_dptr(a->sb->s_root, bindex); +- +- au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT); +- wbr_wh_write_lock(wbr); +- err = au_h_verify(wbr->wbr_whbase, au_opt_udba(a->sb), hdir->hi_inode, +- h_root, a->br); +- if (!err) { +- err = vfsub_mnt_want_write(a->br->br_mnt); +- if (!err) { +- h_path.dentry = wbr->wbr_whbase; +- h_path.mnt = a->br->br_mnt; +- err = vfsub_unlink(hdir->hi_inode, &h_path, /*force*/0); +- vfsub_mnt_drop_write(a->br->br_mnt); +- } +- } else { +- pr_warn("%.*s is moved, ignored\n", +- AuDLNPair(wbr->wbr_whbase)); +- err = 0; +- } +- dput(wbr->wbr_whbase); +- wbr->wbr_whbase = NULL; +- if (!err) +- err = au_wh_init(h_root, a->br, a->sb); +- wbr_wh_write_unlock(wbr); +- au_hn_imtx_unlock(hdir); +- di_read_unlock(a->sb->s_root, AuLock_IR); +- +-out: +- if (wbr) +- atomic_dec(&wbr->wbr_wh_running); +- atomic_dec(&a->br->br_count); +- si_write_unlock(a->sb); +- au_nwt_done(&au_sbi(a->sb)->si_nowait); +- kfree(arg); +- if (unlikely(err)) +- AuIOErr("err %d\n", err); +-} +- +-static void kick_reinit_br_wh(struct super_block *sb, struct au_branch *br) +-{ +- int do_dec, wkq_err; +- struct reinit_br_wh *arg; +- +- do_dec = 1; +- if (atomic_inc_return(&br->br_wbr->wbr_wh_running) != 1) +- goto out; +- +- /* ignore ENOMEM */ +- arg = kmalloc(sizeof(*arg), GFP_NOFS); +- if (arg) { +- /* +- * dec(wh_running), kfree(arg) and dec(br_count) +- * in reinit function +- */ +- arg->sb = sb; +- arg->br = br; +- atomic_inc(&br->br_count); +- wkq_err = au_wkq_nowait(reinit_br_wh, arg, sb, /*flags*/0); +- if (unlikely(wkq_err)) { +- atomic_dec(&br->br_wbr->wbr_wh_running); +- atomic_dec(&br->br_count); +- kfree(arg); +- } +- do_dec = 0; +- } +- +-out: +- if (do_dec) +- atomic_dec(&br->br_wbr->wbr_wh_running); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* +- * create the whiteout @wh. +- */ +-static int link_or_create_wh(struct super_block *sb, aufs_bindex_t bindex, +- struct dentry *wh) +-{ +- int err; +- struct path h_path = { +- .dentry = wh +- }; +- struct au_branch *br; +- struct au_wbr *wbr; +- struct dentry *h_parent; +- struct inode *h_dir; +- +- h_parent = wh->d_parent; /* dir inode is locked */ +- h_dir = h_parent->d_inode; +- IMustLock(h_dir); +- +- br = au_sbr(sb, bindex); +- h_path.mnt = br->br_mnt; +- wbr = br->br_wbr; +- wbr_wh_read_lock(wbr); +- if (wbr->wbr_whbase) { +- err = vfsub_link(wbr->wbr_whbase, h_dir, &h_path); +- if (!err || err != -EMLINK) +- goto out; +- +- /* link count full. re-initialize br_whbase. */ +- kick_reinit_br_wh(sb, br); +- } +- +- /* return this error in this context */ +- err = vfsub_create(h_dir, &h_path, WH_MASK, /*want_excl*/true); +- +-out: +- wbr_wh_read_unlock(wbr); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* +- * create or remove the diropq. +- */ +-static struct dentry *do_diropq(struct dentry *dentry, aufs_bindex_t bindex, +- unsigned int flags) +-{ +- struct dentry *opq_dentry, *h_dentry; +- struct super_block *sb; +- struct au_branch *br; +- int err; +- +- sb = dentry->d_sb; +- br = au_sbr(sb, bindex); +- h_dentry = au_h_dptr(dentry, bindex); +- opq_dentry = vfsub_lkup_one(&diropq_name, h_dentry); +- if (IS_ERR(opq_dentry)) +- goto out; +- +- if (au_ftest_diropq(flags, CREATE)) { +- err = link_or_create_wh(sb, bindex, opq_dentry); +- if (!err) { +- au_set_dbdiropq(dentry, bindex); +- goto out; /* success */ +- } +- } else { +- struct path tmp = { +- .dentry = opq_dentry, +- .mnt = br->br_mnt +- }; +- err = do_unlink_wh(au_h_iptr(dentry->d_inode, bindex), &tmp); +- if (!err) +- au_set_dbdiropq(dentry, -1); +- } +- dput(opq_dentry); +- opq_dentry = ERR_PTR(err); +- +-out: +- return opq_dentry; +-} +- +-struct do_diropq_args { +- struct dentry **errp; +- struct dentry *dentry; +- aufs_bindex_t bindex; +- unsigned int flags; +-}; +- +-static void call_do_diropq(void *args) +-{ +- struct do_diropq_args *a = args; +- *a->errp = do_diropq(a->dentry, a->bindex, a->flags); +-} +- +-struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex, +- unsigned int flags) +-{ +- struct dentry *diropq, *h_dentry; +- +- h_dentry = au_h_dptr(dentry, bindex); +- if (!au_test_h_perm_sio(h_dentry->d_inode, MAY_EXEC | MAY_WRITE)) +- diropq = do_diropq(dentry, bindex, flags); +- else { +- int wkq_err; +- struct do_diropq_args args = { +- .errp = &diropq, +- .dentry = dentry, +- .bindex = bindex, +- .flags = flags +- }; +- +- wkq_err = au_wkq_wait(call_do_diropq, &args); +- if (unlikely(wkq_err)) +- diropq = ERR_PTR(wkq_err); +- } +- +- return diropq; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* +- * lookup whiteout dentry. +- * @h_parent: lower parent dentry which must exist and be locked +- * @base_name: name of dentry which will be whiteouted +- * returns dentry for whiteout. +- */ +-struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name, +- struct au_branch *br) +-{ +- int err; +- struct qstr wh_name; +- struct dentry *wh_dentry; +- +- err = au_wh_name_alloc(&wh_name, base_name); +- wh_dentry = ERR_PTR(err); +- if (!err) { +- wh_dentry = vfsub_lkup_one(&wh_name, h_parent); +- kfree(wh_name.name); +- } +- return wh_dentry; +-} +- +-/* +- * link/create a whiteout for @dentry on @bindex. +- */ +-struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex, +- struct dentry *h_parent) +-{ +- struct dentry *wh_dentry; +- struct super_block *sb; +- int err; +- +- sb = dentry->d_sb; +- wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, au_sbr(sb, bindex)); +- if (!IS_ERR(wh_dentry) && !wh_dentry->d_inode) { +- err = link_or_create_wh(sb, bindex, wh_dentry); +- if (!err) +- au_set_dbwh(dentry, bindex); +- else { +- dput(wh_dentry); +- wh_dentry = ERR_PTR(err); +- } +- } +- +- return wh_dentry; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* Delete all whiteouts in this directory on branch bindex. */ +-static int del_wh_children(struct dentry *h_dentry, struct au_nhash *whlist, +- aufs_bindex_t bindex, struct au_branch *br) +-{ +- int err; +- unsigned long ul, n; +- struct qstr wh_name; +- char *p; +- struct hlist_head *head; +- struct au_vdir_wh *tpos; +- struct hlist_node *pos; +- struct au_vdir_destr *str; +- +- err = -ENOMEM; +- p = (void *)__get_free_page(GFP_NOFS); +- wh_name.name = p; +- if (unlikely(!wh_name.name)) +- goto out; +- +- err = 0; +- memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); +- p += AUFS_WH_PFX_LEN; +- n = whlist->nh_num; +- head = whlist->nh_head; +- for (ul = 0; !err && ul < n; ul++, head++) { +- hlist_for_each_entry(tpos, pos, head, wh_hash) { +- if (tpos->wh_bindex != bindex) +- continue; +- +- str = &tpos->wh_str; +- if (str->len + AUFS_WH_PFX_LEN <= PATH_MAX) { +- memcpy(p, str->name, str->len); +- wh_name.len = AUFS_WH_PFX_LEN + str->len; +- err = unlink_wh_name(h_dentry, &wh_name, br); +- if (!err) +- continue; +- break; +- } +- AuIOErr("whiteout name too long %.*s\n", +- str->len, str->name); +- err = -EIO; +- break; +- } +- } +- free_page((unsigned long)wh_name.name); +- +-out: +- return err; +-} +- +-struct del_wh_children_args { +- int *errp; +- struct dentry *h_dentry; +- struct au_nhash *whlist; +- aufs_bindex_t bindex; +- struct au_branch *br; +-}; +- +-static void call_del_wh_children(void *args) +-{ +- struct del_wh_children_args *a = args; +- *a->errp = del_wh_children(a->h_dentry, a->whlist, a->bindex, a->br); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp) +-{ +- struct au_whtmp_rmdir *whtmp; +- int err; +- unsigned int rdhash; +- +- SiMustAnyLock(sb); +- +- whtmp = kmalloc(sizeof(*whtmp), gfp); +- if (unlikely(!whtmp)) { +- whtmp = ERR_PTR(-ENOMEM); +- goto out; +- } +- +- whtmp->dir = NULL; +- whtmp->br = NULL; +- whtmp->wh_dentry = NULL; +- /* no estimation for dir size */ +- rdhash = au_sbi(sb)->si_rdhash; +- if (!rdhash) +- rdhash = AUFS_RDHASH_DEF; +- err = au_nhash_alloc(&whtmp->whlist, rdhash, gfp); +- if (unlikely(err)) { +- kfree(whtmp); +- whtmp = ERR_PTR(err); +- } +- +-out: +- return whtmp; +-} +- +-void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp) +-{ +- if (whtmp->br) +- atomic_dec(&whtmp->br->br_count); +- dput(whtmp->wh_dentry); +- iput(whtmp->dir); +- au_nhash_wh_free(&whtmp->whlist); +- kfree(whtmp); +-} +- +-/* +- * rmdir the whiteouted temporary named dir @h_dentry. +- * @whlist: whiteouted children. +- */ +-int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex, +- struct dentry *wh_dentry, struct au_nhash *whlist) +-{ +- int err; +- struct path h_tmp; +- struct inode *wh_inode, *h_dir; +- struct au_branch *br; +- +- h_dir = wh_dentry->d_parent->d_inode; /* dir inode is locked */ +- IMustLock(h_dir); +- +- br = au_sbr(dir->i_sb, bindex); +- wh_inode = wh_dentry->d_inode; +- mutex_lock_nested(&wh_inode->i_mutex, AuLsc_I_CHILD); +- +- /* +- * someone else might change some whiteouts while we were sleeping. +- * it means this whlist may have an obsoleted entry. +- */ +- if (!au_test_h_perm_sio(wh_inode, MAY_EXEC | MAY_WRITE)) +- err = del_wh_children(wh_dentry, whlist, bindex, br); +- else { +- int wkq_err; +- struct del_wh_children_args args = { +- .errp = &err, +- .h_dentry = wh_dentry, +- .whlist = whlist, +- .bindex = bindex, +- .br = br +- }; +- +- wkq_err = au_wkq_wait(call_del_wh_children, &args); +- if (unlikely(wkq_err)) +- err = wkq_err; +- } +- mutex_unlock(&wh_inode->i_mutex); +- +- if (!err) { +- h_tmp.dentry = wh_dentry; +- h_tmp.mnt = br->br_mnt; +- err = vfsub_rmdir(h_dir, &h_tmp); +- } +- +- if (!err) { +- if (au_ibstart(dir) == bindex) { +- /* todo: dir->i_mutex is necessary */ +- au_cpup_attr_timesizes(dir); +- vfsub_drop_nlink(dir); +- } +- return 0; /* success */ +- } +- +- pr_warn("failed removing %.*s(%d), ignored\n", +- AuDLNPair(wh_dentry), err); +- return err; +-} +- +-static void call_rmdir_whtmp(void *args) +-{ +- int err; +- aufs_bindex_t bindex; +- struct au_whtmp_rmdir *a = args; +- struct super_block *sb; +- struct dentry *h_parent; +- struct inode *h_dir; +- struct au_hinode *hdir; +- +- /* rmdir by nfsd may cause deadlock with this i_mutex */ +- /* mutex_lock(&a->dir->i_mutex); */ +- err = -EROFS; +- sb = a->dir->i_sb; +- si_read_lock(sb, !AuLock_FLUSH); +- if (!au_br_writable(a->br->br_perm)) +- goto out; +- bindex = au_br_index(sb, a->br->br_id); +- if (unlikely(bindex < 0)) +- goto out; +- +- err = -EIO; +- ii_write_lock_parent(a->dir); +- h_parent = dget_parent(a->wh_dentry); +- h_dir = h_parent->d_inode; +- hdir = au_hi(a->dir, bindex); +- au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT); +- err = au_h_verify(a->wh_dentry, au_opt_udba(sb), h_dir, h_parent, +- a->br); +- if (!err) { +- err = vfsub_mnt_want_write(a->br->br_mnt); +- if (!err) { +- err = au_whtmp_rmdir(a->dir, bindex, a->wh_dentry, +- &a->whlist); +- vfsub_mnt_drop_write(a->br->br_mnt); +- } +- } +- au_hn_imtx_unlock(hdir); +- dput(h_parent); +- ii_write_unlock(a->dir); +- +-out: +- /* mutex_unlock(&a->dir->i_mutex); */ +- au_whtmp_rmdir_free(a); +- si_read_unlock(sb); +- au_nwt_done(&au_sbi(sb)->si_nowait); +- if (unlikely(err)) +- AuIOErr("err %d\n", err); +-} +- +-void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex, +- struct dentry *wh_dentry, struct au_whtmp_rmdir *args) +-{ +- int wkq_err; +- struct super_block *sb; +- +- IMustLock(dir); +- +- /* all post-process will be done in do_rmdir_whtmp(). */ +- sb = dir->i_sb; +- args->dir = au_igrab(dir); +- args->br = au_sbr(sb, bindex); +- atomic_inc(&args->br->br_count); +- args->wh_dentry = dget(wh_dentry); +- wkq_err = au_wkq_nowait(call_rmdir_whtmp, args, sb, /*flags*/0); +- if (unlikely(wkq_err)) { +- pr_warn("rmdir error %.*s (%d), ignored\n", +- AuDLNPair(wh_dentry), wkq_err); +- au_whtmp_rmdir_free(args); +- } +-} +diff --git a/fs/aufs/whout.h b/fs/aufs/whout.h +deleted file mode 100644 +index deb4d5a..0000000 +--- a/fs/aufs/whout.h ++++ /dev/null +@@ -1,88 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * whiteout for logical deletion and opaque directory +- */ +- +-#ifndef __AUFS_WHOUT_H__ +-#define __AUFS_WHOUT_H__ +- +-#ifdef __KERNEL__ +- +-#include "dir.h" +- +-/* whout.c */ +-int au_wh_name_alloc(struct qstr *wh, const struct qstr *name); +-struct au_branch; +-int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, +- struct au_branch *br, int try_sio); +-int au_diropq_test(struct dentry *h_dentry, struct au_branch *br); +-struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br, +- struct qstr *prefix); +-int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br); +-int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path, +- struct dentry *dentry); +-int au_wh_init(struct dentry *h_parent, struct au_branch *br, +- struct super_block *sb); +- +-/* diropq flags */ +-#define AuDiropq_CREATE 1 +-#define au_ftest_diropq(flags, name) ((flags) & AuDiropq_##name) +-#define au_fset_diropq(flags, name) \ +- do { (flags) |= AuDiropq_##name; } while (0) +-#define au_fclr_diropq(flags, name) \ +- do { (flags) &= ~AuDiropq_##name; } while (0) +- +-struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex, +- unsigned int flags); +-struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name, +- struct au_branch *br); +-struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex, +- struct dentry *h_parent); +- +-/* real rmdir for the whiteout-ed dir */ +-struct au_whtmp_rmdir { +- struct inode *dir; +- struct au_branch *br; +- struct dentry *wh_dentry; +- struct au_nhash whlist; +-}; +- +-struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp); +-void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp); +-int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex, +- struct dentry *wh_dentry, struct au_nhash *whlist); +-void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex, +- struct dentry *wh_dentry, struct au_whtmp_rmdir *args); +- +-/* ---------------------------------------------------------------------- */ +- +-static inline struct dentry *au_diropq_create(struct dentry *dentry, +- aufs_bindex_t bindex) +-{ +- return au_diropq_sio(dentry, bindex, AuDiropq_CREATE); +-} +- +-static inline int au_diropq_remove(struct dentry *dentry, aufs_bindex_t bindex) +-{ +- return PTR_ERR(au_diropq_sio(dentry, bindex, !AuDiropq_CREATE)); +-} +- +-#endif /* __KERNEL__ */ +-#endif /* __AUFS_WHOUT_H__ */ +diff --git a/fs/aufs/wkq.c b/fs/aufs/wkq.c +deleted file mode 100644 +index c144c5a..0000000 +--- a/fs/aufs/wkq.c ++++ /dev/null +@@ -1,214 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * workqueue for asynchronous/super-io operations +- * todo: try new dredential scheme +- */ +- +-#include +-#include "aufs.h" +- +-/* internal workqueue named AUFS_WKQ_NAME */ +- +-static struct workqueue_struct *au_wkq; +- +-struct au_wkinfo { +- struct work_struct wk; +- struct kobject *kobj; +- +- unsigned int flags; /* see wkq.h */ +- +- au_wkq_func_t func; +- void *args; +- +- struct completion *comp; +-}; +- +-/* ---------------------------------------------------------------------- */ +- +-static void wkq_func(struct work_struct *wk) +-{ +- struct au_wkinfo *wkinfo = container_of(wk, struct au_wkinfo, wk); +- +- AuDebugOn(!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)); +- AuDebugOn(rlimit(RLIMIT_FSIZE) != RLIM_INFINITY); +- +- wkinfo->func(wkinfo->args); +- if (au_ftest_wkq(wkinfo->flags, WAIT)) +- complete(wkinfo->comp); +- else { +- kobject_put(wkinfo->kobj); +- module_put(THIS_MODULE); /* todo: ?? */ +- kfree(wkinfo); +- } +-} +- +-/* +- * Since struct completion is large, try allocating it dynamically. +- */ +-#if defined(CONFIG_4KSTACKS) || defined(AuTest4KSTACKS) +-#define AuWkqCompDeclare(name) struct completion *comp = NULL +- +-static int au_wkq_comp_alloc(struct au_wkinfo *wkinfo, struct completion **comp) +-{ +- *comp = kmalloc(sizeof(**comp), GFP_NOFS); +- if (*comp) { +- init_completion(*comp); +- wkinfo->comp = *comp; +- return 0; +- } +- return -ENOMEM; +-} +- +-static void au_wkq_comp_free(struct completion *comp) +-{ +- kfree(comp); +-} +- +-#else +- +-/* no braces */ +-#define AuWkqCompDeclare(name) \ +- DECLARE_COMPLETION_ONSTACK(_ ## name); \ +- struct completion *comp = &_ ## name +- +-static int au_wkq_comp_alloc(struct au_wkinfo *wkinfo, struct completion **comp) +-{ +- wkinfo->comp = *comp; +- return 0; +-} +- +-static void au_wkq_comp_free(struct completion *comp __maybe_unused) +-{ +- /* empty */ +-} +-#endif /* 4KSTACKS */ +- +-static void au_wkq_run(struct au_wkinfo *wkinfo) +-{ +- if (au_ftest_wkq(wkinfo->flags, NEST)) { +- if (au_wkq_test()) { +- AuWarn1("wkq from wkq, due to a dead dir by UDBA?\n"); +- AuDebugOn(au_ftest_wkq(wkinfo->flags, WAIT)); +- } +- } else +- au_dbg_verify_kthread(); +- +- if (au_ftest_wkq(wkinfo->flags, WAIT)) { +- INIT_WORK_ONSTACK(&wkinfo->wk, wkq_func); +- queue_work(au_wkq, &wkinfo->wk); +- } else { +- INIT_WORK(&wkinfo->wk, wkq_func); +- schedule_work(&wkinfo->wk); +- } +-} +- +-/* +- * Be careful. It is easy to make deadlock happen. +- * processA: lock, wkq and wait +- * processB: wkq and wait, lock in wkq +- * --> deadlock +- */ +-int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args) +-{ +- int err; +- AuWkqCompDeclare(comp); +- struct au_wkinfo wkinfo = { +- .flags = flags, +- .func = func, +- .args = args +- }; +- +- err = au_wkq_comp_alloc(&wkinfo, &comp); +- if (!err) { +- au_wkq_run(&wkinfo); +- /* no timeout, no interrupt */ +- wait_for_completion(wkinfo.comp); +- au_wkq_comp_free(comp); +- destroy_work_on_stack(&wkinfo.wk); +- } +- +- return err; +- +-} +- +-/* +- * Note: dget/dput() in func for aufs dentries are not supported. It will be a +- * problem in a concurrent umounting. +- */ +-int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb, +- unsigned int flags) +-{ +- int err; +- struct au_wkinfo *wkinfo; +- +- atomic_inc(&au_sbi(sb)->si_nowait.nw_len); +- +- /* +- * wkq_func() must free this wkinfo. +- * it highly depends upon the implementation of workqueue. +- */ +- err = 0; +- wkinfo = kmalloc(sizeof(*wkinfo), GFP_NOFS); +- if (wkinfo) { +- wkinfo->kobj = &au_sbi(sb)->si_kobj; +- wkinfo->flags = flags & ~AuWkq_WAIT; +- wkinfo->func = func; +- wkinfo->args = args; +- wkinfo->comp = NULL; +- kobject_get(wkinfo->kobj); +- __module_get(THIS_MODULE); /* todo: ?? */ +- +- au_wkq_run(wkinfo); +- } else { +- err = -ENOMEM; +- au_nwt_done(&au_sbi(sb)->si_nowait); +- } +- +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-void au_nwt_init(struct au_nowait_tasks *nwt) +-{ +- atomic_set(&nwt->nw_len, 0); +- /* smp_mb(); */ /* atomic_set */ +- init_waitqueue_head(&nwt->nw_wq); +-} +- +-void au_wkq_fin(void) +-{ +- destroy_workqueue(au_wkq); +-} +- +-int __init au_wkq_init(void) +-{ +- int err; +- +- err = 0; +- BUILD_BUG_ON(!WQ_RESCUER); +- au_wkq = alloc_workqueue(AUFS_WKQ_NAME, !WQ_RESCUER, WQ_DFL_ACTIVE); +- if (IS_ERR(au_wkq)) +- err = PTR_ERR(au_wkq); +- else if (!au_wkq) +- err = -ENOMEM; +- +- return err; +-} +diff --git a/fs/aufs/wkq.h b/fs/aufs/wkq.h +deleted file mode 100644 +index c316b7f..0000000 +--- a/fs/aufs/wkq.h ++++ /dev/null +@@ -1,92 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * workqueue for asynchronous/super-io operations +- * todo: try new credentials management scheme +- */ +- +-#ifndef __AUFS_WKQ_H__ +-#define __AUFS_WKQ_H__ +- +-#ifdef __KERNEL__ +- +-struct super_block; +- +-/* ---------------------------------------------------------------------- */ +- +-/* +- * in the next operation, wait for the 'nowait' tasks in system-wide workqueue +- */ +-struct au_nowait_tasks { +- atomic_t nw_len; +- wait_queue_head_t nw_wq; +-}; +- +-/* ---------------------------------------------------------------------- */ +- +-typedef void (*au_wkq_func_t)(void *args); +- +-/* wkq flags */ +-#define AuWkq_WAIT 1 +-#define AuWkq_NEST (1 << 1) +-#define au_ftest_wkq(flags, name) ((flags) & AuWkq_##name) +-#define au_fset_wkq(flags, name) \ +- do { (flags) |= AuWkq_##name; } while (0) +-#define au_fclr_wkq(flags, name) \ +- do { (flags) &= ~AuWkq_##name; } while (0) +- +-#ifndef CONFIG_AUFS_HNOTIFY +-#undef AuWkq_NEST +-#define AuWkq_NEST 0 +-#endif +- +-/* wkq.c */ +-int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args); +-int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb, +- unsigned int flags); +-void au_nwt_init(struct au_nowait_tasks *nwt); +-int __init au_wkq_init(void); +-void au_wkq_fin(void); +- +-/* ---------------------------------------------------------------------- */ +- +-static inline int au_wkq_test(void) +-{ +- return current->flags & PF_WQ_WORKER; +-} +- +-static inline int au_wkq_wait(au_wkq_func_t func, void *args) +-{ +- return au_wkq_do_wait(AuWkq_WAIT, func, args); +-} +- +-static inline void au_nwt_done(struct au_nowait_tasks *nwt) +-{ +- if (atomic_dec_and_test(&nwt->nw_len)) +- wake_up_all(&nwt->nw_wq); +-} +- +-static inline int au_nwt_flush(struct au_nowait_tasks *nwt) +-{ +- wait_event(nwt->nw_wq, !atomic_read(&nwt->nw_len)); +- return 0; +-} +- +-#endif /* __KERNEL__ */ +-#endif /* __AUFS_WKQ_H__ */ +diff --git a/fs/aufs/xino.c b/fs/aufs/xino.c +deleted file mode 100644 +index 541517a..0000000 +--- a/fs/aufs/xino.c ++++ /dev/null +@@ -1,1265 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-/* +- * external inode number translation table and bitmap +- */ +- +-#include +-#include "aufs.h" +- +-/* todo: unnecessary to support mmap_sem since kernel-space? */ +-ssize_t xino_fread(au_readf_t func, struct file *file, void *kbuf, size_t size, +- loff_t *pos) +-{ +- ssize_t err; +- mm_segment_t oldfs; +- union { +- void *k; +- char __user *u; +- } buf; +- +- buf.k = kbuf; +- oldfs = get_fs(); +- set_fs(KERNEL_DS); +- do { +- /* todo: signal_pending? */ +- err = func(file, buf.u, size, pos); +- } while (err == -EAGAIN || err == -EINTR); +- set_fs(oldfs); +- +-#if 0 /* reserved for future use */ +- if (err > 0) +- fsnotify_access(file->f_dentry); +-#endif +- +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static ssize_t do_xino_fwrite(au_writef_t func, struct file *file, void *kbuf, +- size_t size, loff_t *pos) +-{ +- ssize_t err; +- mm_segment_t oldfs; +- union { +- void *k; +- const char __user *u; +- } buf; +- +- buf.k = kbuf; +- oldfs = get_fs(); +- set_fs(KERNEL_DS); +- do { +- /* todo: signal_pending? */ +- err = func(file, buf.u, size, pos); +- } while (err == -EAGAIN || err == -EINTR); +- set_fs(oldfs); +- +-#if 0 /* reserved for future use */ +- if (err > 0) +- fsnotify_modify(file->f_dentry); +-#endif +- +- return err; +-} +- +-struct do_xino_fwrite_args { +- ssize_t *errp; +- au_writef_t func; +- struct file *file; +- void *buf; +- size_t size; +- loff_t *pos; +-}; +- +-static void call_do_xino_fwrite(void *args) +-{ +- struct do_xino_fwrite_args *a = args; +- *a->errp = do_xino_fwrite(a->func, a->file, a->buf, a->size, a->pos); +-} +- +-ssize_t xino_fwrite(au_writef_t func, struct file *file, void *buf, size_t size, +- loff_t *pos) +-{ +- ssize_t err; +- +- /* todo: signal block and no wkq? */ +- if (rlimit(RLIMIT_FSIZE) == RLIM_INFINITY) { +- lockdep_off(); +- err = do_xino_fwrite(func, file, buf, size, pos); +- lockdep_on(); +- } else { +- /* +- * it breaks RLIMIT_FSIZE and normal user's limit, +- * users should care about quota and real 'filesystem full.' +- */ +- int wkq_err; +- struct do_xino_fwrite_args args = { +- .errp = &err, +- .func = func, +- .file = file, +- .buf = buf, +- .size = size, +- .pos = pos +- }; +- +- wkq_err = au_wkq_wait(call_do_xino_fwrite, &args); +- if (unlikely(wkq_err)) +- err = wkq_err; +- } +- +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* +- * create a new xinofile at the same place/path as @base_file. +- */ +-struct file *au_xino_create2(struct file *base_file, struct file *copy_src) +-{ +- struct file *file; +- struct dentry *base, *parent; +- struct inode *dir; +- struct qstr *name; +- struct path path; +- int err; +- +- base = base_file->f_dentry; +- parent = base->d_parent; /* dir inode is locked */ +- dir = parent->d_inode; +- IMustLock(dir); +- +- file = ERR_PTR(-EINVAL); +- name = &base->d_name; +- path.dentry = vfsub_lookup_one_len(name->name, parent, name->len); +- if (IS_ERR(path.dentry)) { +- file = (void *)path.dentry; +- pr_err("%.*s lookup err %ld\n", +- AuLNPair(name), PTR_ERR(path.dentry)); +- goto out; +- } +- +- /* no need to mnt_want_write() since we call dentry_open() later */ +- err = vfs_create(dir, path.dentry, S_IRUGO | S_IWUGO, NULL); +- if (unlikely(err)) { +- file = ERR_PTR(err); +- pr_err("%.*s create err %d\n", AuLNPair(name), err); +- goto out_dput; +- } +- +- path.mnt = base_file->f_vfsmnt; +- file = vfsub_dentry_open(&path, +- O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE +- /* | __FMODE_NONOTIFY */); +- if (IS_ERR(file)) { +- pr_err("%.*s open err %ld\n", AuLNPair(name), PTR_ERR(file)); +- goto out_dput; +- } +- +- err = vfsub_unlink(dir, &file->f_path, /*force*/0); +- if (unlikely(err)) { +- pr_err("%.*s unlink err %d\n", AuLNPair(name), err); +- goto out_fput; +- } +- +- if (copy_src) { +- /* no one can touch copy_src xino */ +- err = au_copy_file(file, copy_src, +- i_size_read(copy_src->f_dentry->d_inode)); +- if (unlikely(err)) { +- pr_err("%.*s copy err %d\n", AuLNPair(name), err); +- goto out_fput; +- } +- } +- goto out_dput; /* success */ +- +-out_fput: +- fput(file); +- file = ERR_PTR(err); +-out_dput: +- dput(path.dentry); +-out: +- return file; +-} +- +-struct au_xino_lock_dir { +- struct au_hinode *hdir; +- struct dentry *parent; +- struct mutex *mtx; +-}; +- +-static void au_xino_lock_dir(struct super_block *sb, struct file *xino, +- struct au_xino_lock_dir *ldir) +-{ +- aufs_bindex_t brid, bindex; +- +- ldir->hdir = NULL; +- bindex = -1; +- brid = au_xino_brid(sb); +- if (brid >= 0) +- bindex = au_br_index(sb, brid); +- if (bindex >= 0) { +- ldir->hdir = au_hi(sb->s_root->d_inode, bindex); +- au_hn_imtx_lock_nested(ldir->hdir, AuLsc_I_PARENT); +- } else { +- ldir->parent = dget_parent(xino->f_dentry); +- ldir->mtx = &ldir->parent->d_inode->i_mutex; +- mutex_lock_nested(ldir->mtx, AuLsc_I_PARENT); +- } +-} +- +-static void au_xino_unlock_dir(struct au_xino_lock_dir *ldir) +-{ +- if (ldir->hdir) +- au_hn_imtx_unlock(ldir->hdir); +- else { +- mutex_unlock(ldir->mtx); +- dput(ldir->parent); +- } +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* trucate xino files asynchronously */ +- +-int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex) +-{ +- int err; +- aufs_bindex_t bi, bend; +- struct au_branch *br; +- struct file *new_xino, *file; +- struct super_block *h_sb; +- struct au_xino_lock_dir ldir; +- +- err = -EINVAL; +- bend = au_sbend(sb); +- if (unlikely(bindex < 0 || bend < bindex)) +- goto out; +- br = au_sbr(sb, bindex); +- file = br->br_xino.xi_file; +- if (!file) +- goto out; +- +- au_xino_lock_dir(sb, file, &ldir); +- /* mnt_want_write() is unnecessary here */ +- new_xino = au_xino_create2(file, file); +- au_xino_unlock_dir(&ldir); +- err = PTR_ERR(new_xino); +- if (IS_ERR(new_xino)) +- goto out; +- err = 0; +- fput(file); +- br->br_xino.xi_file = new_xino; +- +- h_sb = br->br_mnt->mnt_sb; +- for (bi = 0; bi <= bend; bi++) { +- if (unlikely(bi == bindex)) +- continue; +- br = au_sbr(sb, bi); +- if (br->br_mnt->mnt_sb != h_sb) +- continue; +- +- fput(br->br_xino.xi_file); +- br->br_xino.xi_file = new_xino; +- get_file(new_xino); +- } +- +-out: +- return err; +-} +- +-struct xino_do_trunc_args { +- struct super_block *sb; +- struct au_branch *br; +-}; +- +-static void xino_do_trunc(void *_args) +-{ +- struct xino_do_trunc_args *args = _args; +- struct super_block *sb; +- struct au_branch *br; +- struct inode *dir; +- int err; +- aufs_bindex_t bindex; +- +- err = 0; +- sb = args->sb; +- dir = sb->s_root->d_inode; +- br = args->br; +- +- si_noflush_write_lock(sb); +- ii_read_lock_parent(dir); +- bindex = au_br_index(sb, br->br_id); +- err = au_xino_trunc(sb, bindex); +- if (!err +- && br->br_xino.xi_file->f_dentry->d_inode->i_blocks +- >= br->br_xino_upper) +- br->br_xino_upper += AUFS_XINO_TRUNC_STEP; +- +- ii_read_unlock(dir); +- if (unlikely(err)) +- pr_warn("err b%d, upper %llu, (%d)\n", +- bindex, (unsigned long long)br->br_xino_upper, err); +- atomic_dec(&br->br_xino_running); +- atomic_dec(&br->br_count); +- si_write_unlock(sb); +- au_nwt_done(&au_sbi(sb)->si_nowait); +- kfree(args); +-} +- +-static void xino_try_trunc(struct super_block *sb, struct au_branch *br) +-{ +- struct xino_do_trunc_args *args; +- int wkq_err; +- +- if (br->br_xino.xi_file->f_dentry->d_inode->i_blocks +- < br->br_xino_upper) +- return; +- +- if (atomic_inc_return(&br->br_xino_running) > 1) +- goto out; +- +- /* lock and kfree() will be called in trunc_xino() */ +- args = kmalloc(sizeof(*args), GFP_NOFS); +- if (unlikely(!args)) { +- AuErr1("no memory\n"); +- goto out_args; +- } +- +- atomic_inc(&br->br_count); +- args->sb = sb; +- args->br = br; +- wkq_err = au_wkq_nowait(xino_do_trunc, args, sb, /*flags*/0); +- if (!wkq_err) +- return; /* success */ +- +- pr_err("wkq %d\n", wkq_err); +- atomic_dec(&br->br_count); +- +-out_args: +- kfree(args); +-out: +- atomic_dec(&br->br_xino_running); +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static int au_xino_do_write(au_writef_t write, struct file *file, +- ino_t h_ino, ino_t ino) +-{ +- loff_t pos; +- ssize_t sz; +- +- pos = h_ino; +- if (unlikely(au_loff_max / sizeof(ino) - 1 < pos)) { +- AuIOErr1("too large hi%lu\n", (unsigned long)h_ino); +- return -EFBIG; +- } +- pos *= sizeof(ino); +- sz = xino_fwrite(write, file, &ino, sizeof(ino), &pos); +- if (sz == sizeof(ino)) +- return 0; /* success */ +- +- AuIOErr("write failed (%zd)\n", sz); +- return -EIO; +-} +- +-/* +- * write @ino to the xinofile for the specified branch{@sb, @bindex} +- * at the position of @h_ino. +- * even if @ino is zero, it is written to the xinofile and means no entry. +- * if the size of the xino file on a specific filesystem exceeds the watermark, +- * try truncating it. +- */ +-int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, +- ino_t ino) +-{ +- int err; +- unsigned int mnt_flags; +- struct au_branch *br; +- +- BUILD_BUG_ON(sizeof(long long) != sizeof(au_loff_max) +- || ((loff_t)-1) > 0); +- SiMustAnyLock(sb); +- +- mnt_flags = au_mntflags(sb); +- if (!au_opt_test(mnt_flags, XINO)) +- return 0; +- +- br = au_sbr(sb, bindex); +- err = au_xino_do_write(au_sbi(sb)->si_xwrite, br->br_xino.xi_file, +- h_ino, ino); +- if (!err) { +- if (au_opt_test(mnt_flags, TRUNC_XINO) +- && au_test_fs_trunc_xino(br->br_mnt->mnt_sb)) +- xino_try_trunc(sb, br); +- return 0; /* success */ +- } +- +- AuIOErr("write failed (%d)\n", err); +- return -EIO; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* aufs inode number bitmap */ +- +-static const int page_bits = (int)PAGE_SIZE * BITS_PER_BYTE; +-static ino_t xib_calc_ino(unsigned long pindex, int bit) +-{ +- ino_t ino; +- +- AuDebugOn(bit < 0 || page_bits <= bit); +- ino = AUFS_FIRST_INO + pindex * page_bits + bit; +- return ino; +-} +- +-static void xib_calc_bit(ino_t ino, unsigned long *pindex, int *bit) +-{ +- AuDebugOn(ino < AUFS_FIRST_INO); +- ino -= AUFS_FIRST_INO; +- *pindex = ino / page_bits; +- *bit = ino % page_bits; +-} +- +-static int xib_pindex(struct super_block *sb, unsigned long pindex) +-{ +- int err; +- loff_t pos; +- ssize_t sz; +- struct au_sbinfo *sbinfo; +- struct file *xib; +- unsigned long *p; +- +- sbinfo = au_sbi(sb); +- MtxMustLock(&sbinfo->si_xib_mtx); +- AuDebugOn(pindex > ULONG_MAX / PAGE_SIZE +- || !au_opt_test(sbinfo->si_mntflags, XINO)); +- +- if (pindex == sbinfo->si_xib_last_pindex) +- return 0; +- +- xib = sbinfo->si_xib; +- p = sbinfo->si_xib_buf; +- pos = sbinfo->si_xib_last_pindex; +- pos *= PAGE_SIZE; +- sz = xino_fwrite(sbinfo->si_xwrite, xib, p, PAGE_SIZE, &pos); +- if (unlikely(sz != PAGE_SIZE)) +- goto out; +- +- pos = pindex; +- pos *= PAGE_SIZE; +- if (i_size_read(xib->f_dentry->d_inode) >= pos + PAGE_SIZE) +- sz = xino_fread(sbinfo->si_xread, xib, p, PAGE_SIZE, &pos); +- else { +- memset(p, 0, PAGE_SIZE); +- sz = xino_fwrite(sbinfo->si_xwrite, xib, p, PAGE_SIZE, &pos); +- } +- if (sz == PAGE_SIZE) { +- sbinfo->si_xib_last_pindex = pindex; +- return 0; /* success */ +- } +- +-out: +- AuIOErr1("write failed (%zd)\n", sz); +- err = sz; +- if (sz >= 0) +- err = -EIO; +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-static void au_xib_clear_bit(struct inode *inode) +-{ +- int err, bit; +- unsigned long pindex; +- struct super_block *sb; +- struct au_sbinfo *sbinfo; +- +- AuDebugOn(inode->i_nlink); +- +- sb = inode->i_sb; +- xib_calc_bit(inode->i_ino, &pindex, &bit); +- AuDebugOn(page_bits <= bit); +- sbinfo = au_sbi(sb); +- mutex_lock(&sbinfo->si_xib_mtx); +- err = xib_pindex(sb, pindex); +- if (!err) { +- clear_bit(bit, sbinfo->si_xib_buf); +- sbinfo->si_xib_next_bit = bit; +- } +- mutex_unlock(&sbinfo->si_xib_mtx); +-} +- +-/* for s_op->delete_inode() */ +-void au_xino_delete_inode(struct inode *inode, const int unlinked) +-{ +- int err; +- unsigned int mnt_flags; +- aufs_bindex_t bindex, bend, bi; +- unsigned char try_trunc; +- struct au_iinfo *iinfo; +- struct super_block *sb; +- struct au_hinode *hi; +- struct inode *h_inode; +- struct au_branch *br; +- au_writef_t xwrite; +- +- sb = inode->i_sb; +- mnt_flags = au_mntflags(sb); +- if (!au_opt_test(mnt_flags, XINO) +- || inode->i_ino == AUFS_ROOT_INO) +- return; +- +- if (unlinked) { +- au_xigen_inc(inode); +- au_xib_clear_bit(inode); +- } +- +- iinfo = au_ii(inode); +- if (!iinfo) +- return; +- +- bindex = iinfo->ii_bstart; +- if (bindex < 0) +- return; +- +- xwrite = au_sbi(sb)->si_xwrite; +- try_trunc = !!au_opt_test(mnt_flags, TRUNC_XINO); +- hi = iinfo->ii_hinode + bindex; +- bend = iinfo->ii_bend; +- for (; bindex <= bend; bindex++, hi++) { +- h_inode = hi->hi_inode; +- if (!h_inode +- || (!unlinked && h_inode->i_nlink)) +- continue; +- +- /* inode may not be revalidated */ +- bi = au_br_index(sb, hi->hi_id); +- if (bi < 0) +- continue; +- +- br = au_sbr(sb, bi); +- err = au_xino_do_write(xwrite, br->br_xino.xi_file, +- h_inode->i_ino, /*ino*/0); +- if (!err && try_trunc +- && au_test_fs_trunc_xino(br->br_mnt->mnt_sb)) +- xino_try_trunc(sb, br); +- } +-} +- +-/* get an unused inode number from bitmap */ +-ino_t au_xino_new_ino(struct super_block *sb) +-{ +- ino_t ino; +- unsigned long *p, pindex, ul, pend; +- struct au_sbinfo *sbinfo; +- struct file *file; +- int free_bit, err; +- +- if (!au_opt_test(au_mntflags(sb), XINO)) +- return iunique(sb, AUFS_FIRST_INO); +- +- sbinfo = au_sbi(sb); +- mutex_lock(&sbinfo->si_xib_mtx); +- p = sbinfo->si_xib_buf; +- free_bit = sbinfo->si_xib_next_bit; +- if (free_bit < page_bits && !test_bit(free_bit, p)) +- goto out; /* success */ +- free_bit = find_first_zero_bit(p, page_bits); +- if (free_bit < page_bits) +- goto out; /* success */ +- +- pindex = sbinfo->si_xib_last_pindex; +- for (ul = pindex - 1; ul < ULONG_MAX; ul--) { +- err = xib_pindex(sb, ul); +- if (unlikely(err)) +- goto out_err; +- free_bit = find_first_zero_bit(p, page_bits); +- if (free_bit < page_bits) +- goto out; /* success */ +- } +- +- file = sbinfo->si_xib; +- pend = i_size_read(file->f_dentry->d_inode) / PAGE_SIZE; +- for (ul = pindex + 1; ul <= pend; ul++) { +- err = xib_pindex(sb, ul); +- if (unlikely(err)) +- goto out_err; +- free_bit = find_first_zero_bit(p, page_bits); +- if (free_bit < page_bits) +- goto out; /* success */ +- } +- BUG(); +- +-out: +- set_bit(free_bit, p); +- sbinfo->si_xib_next_bit = free_bit + 1; +- pindex = sbinfo->si_xib_last_pindex; +- mutex_unlock(&sbinfo->si_xib_mtx); +- ino = xib_calc_ino(pindex, free_bit); +- AuDbg("i%lu\n", (unsigned long)ino); +- return ino; +-out_err: +- mutex_unlock(&sbinfo->si_xib_mtx); +- AuDbg("i0\n"); +- return 0; +-} +- +-/* +- * read @ino from xinofile for the specified branch{@sb, @bindex} +- * at the position of @h_ino. +- * if @ino does not exist and @do_new is true, get new one. +- */ +-int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, +- ino_t *ino) +-{ +- int err; +- ssize_t sz; +- loff_t pos; +- struct file *file; +- struct au_sbinfo *sbinfo; +- +- *ino = 0; +- if (!au_opt_test(au_mntflags(sb), XINO)) +- return 0; /* no xino */ +- +- err = 0; +- sbinfo = au_sbi(sb); +- pos = h_ino; +- if (unlikely(au_loff_max / sizeof(*ino) - 1 < pos)) { +- AuIOErr1("too large hi%lu\n", (unsigned long)h_ino); +- return -EFBIG; +- } +- pos *= sizeof(*ino); +- +- file = au_sbr(sb, bindex)->br_xino.xi_file; +- if (i_size_read(file->f_dentry->d_inode) < pos + sizeof(*ino)) +- return 0; /* no ino */ +- +- sz = xino_fread(sbinfo->si_xread, file, ino, sizeof(*ino), &pos); +- if (sz == sizeof(*ino)) +- return 0; /* success */ +- +- err = sz; +- if (unlikely(sz >= 0)) { +- err = -EIO; +- AuIOErr("xino read error (%zd)\n", sz); +- } +- +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* create and set a new xino file */ +- +-struct file *au_xino_create(struct super_block *sb, char *fname, int silent) +-{ +- struct file *file; +- struct dentry *h_parent, *d; +- struct inode *h_dir; +- int err; +- +- /* +- * at mount-time, and the xino file is the default path, +- * hnotify is disabled so we have no notify events to ignore. +- * when a user specified the xino, we cannot get au_hdir to be ignored. +- */ +- file = vfsub_filp_open(fname, O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE +- /* | __FMODE_NONOTIFY */, +- S_IRUGO | S_IWUGO); +- if (IS_ERR(file)) { +- if (!silent) +- pr_err("open %s(%ld)\n", fname, PTR_ERR(file)); +- return file; +- } +- +- /* keep file count */ +- h_parent = dget_parent(file->f_dentry); +- h_dir = h_parent->d_inode; +- mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT); +- /* mnt_want_write() is unnecessary here */ +- err = vfsub_unlink(h_dir, &file->f_path, /*force*/0); +- mutex_unlock(&h_dir->i_mutex); +- dput(h_parent); +- if (unlikely(err)) { +- if (!silent) +- pr_err("unlink %s(%d)\n", fname, err); +- goto out; +- } +- +- err = -EINVAL; +- d = file->f_dentry; +- if (unlikely(sb == d->d_sb)) { +- if (!silent) +- pr_err("%s must be outside\n", fname); +- goto out; +- } +- if (unlikely(au_test_fs_bad_xino(d->d_sb))) { +- if (!silent) +- pr_err("xino doesn't support %s(%s)\n", +- fname, au_sbtype(d->d_sb)); +- goto out; +- } +- return file; /* success */ +- +-out: +- fput(file); +- file = ERR_PTR(err); +- return file; +-} +- +-/* +- * find another branch who is on the same filesystem of the specified +- * branch{@btgt}. search until @bend. +- */ +-static int is_sb_shared(struct super_block *sb, aufs_bindex_t btgt, +- aufs_bindex_t bend) +-{ +- aufs_bindex_t bindex; +- struct super_block *tgt_sb = au_sbr_sb(sb, btgt); +- +- for (bindex = 0; bindex < btgt; bindex++) +- if (unlikely(tgt_sb == au_sbr_sb(sb, bindex))) +- return bindex; +- for (bindex++; bindex <= bend; bindex++) +- if (unlikely(tgt_sb == au_sbr_sb(sb, bindex))) +- return bindex; +- return -1; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* +- * initialize the xinofile for the specified branch @br +- * at the place/path where @base_file indicates. +- * test whether another branch is on the same filesystem or not, +- * if @do_test is true. +- */ +-int au_xino_br(struct super_block *sb, struct au_branch *br, ino_t h_ino, +- struct file *base_file, int do_test) +-{ +- int err; +- ino_t ino; +- aufs_bindex_t bend, bindex; +- struct au_branch *shared_br, *b; +- struct file *file; +- struct super_block *tgt_sb; +- +- shared_br = NULL; +- bend = au_sbend(sb); +- if (do_test) { +- tgt_sb = br->br_mnt->mnt_sb; +- for (bindex = 0; bindex <= bend; bindex++) { +- b = au_sbr(sb, bindex); +- if (tgt_sb == b->br_mnt->mnt_sb) { +- shared_br = b; +- break; +- } +- } +- } +- +- if (!shared_br || !shared_br->br_xino.xi_file) { +- struct au_xino_lock_dir ldir; +- +- au_xino_lock_dir(sb, base_file, &ldir); +- /* mnt_want_write() is unnecessary here */ +- file = au_xino_create2(base_file, NULL); +- au_xino_unlock_dir(&ldir); +- err = PTR_ERR(file); +- if (IS_ERR(file)) +- goto out; +- br->br_xino.xi_file = file; +- } else { +- br->br_xino.xi_file = shared_br->br_xino.xi_file; +- get_file(br->br_xino.xi_file); +- } +- +- ino = AUFS_ROOT_INO; +- err = au_xino_do_write(au_sbi(sb)->si_xwrite, br->br_xino.xi_file, +- h_ino, ino); +- if (unlikely(err)) { +- fput(br->br_xino.xi_file); +- br->br_xino.xi_file = NULL; +- } +- +-out: +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* trucate a xino bitmap file */ +- +-/* todo: slow */ +-static int do_xib_restore(struct super_block *sb, struct file *file, void *page) +-{ +- int err, bit; +- ssize_t sz; +- unsigned long pindex; +- loff_t pos, pend; +- struct au_sbinfo *sbinfo; +- au_readf_t func; +- ino_t *ino; +- unsigned long *p; +- +- err = 0; +- sbinfo = au_sbi(sb); +- MtxMustLock(&sbinfo->si_xib_mtx); +- p = sbinfo->si_xib_buf; +- func = sbinfo->si_xread; +- pend = i_size_read(file->f_dentry->d_inode); +- pos = 0; +- while (pos < pend) { +- sz = xino_fread(func, file, page, PAGE_SIZE, &pos); +- err = sz; +- if (unlikely(sz <= 0)) +- goto out; +- +- err = 0; +- for (ino = page; sz > 0; ino++, sz -= sizeof(ino)) { +- if (unlikely(*ino < AUFS_FIRST_INO)) +- continue; +- +- xib_calc_bit(*ino, &pindex, &bit); +- AuDebugOn(page_bits <= bit); +- err = xib_pindex(sb, pindex); +- if (!err) +- set_bit(bit, p); +- else +- goto out; +- } +- } +- +-out: +- return err; +-} +- +-static int xib_restore(struct super_block *sb) +-{ +- int err; +- aufs_bindex_t bindex, bend; +- void *page; +- +- err = -ENOMEM; +- page = (void *)__get_free_page(GFP_NOFS); +- if (unlikely(!page)) +- goto out; +- +- err = 0; +- bend = au_sbend(sb); +- for (bindex = 0; !err && bindex <= bend; bindex++) +- if (!bindex || is_sb_shared(sb, bindex, bindex - 1) < 0) +- err = do_xib_restore +- (sb, au_sbr(sb, bindex)->br_xino.xi_file, page); +- else +- AuDbg("b%d\n", bindex); +- free_page((unsigned long)page); +- +-out: +- return err; +-} +- +-int au_xib_trunc(struct super_block *sb) +-{ +- int err; +- ssize_t sz; +- loff_t pos; +- struct au_xino_lock_dir ldir; +- struct au_sbinfo *sbinfo; +- unsigned long *p; +- struct file *file; +- +- SiMustWriteLock(sb); +- +- err = 0; +- sbinfo = au_sbi(sb); +- if (!au_opt_test(sbinfo->si_mntflags, XINO)) +- goto out; +- +- file = sbinfo->si_xib; +- if (i_size_read(file->f_dentry->d_inode) <= PAGE_SIZE) +- goto out; +- +- au_xino_lock_dir(sb, file, &ldir); +- /* mnt_want_write() is unnecessary here */ +- file = au_xino_create2(sbinfo->si_xib, NULL); +- au_xino_unlock_dir(&ldir); +- err = PTR_ERR(file); +- if (IS_ERR(file)) +- goto out; +- fput(sbinfo->si_xib); +- sbinfo->si_xib = file; +- +- p = sbinfo->si_xib_buf; +- memset(p, 0, PAGE_SIZE); +- pos = 0; +- sz = xino_fwrite(sbinfo->si_xwrite, sbinfo->si_xib, p, PAGE_SIZE, &pos); +- if (unlikely(sz != PAGE_SIZE)) { +- err = sz; +- AuIOErr("err %d\n", err); +- if (sz >= 0) +- err = -EIO; +- goto out; +- } +- +- mutex_lock(&sbinfo->si_xib_mtx); +- /* mnt_want_write() is unnecessary here */ +- err = xib_restore(sb); +- mutex_unlock(&sbinfo->si_xib_mtx); +- +-out: +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* +- * xino mount option handlers +- */ +-static au_readf_t find_readf(struct file *h_file) +-{ +- const struct file_operations *fop = h_file->f_op; +- +- if (fop) { +- if (fop->read) +- return fop->read; +- if (fop->aio_read) +- return do_sync_read; +- } +- return ERR_PTR(-ENOSYS); +-} +- +-static au_writef_t find_writef(struct file *h_file) +-{ +- const struct file_operations *fop = h_file->f_op; +- +- if (fop) { +- if (fop->write) +- return fop->write; +- if (fop->aio_write) +- return do_sync_write; +- } +- return ERR_PTR(-ENOSYS); +-} +- +-/* xino bitmap */ +-static void xino_clear_xib(struct super_block *sb) +-{ +- struct au_sbinfo *sbinfo; +- +- SiMustWriteLock(sb); +- +- sbinfo = au_sbi(sb); +- sbinfo->si_xread = NULL; +- sbinfo->si_xwrite = NULL; +- if (sbinfo->si_xib) +- fput(sbinfo->si_xib); +- sbinfo->si_xib = NULL; +- free_page((unsigned long)sbinfo->si_xib_buf); +- sbinfo->si_xib_buf = NULL; +-} +- +-static int au_xino_set_xib(struct super_block *sb, struct file *base) +-{ +- int err; +- loff_t pos; +- struct au_sbinfo *sbinfo; +- struct file *file; +- +- SiMustWriteLock(sb); +- +- sbinfo = au_sbi(sb); +- file = au_xino_create2(base, sbinfo->si_xib); +- err = PTR_ERR(file); +- if (IS_ERR(file)) +- goto out; +- if (sbinfo->si_xib) +- fput(sbinfo->si_xib); +- sbinfo->si_xib = file; +- sbinfo->si_xread = find_readf(file); +- sbinfo->si_xwrite = find_writef(file); +- +- err = -ENOMEM; +- if (!sbinfo->si_xib_buf) +- sbinfo->si_xib_buf = (void *)get_zeroed_page(GFP_NOFS); +- if (unlikely(!sbinfo->si_xib_buf)) +- goto out_unset; +- +- sbinfo->si_xib_last_pindex = 0; +- sbinfo->si_xib_next_bit = 0; +- if (i_size_read(file->f_dentry->d_inode) < PAGE_SIZE) { +- pos = 0; +- err = xino_fwrite(sbinfo->si_xwrite, file, sbinfo->si_xib_buf, +- PAGE_SIZE, &pos); +- if (unlikely(err != PAGE_SIZE)) +- goto out_free; +- } +- err = 0; +- goto out; /* success */ +- +-out_free: +- free_page((unsigned long)sbinfo->si_xib_buf); +- sbinfo->si_xib_buf = NULL; +- if (err >= 0) +- err = -EIO; +-out_unset: +- fput(sbinfo->si_xib); +- sbinfo->si_xib = NULL; +- sbinfo->si_xread = NULL; +- sbinfo->si_xwrite = NULL; +-out: +- return err; +-} +- +-/* xino for each branch */ +-static void xino_clear_br(struct super_block *sb) +-{ +- aufs_bindex_t bindex, bend; +- struct au_branch *br; +- +- bend = au_sbend(sb); +- for (bindex = 0; bindex <= bend; bindex++) { +- br = au_sbr(sb, bindex); +- if (!br || !br->br_xino.xi_file) +- continue; +- +- fput(br->br_xino.xi_file); +- br->br_xino.xi_file = NULL; +- } +-} +- +-static int au_xino_set_br(struct super_block *sb, struct file *base) +-{ +- int err; +- ino_t ino; +- aufs_bindex_t bindex, bend, bshared; +- struct { +- struct file *old, *new; +- } *fpair, *p; +- struct au_branch *br; +- struct inode *inode; +- au_writef_t writef; +- +- SiMustWriteLock(sb); +- +- err = -ENOMEM; +- bend = au_sbend(sb); +- fpair = kcalloc(bend + 1, sizeof(*fpair), GFP_NOFS); +- if (unlikely(!fpair)) +- goto out; +- +- inode = sb->s_root->d_inode; +- ino = AUFS_ROOT_INO; +- writef = au_sbi(sb)->si_xwrite; +- for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++) { +- br = au_sbr(sb, bindex); +- bshared = is_sb_shared(sb, bindex, bindex - 1); +- if (bshared >= 0) { +- /* shared xino */ +- *p = fpair[bshared]; +- get_file(p->new); +- } +- +- if (!p->new) { +- /* new xino */ +- p->old = br->br_xino.xi_file; +- p->new = au_xino_create2(base, br->br_xino.xi_file); +- err = PTR_ERR(p->new); +- if (IS_ERR(p->new)) { +- p->new = NULL; +- goto out_pair; +- } +- } +- +- err = au_xino_do_write(writef, p->new, +- au_h_iptr(inode, bindex)->i_ino, ino); +- if (unlikely(err)) +- goto out_pair; +- } +- +- for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++) { +- br = au_sbr(sb, bindex); +- if (br->br_xino.xi_file) +- fput(br->br_xino.xi_file); +- get_file(p->new); +- br->br_xino.xi_file = p->new; +- } +- +-out_pair: +- for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++) +- if (p->new) +- fput(p->new); +- else +- break; +- kfree(fpair); +-out: +- return err; +-} +- +-void au_xino_clr(struct super_block *sb) +-{ +- struct au_sbinfo *sbinfo; +- +- au_xigen_clr(sb); +- xino_clear_xib(sb); +- xino_clear_br(sb); +- sbinfo = au_sbi(sb); +- /* lvalue, do not call au_mntflags() */ +- au_opt_clr(sbinfo->si_mntflags, XINO); +-} +- +-int au_xino_set(struct super_block *sb, struct au_opt_xino *xino, int remount) +-{ +- int err, skip; +- struct dentry *parent, *cur_parent; +- struct qstr *dname, *cur_name; +- struct file *cur_xino; +- struct inode *dir; +- struct au_sbinfo *sbinfo; +- +- SiMustWriteLock(sb); +- +- err = 0; +- sbinfo = au_sbi(sb); +- parent = dget_parent(xino->file->f_dentry); +- if (remount) { +- skip = 0; +- dname = &xino->file->f_dentry->d_name; +- cur_xino = sbinfo->si_xib; +- if (cur_xino) { +- cur_parent = dget_parent(cur_xino->f_dentry); +- cur_name = &cur_xino->f_dentry->d_name; +- skip = (cur_parent == parent +- && dname->len == cur_name->len +- && !memcmp(dname->name, cur_name->name, +- dname->len)); +- dput(cur_parent); +- } +- if (skip) +- goto out; +- } +- +- au_opt_set(sbinfo->si_mntflags, XINO); +- dir = parent->d_inode; +- mutex_lock_nested(&dir->i_mutex, AuLsc_I_PARENT); +- /* mnt_want_write() is unnecessary here */ +- err = au_xino_set_xib(sb, xino->file); +- if (!err) +- err = au_xigen_set(sb, xino->file); +- if (!err) +- err = au_xino_set_br(sb, xino->file); +- mutex_unlock(&dir->i_mutex); +- if (!err) +- goto out; /* success */ +- +- /* reset all */ +- AuIOErr("failed creating xino(%d).\n", err); +- +-out: +- dput(parent); +- return err; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-/* +- * create a xinofile at the default place/path. +- */ +-struct file *au_xino_def(struct super_block *sb) +-{ +- struct file *file; +- char *page, *p; +- struct au_branch *br; +- struct super_block *h_sb; +- struct path path; +- aufs_bindex_t bend, bindex, bwr; +- +- br = NULL; +- bend = au_sbend(sb); +- bwr = -1; +- for (bindex = 0; bindex <= bend; bindex++) { +- br = au_sbr(sb, bindex); +- if (au_br_writable(br->br_perm) +- && !au_test_fs_bad_xino(br->br_mnt->mnt_sb)) { +- bwr = bindex; +- break; +- } +- } +- +- if (bwr >= 0) { +- file = ERR_PTR(-ENOMEM); +- page = (void *)__get_free_page(GFP_NOFS); +- if (unlikely(!page)) +- goto out; +- path.mnt = br->br_mnt; +- path.dentry = au_h_dptr(sb->s_root, bwr); +- p = d_path(&path, page, PATH_MAX - sizeof(AUFS_XINO_FNAME)); +- file = (void *)p; +- if (!IS_ERR(p)) { +- strcat(p, "/" AUFS_XINO_FNAME); +- AuDbg("%s\n", p); +- file = au_xino_create(sb, p, /*silent*/0); +- if (!IS_ERR(file)) +- au_xino_brid_set(sb, br->br_id); +- } +- free_page((unsigned long)page); +- } else { +- file = au_xino_create(sb, AUFS_XINO_DEFPATH, /*silent*/0); +- if (IS_ERR(file)) +- goto out; +- h_sb = file->f_dentry->d_sb; +- if (unlikely(au_test_fs_bad_xino(h_sb))) { +- pr_err("xino doesn't support %s(%s)\n", +- AUFS_XINO_DEFPATH, au_sbtype(h_sb)); +- fput(file); +- file = ERR_PTR(-EINVAL); +- } +- if (!IS_ERR(file)) +- au_xino_brid_set(sb, -1); +- } +- +-out: +- return file; +-} +- +-/* ---------------------------------------------------------------------- */ +- +-int au_xino_path(struct seq_file *seq, struct file *file) +-{ +- int err; +- +- err = au_seq_path(seq, &file->f_path); +- if (unlikely(err < 0)) +- goto out; +- +- err = 0; +-#define Deleted "\\040(deleted)" +- seq->count -= sizeof(Deleted) - 1; +- AuDebugOn(memcmp(seq->buf + seq->count, Deleted, +- sizeof(Deleted) - 1)); +-#undef Deleted +- +-out: +- return err; +-} +diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c +index 13ddec9..01443ce 100644 +--- a/fs/autofs4/expire.c ++++ b/fs/autofs4/expire.c +@@ -61,6 +61,15 @@ static int autofs4_mount_busy(struct vfsmount *mnt, struct dentry *dentry) + /* This is an autofs submount, we can't expire it */ + if (autofs_type_indirect(sbi->type)) + goto done; ++ ++ /* ++ * Otherwise it's an offset mount and we need to check ++ * if we can umount its mount, if there is one. ++ */ ++ if (!d_mountpoint(path.dentry)) { ++ status = 0; ++ goto done; ++ } + } + + /* Update the expiry counter if fs is busy */ +diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c +index 105b265..ae94117 100644 +--- a/fs/btrfs/delayed-ref.c ++++ b/fs/btrfs/delayed-ref.c +@@ -36,19 +36,16 @@ + * compare two delayed tree backrefs with same bytenr and type + */ + static int comp_tree_refs(struct btrfs_delayed_tree_ref *ref2, +- struct btrfs_delayed_tree_ref *ref1, int type) ++ struct btrfs_delayed_tree_ref *ref1) + { +- if (type == BTRFS_TREE_BLOCK_REF_KEY) { +- if (ref1->root < ref2->root) +- return -1; +- if (ref1->root > ref2->root) +- return 1; +- } else { +- if (ref1->parent < ref2->parent) +- return -1; +- if (ref1->parent > ref2->parent) +- return 1; +- } ++ if (ref1->root < ref2->root) ++ return -1; ++ if (ref1->root > ref2->root) ++ return 1; ++ if (ref1->parent < ref2->parent) ++ return -1; ++ if (ref1->parent > ref2->parent) ++ return 1; + return 0; + } + +@@ -112,8 +109,7 @@ static int comp_entry(struct btrfs_delayed_ref_node *ref2, + if (ref1->type == BTRFS_TREE_BLOCK_REF_KEY || + ref1->type == BTRFS_SHARED_BLOCK_REF_KEY) { + return comp_tree_refs(btrfs_delayed_node_to_tree_ref(ref2), +- btrfs_delayed_node_to_tree_ref(ref1), +- ref1->type); ++ btrfs_delayed_node_to_tree_ref(ref1)); + } else if (ref1->type == BTRFS_EXTENT_DATA_REF_KEY || + ref1->type == BTRFS_SHARED_DATA_REF_KEY) { + return comp_data_refs(btrfs_delayed_node_to_data_ref(ref2), +diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c +index 4b5398c..7c4e6cc 100644 +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -5794,9 +5794,7 @@ out: + * block must be cow'd + */ + static noinline int can_nocow_odirect(struct btrfs_trans_handle *trans, +- struct inode *inode, u64 offset, u64 *len, +- u64 *orig_start, u64 *orig_block_len, +- u64 *ram_bytes) ++ struct inode *inode, u64 offset, u64 len) + { + struct btrfs_path *path; + int ret; +@@ -5853,12 +5851,8 @@ static noinline int can_nocow_odirect(struct btrfs_trans_handle *trans, + disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); + backref_offset = btrfs_file_extent_offset(leaf, fi); + +- *orig_start = key.offset - backref_offset; +- *orig_block_len = btrfs_file_extent_disk_num_bytes(leaf, fi); +- *ram_bytes = btrfs_file_extent_ram_bytes(leaf, fi); +- + extent_end = key.offset + btrfs_file_extent_num_bytes(leaf, fi); +- if (extent_end < offset + *len) { ++ if (extent_end < offset + len) { + /* extent doesn't include our full range, must cow */ + goto out; + } +@@ -5882,14 +5876,13 @@ static noinline int can_nocow_odirect(struct btrfs_trans_handle *trans, + */ + disk_bytenr += backref_offset; + disk_bytenr += offset - key.offset; +- num_bytes = min(offset + *len, extent_end) - offset; ++ num_bytes = min(offset + len, extent_end) - offset; + if (csum_exist_in_range(root, disk_bytenr, num_bytes)) + goto out; + /* + * all of the above have passed, it is safe to overwrite this extent + * without cow + */ +- *len = num_bytes; + ret = 1; + out: + btrfs_free_path(path); +@@ -6099,7 +6092,7 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, + em->block_start != EXTENT_MAP_HOLE)) { + int type; + int ret; +- u64 block_start, orig_start, orig_block_len, ram_bytes; ++ u64 block_start; + + if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) + type = BTRFS_ORDERED_PREALLOC; +@@ -6117,8 +6110,10 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, + if (IS_ERR(trans)) + goto must_cow; + +- if (can_nocow_odirect(trans, inode, start, &len, &orig_start, +- &orig_block_len, &ram_bytes) == 1) { ++ if (can_nocow_odirect(trans, inode, start, len) == 1) { ++ u64 orig_start = em->orig_start; ++ u64 orig_block_len = em->orig_block_len; ++ + if (type == BTRFS_ORDERED_PREALLOC) { + free_extent_map(em); + em = create_pinned_em(inode, start, len, +diff --git a/fs/buffer.c b/fs/buffer.c +index b9c3f3c..7a75c3e 100644 +--- a/fs/buffer.c ++++ b/fs/buffer.c +@@ -2380,8 +2380,6 @@ int block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, + * fault so this update may be superfluous but who really cares... + */ + file_update_time(vma->vm_file); +- if (vma->vm_prfile) +- file_update_time(vma->vm_prfile); + + ret = __block_page_mkwrite(vma, vmf, get_block); + sb_end_pagefault(sb); +diff --git a/fs/dcache.c b/fs/dcache.c +index de73da2..c3bbf85 100644 +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -1232,10 +1232,8 @@ void shrink_dcache_parent(struct dentry * parent) + LIST_HEAD(dispose); + int found; + +- while ((found = select_parent(parent, &dispose)) != 0) { ++ while ((found = select_parent(parent, &dispose)) != 0) + shrink_dentry_list(&dispose); +- cond_resched(); +- } + } + EXPORT_SYMBOL(shrink_dcache_parent); + +diff --git a/fs/exec.c b/fs/exec.c +index ac014f1..20df02c 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -613,7 +613,7 @@ static int shift_arg_pages(struct vm_area_struct *vma, unsigned long shift) + * when the old and new regions overlap clear from new_end. + */ + free_pgd_range(&tlb, new_end, old_end, new_end, +- vma->vm_next ? vma->vm_next->vm_start : USER_PGTABLES_CEILING); ++ vma->vm_next ? vma->vm_next->vm_start : 0); + } else { + /* + * otherwise, clean from old_start; this is done to not touch +@@ -622,7 +622,7 @@ static int shift_arg_pages(struct vm_area_struct *vma, unsigned long shift) + * for the others its just a little faster. + */ + free_pgd_range(&tlb, old_start, old_end, new_end, +- vma->vm_next ? vma->vm_next->vm_start : USER_PGTABLES_CEILING); ++ vma->vm_next ? vma->vm_next->vm_start : 0); + } + tlb_finish_mmu(&tlb, new_end, old_end); + +@@ -898,13 +898,11 @@ static int de_thread(struct task_struct *tsk) + + sig->notify_count = -1; /* for exit_notify() */ + for (;;) { +- threadgroup_change_begin(tsk); + write_lock_irq(&tasklist_lock); + if (likely(leader->exit_state)) + break; + __set_current_state(TASK_KILLABLE); + write_unlock_irq(&tasklist_lock); +- threadgroup_change_end(tsk); + schedule(); + if (unlikely(__fatal_signal_pending(tsk))) + goto killed; +@@ -962,7 +960,6 @@ static int de_thread(struct task_struct *tsk) + if (unlikely(leader->ptrace)) + __wake_up_parent(leader, leader->parent); + write_unlock_irq(&tasklist_lock); +- threadgroup_change_end(tsk); + + release_task(leader); + } +diff --git a/fs/ext4/Kconfig b/fs/ext4/Kconfig +index efea5d5..9873587 100644 +--- a/fs/ext4/Kconfig ++++ b/fs/ext4/Kconfig +@@ -71,5 +71,4 @@ config EXT4_DEBUG + Enables run-time debugging support for the ext4 filesystem. + + If you select Y here, then you will be able to turn on debugging +- with a command such as: +- echo 1 > /sys/module/ext4/parameters/mballoc_debug ++ with a command such as "echo 1 > /sys/kernel/debug/ext4/mballoc-debug" +diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h +index dbd9ae1..7177f9b 100644 +--- a/fs/ext4/ext4_jbd2.h ++++ b/fs/ext4/ext4_jbd2.h +@@ -170,20 +170,16 @@ static inline void ext4_journal_callback_add(handle_t *handle, + * ext4_journal_callback_del: delete a registered callback + * @handle: active journal transaction handle on which callback was registered + * @jce: registered journal callback entry to unregister +- * Return true if object was sucessfully removed + */ +-static inline bool ext4_journal_callback_try_del(handle_t *handle, ++static inline void ext4_journal_callback_del(handle_t *handle, + struct ext4_journal_cb_entry *jce) + { +- bool deleted; + struct ext4_sb_info *sbi = + EXT4_SB(handle->h_transaction->t_journal->j_private); + + spin_lock(&sbi->s_md_lock); +- deleted = !list_empty(&jce->jce_list); + list_del_init(&jce->jce_list); + spin_unlock(&sbi->s_md_lock); +- return deleted; + } + + int +diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c +index e0ba8a4..3278e64 100644 +--- a/fs/ext4/fsync.c ++++ b/fs/ext4/fsync.c +@@ -166,7 +166,8 @@ int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync) + if (journal->j_flags & JBD2_BARRIER && + !jbd2_trans_will_send_data_barrier(journal, commit_tid)) + needs_barrier = true; +- ret = jbd2_complete_transaction(journal, commit_tid); ++ jbd2_log_start_commit(journal, commit_tid); ++ ret = jbd2_log_wait_commit(journal, commit_tid); + if (needs_barrier) { + err = blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); + if (!ret) +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index c0fbd96..22c5c67 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -55,21 +55,21 @@ static __u32 ext4_inode_csum(struct inode *inode, struct ext4_inode *raw, + __u16 csum_hi = 0; + __u32 csum; + +- csum_lo = le16_to_cpu(raw->i_checksum_lo); ++ csum_lo = raw->i_checksum_lo; + raw->i_checksum_lo = 0; + if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE && + EXT4_FITS_IN_INODE(raw, ei, i_checksum_hi)) { +- csum_hi = le16_to_cpu(raw->i_checksum_hi); ++ csum_hi = raw->i_checksum_hi; + raw->i_checksum_hi = 0; + } + + csum = ext4_chksum(sbi, ei->i_csum_seed, (__u8 *)raw, + EXT4_INODE_SIZE(inode->i_sb)); + +- raw->i_checksum_lo = cpu_to_le16(csum_lo); ++ raw->i_checksum_lo = csum_lo; + if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE && + EXT4_FITS_IN_INODE(raw, ei, i_checksum_hi)) +- raw->i_checksum_hi = cpu_to_le16(csum_hi); ++ raw->i_checksum_hi = csum_hi; + + return csum; + } +@@ -216,7 +216,8 @@ void ext4_evict_inode(struct inode *inode) + journal_t *journal = EXT4_SB(inode->i_sb)->s_journal; + tid_t commit_tid = EXT4_I(inode)->i_datasync_tid; + +- jbd2_complete_transaction(journal, commit_tid); ++ jbd2_log_start_commit(journal, commit_tid); ++ jbd2_log_wait_commit(journal, commit_tid); + filemap_write_and_wait(&inode->i_data); + } + truncate_inode_pages(&inode->i_data, 0); +diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c +index b443e62..82f8c2d 100644 +--- a/fs/ext4/mballoc.c ++++ b/fs/ext4/mballoc.c +@@ -4449,11 +4449,11 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b, + node = rb_prev(new_node); + if (node) { + entry = rb_entry(node, struct ext4_free_data, efd_node); +- if (can_merge(entry, new_entry) && +- ext4_journal_callback_try_del(handle, &entry->efd_jce)) { ++ if (can_merge(entry, new_entry)) { + new_entry->efd_start_cluster = entry->efd_start_cluster; + new_entry->efd_count += entry->efd_count; + rb_erase(node, &(db->bb_free_root)); ++ ext4_journal_callback_del(handle, &entry->efd_jce); + kmem_cache_free(ext4_free_data_cachep, entry); + } + } +@@ -4461,10 +4461,10 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b, + node = rb_next(new_node); + if (node) { + entry = rb_entry(node, struct ext4_free_data, efd_node); +- if (can_merge(new_entry, entry) && +- ext4_journal_callback_try_del(handle, &entry->efd_jce)) { ++ if (can_merge(new_entry, entry)) { + new_entry->efd_count += entry->efd_count; + rb_erase(node, &(db->bb_free_root)); ++ ext4_journal_callback_del(handle, &entry->efd_jce); + kmem_cache_free(ext4_free_data_cachep, entry); + } + } +diff --git a/fs/ext4/mmp.c b/fs/ext4/mmp.c +index fe201c6..44734f1 100644 +--- a/fs/ext4/mmp.c ++++ b/fs/ext4/mmp.c +@@ -7,7 +7,7 @@ + #include "ext4.h" + + /* Checksumming functions */ +-static __le32 ext4_mmp_csum(struct super_block *sb, struct mmp_struct *mmp) ++static __u32 ext4_mmp_csum(struct super_block *sb, struct mmp_struct *mmp) + { + struct ext4_sb_info *sbi = EXT4_SB(sb); + int offset = offsetof(struct mmp_struct, mmp_checksum); +diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c +index 0cfa2f4..9eace36 100644 +--- a/fs/ext4/resize.c ++++ b/fs/ext4/resize.c +@@ -1341,8 +1341,6 @@ static void ext4_update_super(struct super_block *sb, + + /* Update the global fs size fields */ + sbi->s_groups_count += flex_gd->count; +- sbi->s_blockfile_groups = min_t(ext4_group_t, sbi->s_groups_count, +- (EXT4_MAX_BLOCK_FILE_PHYS / EXT4_BLOCKS_PER_GROUP(sb))); + + /* Update the reserved block counts only once the new group is + * active. */ +@@ -1880,10 +1878,6 @@ retry: + return 0; + + ext4_get_group_no_and_offset(sb, n_blocks_count - 1, &n_group, &offset); +- if (n_group > (0xFFFFFFFFUL / EXT4_INODES_PER_GROUP(sb))) { +- ext4_warning(sb, "resize would cause inodes_count overflow"); +- return -EINVAL; +- } + ext4_get_group_no_and_offset(sb, o_blocks_count - 1, &o_group, &offset); + + n_desc_blocks = num_desc_blocks(sb, n_group + 1); +diff --git a/fs/ext4/super.c b/fs/ext4/super.c +index 5575a45..24c767d 100644 +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -452,13 +452,10 @@ static void ext4_journal_commit_callback(journal_t *journal, transaction_t *txn) + struct super_block *sb = journal->j_private; + struct ext4_sb_info *sbi = EXT4_SB(sb); + int error = is_journal_aborted(journal); +- struct ext4_journal_cb_entry *jce; ++ struct ext4_journal_cb_entry *jce, *tmp; + +- BUG_ON(txn->t_state == T_FINISHED); + spin_lock(&sbi->s_md_lock); +- while (!list_empty(&txn->t_private_list)) { +- jce = list_entry(txn->t_private_list.next, +- struct ext4_journal_cb_entry, jce_list); ++ list_for_each_entry_safe(jce, tmp, &txn->t_private_list, jce_list) { + list_del_init(&jce->jce_list); + spin_unlock(&sbi->s_md_lock); + jce->jce_func(sb, jce, error); +diff --git a/fs/fat/Kconfig b/fs/fat/Kconfig +index 6bd12c0..182f9ff 100644 +--- a/fs/fat/Kconfig ++++ b/fs/fat/Kconfig +@@ -74,27 +74,6 @@ config VFAT_FS + To compile this as a module, choose M here: the module will be called + vfat. + +-config VFAT_FS_NO_DUALNAMES +- bool "disable VFAT dual names support (patent workaround)" +- depends on VFAT_FS +- help +- This option disables support for dual filenames on VFAT filesystems. +- If this option is enabled then file creation will either put +- a short (8.3) name or a long name on the file, but never both. +- The field where a shortname would normally go is filled with +- invalid characters such that it cannot be considered a valid +- short filename. +- +- That means that long filenames created with this option +- disabled will not be accessible at all to operating systems +- that do not understand the FAT long filename extensions. +- +- Users considering disabling this option should consider the +- implications of any patents that may exist on dual filenames +- in VFAT. +- +- If unsure, say N +- + config FAT_DEFAULT_CODEPAGE + int "Default codepage for FAT" + depends on MSDOS_FS || VFAT_FS +@@ -119,14 +98,3 @@ config FAT_DEFAULT_IOCHARSET + + Enable any character sets you need in File Systems/Native Language + Support. +- +-config VFAT_NO_CREATE_WITH_LONGNAMES +- bool "Disable creating files with long names" +- depends on VFAT_FS +- default n +- help +- Set this to disable support for creating files or directories with +- names longer than 8.3 (the original DOS maximum file name length) +- e.g. naming a file FILE1234.TXT would be allowed but creating or +- renaming a file to FILE12345.TXT or FILE1234.TEXT would not +- be permitted. Reading files with long file names is still permitted. +diff --git a/fs/fat/dir.c b/fs/fat/dir.c +index 83bb0b4..58bf744 100644 +--- a/fs/fat/dir.c ++++ b/fs/fat/dir.c +@@ -372,8 +372,7 @@ static int fat_parse_short(struct super_block *sb, + dotoffset = 1; + } + +- memcpy(work, de->name, sizeof(de->name)); +- ++ memcpy(work, de->name, sizeof(work)); + /* see namei.c, msdos_format_name */ + if (work[0] == 0x05) + work[0] = 0xE5; +@@ -503,13 +502,6 @@ parse_record: + goto end_of_dir; + } + +- /* +- * The FAT_NO_83NAME flag is used to mark files +- * created with no 8.3 short name +- */ +- if (de->lcase & FAT_NO_83NAME) +- goto compare_longname; +- + /* Never prepend '.' to hidden files here. + * That is done only for msdos mounts (and only when + * 'dotsOK=yes'); if we are executing here, it is in the +@@ -523,7 +515,6 @@ parse_record: + if (fat_name_match(sbi, name, name_len, bufname, len)) + goto found; + +-compare_longname: + if (nr_slots) { + void *longname = unicode + FAT_MAX_UNI_CHARS; + int size = PATH_MAX - FAT_MAX_UNI_SIZE; +@@ -620,8 +611,6 @@ parse_record: + if (de->attr != ATTR_EXT && IS_FREE(de->name)) + goto record_end; + } else { +- if (de->lcase & FAT_NO_83NAME) +- goto record_end; + if ((de->attr & ATTR_VOLUME) || IS_FREE(de->name)) + goto record_end; + } +@@ -964,10 +953,6 @@ int fat_scan(struct inode *dir, const unsigned char *name, + sinfo->bh = NULL; + while (fat_get_short_entry(dir, &sinfo->slot_off, &sinfo->bh, + &sinfo->de) >= 0) { +- /* skip files marked as having no 8.3 short name */ +- if (sinfo->de->lcase & FAT_NO_83NAME) +- continue; +- + if (!strncmp(sinfo->de->name, name, MSDOS_NAME)) { + sinfo->slot_off -= sizeof(*sinfo->de); + sinfo->nr_slots = 1; +diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c +index 2715672..ac959d6 100644 +--- a/fs/fat/namei_vfat.c ++++ b/fs/fat/namei_vfat.c +@@ -21,7 +21,6 @@ + #include + #include + #include +-#include + #include "fat.h" + + /* +@@ -329,17 +328,6 @@ static int vfat_create_shortname(struct inode *dir, struct nls_table *nls, + int sz = 0, extlen, baselen, i, numtail_baselen, numtail2_baselen; + int is_shortname; + struct shortname_info base_info, ext_info; +- unsigned opts_shortname = opts->shortname; +- +-#ifdef CONFIG_VFAT_FS_NO_DUALNAMES +- /* +- * When we do not have dualnames, we want to maximise the +- * chance that a file will be able to be represented with just +- * a 8.3 entry. We can do that by using the WINNT case +- * handling extensions to FAT. +- */ +- opts_shortname = VFAT_SFN_CREATE_WINNT; +-#endif + + is_shortname = 1; + INIT_SHORTNAME_INFO(&base_info); +@@ -448,22 +436,13 @@ static int vfat_create_shortname(struct inode *dir, struct nls_table *nls, + memcpy(name_res, base, baselen); + memcpy(name_res + 8, ext, extlen); + *lcase = 0; +- +-#ifdef CONFIG_VFAT_NO_CREATE_WITH_LONGNAMES +- if (is_shortname == 0) +- return -ENAMETOOLONG; +- if (!base_info.valid || !ext_info.valid) +- return -EINVAL; +- opts_shortname = VFAT_SFN_CREATE_WINNT; +-#endif +- + if (is_shortname && base_info.valid && ext_info.valid) { + if (vfat_find_form(dir, name_res) == 0) + return -EEXIST; + +- if (opts_shortname & VFAT_SFN_CREATE_WIN95) { ++ if (opts->shortname & VFAT_SFN_CREATE_WIN95) { + return (base_info.upper && ext_info.upper); +- } else if (opts_shortname & VFAT_SFN_CREATE_WINNT) { ++ } else if (opts->shortname & VFAT_SFN_CREATE_WINNT) { + if ((base_info.upper || base_info.lower) && + (ext_info.upper || ext_info.lower)) { + if (!base_info.upper && base_info.lower) +@@ -602,66 +581,6 @@ xlate_to_uni(const unsigned char *name, int len, unsigned char *outname, + return 0; + } + +-#ifdef CONFIG_VFAT_FS_NO_DUALNAMES +-/* +- * This function creates a dummy 8.3 entry which is as compatible as +- * possible with existing FAT devices, while not being a valid +- * filename under windows or Linux +- */ +-static void vfat_build_dummy_83_buffer(struct inode *dir, char *msdos_name, +- int is_dir) +-{ +- /* +- * These characters are all invalid in 8.3 names, plus have +- * been shown to be harmless on all tested devices +- */ +- const char invalidchar[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x0B, +- 0x0C, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, +- 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, +- 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x22, 0x2a, +- 0x3a, 0x3c, 0x3e, 0x3f, 0x5b, 0x5d, 0x7c }; +- int i, tilde_pos, slash_pos; +- u32 rand_num = random32(); +- +- /* We need a '~' in the prefix to make Win98 happy. */ +- tilde_pos = rand_num % 8; +- rand_num >>= 3; +- +- /* +- * the '/' makes sure that even unpatched Linux systems can't +- * get at files by the 8.3 entry. Don't put in a / in +- * directories as it can cause problems with some +- * photo frames +- */ +- if (is_dir) +- slash_pos = -1; +- else { +- slash_pos = (tilde_pos + 1 + rand_num % 7) % 8; +- rand_num >>= 3; +- } +- +- /* +- * fill in the first 8 bytes with invalid characters. Note +- * that we need to be careful not to run out of randomness. We +- * leave the 3 byte extension in place as some cheap MP3 +- * players need them. +- */ +- for (i = 0; i < 8; i++) { +- if (i == tilde_pos) +- msdos_name[i] = '~'; +- else if (i == slash_pos) +- msdos_name[i] = '/'; +- else { +- msdos_name[i] = +- invalidchar[rand_num % sizeof(invalidchar)]; +- rand_num /= sizeof(invalidchar); +- if (rand_num < sizeof(invalidchar)) +- rand_num = random32(); +- } +- } +-} +-#endif +- + static int vfat_build_slots(struct inode *dir, const unsigned char *name, + int len, int is_dir, int cluster, + struct timespec *ts, +@@ -669,19 +588,15 @@ static int vfat_build_slots(struct inode *dir, const unsigned char *name, + { + struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb); + struct fat_mount_options *opts = &sbi->options; ++ struct msdos_dir_slot *ps; + struct msdos_dir_entry *de; +- unsigned char lcase; ++ unsigned char cksum, lcase; + unsigned char msdos_name[MSDOS_NAME]; + wchar_t *uname; + __le16 time, date; + u8 time_cs; +- int err, ulen, usize; +-#ifndef CONFIG_VFAT_NO_CREATE_WITH_LONGNAMES +- int i; +- struct msdos_dir_slot *ps; +- unsigned char cksum; ++ int err, ulen, usize, i; + loff_t offset; +-#endif + + *nr_slots = 0; + +@@ -708,16 +623,6 @@ static int vfat_build_slots(struct inode *dir, const unsigned char *name, + goto shortname; + } + +-#ifdef CONFIG_VFAT_FS_NO_DUALNAMES +- printk_once(KERN_INFO +- "VFAT: not creating 8.3 short filenames for long names\n"); +- vfat_build_dummy_83_buffer(dir, msdos_name, is_dir); +- lcase = FAT_NO_83NAME; +-#endif +- +-#ifdef CONFIG_VFAT_NO_CREATE_WITH_LONGNAMES +- de = (struct msdos_dir_entry *)slots; +-#else + /* build the entry of long file name */ + cksum = fat_checksum(msdos_name); + +@@ -735,7 +640,6 @@ static int vfat_build_slots(struct inode *dir, const unsigned char *name, + } + slots[0].id |= 0x40; + de = (struct msdos_dir_entry *)ps; +-#endif + + shortname: + /* build the entry of 8.3 alias name */ +@@ -1164,11 +1068,7 @@ static struct dentry *vfat_mount(struct file_system_type *fs_type, + + static struct file_system_type vfat_fs_type = { + .owner = THIS_MODULE, +-#ifdef CONFIG_VFAT_NO_CREATE_WITH_LONGNAMES +- .name = "lfat", +-#else + .name = "vfat", +-#endif + .mount = vfat_mount, + .kill_sb = kill_block_super, + .fs_flags = FS_REQUIRES_DEV, +@@ -1187,9 +1087,6 @@ static void __exit exit_vfat_fs(void) + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("VFAT filesystem support"); + MODULE_AUTHOR("Gordon Chaffee"); +-#ifdef CONFIG_VFAT_NO_CREATE_WITH_LONGNAMES +-MODULE_ALIAS("lfat"); +-#endif + + module_init(init_vfat_fs) + module_exit(exit_vfat_fs) +diff --git a/fs/file_table.c b/fs/file_table.c +index b33aebe..de9e965 100644 +--- a/fs/file_table.c ++++ b/fs/file_table.c +@@ -36,8 +36,7 @@ struct files_stat_struct files_stat = { + .max_files = NR_FILE + }; + +-DEFINE_LGLOCK(files_lglock); +-EXPORT_SYMBOL(files_lglock); ++DEFINE_STATIC_LGLOCK(files_lglock); + + /* SLAB cache for file structures */ + static struct kmem_cache *filp_cachep __read_mostly; +@@ -404,8 +403,6 @@ void file_sb_list_del(struct file *file) + } + } + +-EXPORT_SYMBOL(file_sb_list_del); +- + #ifdef CONFIG_SMP + + /* +diff --git a/fs/fscache/stats.c b/fs/fscache/stats.c +index 40d13c7..8179e8b 100644 +--- a/fs/fscache/stats.c ++++ b/fs/fscache/stats.c +@@ -287,5 +287,5 @@ const struct file_operations fscache_stats_fops = { + .open = fscache_stats_open, + .read = seq_read, + .llseek = seq_lseek, +- .release = single_release, ++ .release = seq_release, + }; +diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c +index d0de769..ccee8cc 100644 +--- a/fs/hugetlbfs/inode.c ++++ b/fs/hugetlbfs/inode.c +@@ -908,19 +908,19 @@ static int can_do_hugetlb_shm(void) + + static int get_hstate_idx(int page_size_log) + { +- struct hstate *h = hstate_sizelog(page_size_log); ++ struct hstate *h; + ++ if (!page_size_log) ++ return default_hstate_idx; ++ h = size_to_hstate(1 << page_size_log); + if (!h) + return -1; + return h - hstates; + } + +-/* +- * Note that size should be aligned to proper hugepage size in caller side, +- * otherwise hugetlb_reserve_pages reserves one less hugepages than intended. +- */ +-struct file *hugetlb_file_setup(const char *name, size_t size, +- vm_flags_t acctflag, struct user_struct **user, ++struct file *hugetlb_file_setup(const char *name, unsigned long addr, ++ size_t size, vm_flags_t acctflag, ++ struct user_struct **user, + int creat_flags, int page_size_log) + { + int error = -ENOMEM; +@@ -929,6 +929,8 @@ struct file *hugetlb_file_setup(const char *name, size_t size, + struct path path; + struct dentry *root; + struct qstr quick_string; ++ struct hstate *hstate; ++ unsigned long num_pages; + int hstate_idx; + + hstate_idx = get_hstate_idx(page_size_log); +@@ -967,10 +969,12 @@ struct file *hugetlb_file_setup(const char *name, size_t size, + if (!inode) + goto out_dentry; + ++ hstate = hstate_inode(inode); ++ size += addr & ~huge_page_mask(hstate); ++ num_pages = ALIGN(size, huge_page_size(hstate)) >> ++ huge_page_shift(hstate); + error = -ENOMEM; +- if (hugetlb_reserve_pages(inode, 0, +- size >> huge_page_shift(hstate_inode(inode)), NULL, +- acctflag)) ++ if (hugetlb_reserve_pages(inode, 0, num_pages, NULL, acctflag)) + goto out_inode; + + d_instantiate(path.dentry, inode); +diff --git a/fs/inode.c b/fs/inode.c +index 52bc42c..b98540e 100644 +--- a/fs/inode.c ++++ b/fs/inode.c +@@ -56,7 +56,6 @@ static struct hlist_head *inode_hashtable __read_mostly; + static __cacheline_aligned_in_smp DEFINE_SPINLOCK(inode_hash_lock); + + __cacheline_aligned_in_smp DEFINE_SPINLOCK(inode_sb_list_lock); +-EXPORT_SYMBOL(inode_sb_list_lock); + + /* + * Empty aops. Can be used for the cases where the user does not +@@ -1504,7 +1503,7 @@ static int relatime_need_update(struct vfsmount *mnt, struct inode *inode, + * This does the actual work of updating an inodes time or version. Must have + * had called mnt_want_write() before calling this. + */ +-int update_time(struct inode *inode, struct timespec *time, int flags) ++static int update_time(struct inode *inode, struct timespec *time, int flags) + { + if (inode->i_op->update_time) + return inode->i_op->update_time(inode, time, flags); +@@ -1520,7 +1519,6 @@ int update_time(struct inode *inode, struct timespec *time, int flags) + mark_inode_dirty_sync(inode); + return 0; + } +-EXPORT_SYMBOL(update_time); + + /** + * touch_atime - update the access time +diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c +index 069bf58..3091d42 100644 +--- a/fs/jbd2/commit.c ++++ b/fs/jbd2/commit.c +@@ -382,7 +382,7 @@ void jbd2_journal_commit_transaction(journal_t *journal) + int space_left = 0; + int first_tag = 0; + int tag_flag; +- int i; ++ int i, to_free = 0; + int tag_bytes = journal_tag_bytes(journal); + struct buffer_head *cbh = NULL; /* For transactional checksums */ + __u32 crc32_sum = ~0; +@@ -1126,7 +1126,7 @@ restart_loop: + journal->j_stats.run.rs_blocks_logged += stats.run.rs_blocks_logged; + spin_unlock(&journal->j_history_lock); + +- commit_transaction->t_state = T_COMMIT_CALLBACK; ++ commit_transaction->t_state = T_FINISHED; + J_ASSERT(commit_transaction == journal->j_committing_transaction); + journal->j_commit_sequence = commit_transaction->t_tid; + journal->j_committing_transaction = NULL; +@@ -1141,44 +1141,38 @@ restart_loop: + journal->j_average_commit_time*3) / 4; + else + journal->j_average_commit_time = commit_time; +- + write_unlock(&journal->j_state_lock); + +- if (journal->j_checkpoint_transactions == NULL) { +- journal->j_checkpoint_transactions = commit_transaction; +- commit_transaction->t_cpnext = commit_transaction; +- commit_transaction->t_cpprev = commit_transaction; ++ if (commit_transaction->t_checkpoint_list == NULL && ++ commit_transaction->t_checkpoint_io_list == NULL) { ++ __jbd2_journal_drop_transaction(journal, commit_transaction); ++ to_free = 1; + } else { +- commit_transaction->t_cpnext = +- journal->j_checkpoint_transactions; +- commit_transaction->t_cpprev = +- commit_transaction->t_cpnext->t_cpprev; +- commit_transaction->t_cpnext->t_cpprev = +- commit_transaction; +- commit_transaction->t_cpprev->t_cpnext = ++ if (journal->j_checkpoint_transactions == NULL) { ++ journal->j_checkpoint_transactions = commit_transaction; ++ commit_transaction->t_cpnext = commit_transaction; ++ commit_transaction->t_cpprev = commit_transaction; ++ } else { ++ commit_transaction->t_cpnext = ++ journal->j_checkpoint_transactions; ++ commit_transaction->t_cpprev = ++ commit_transaction->t_cpnext->t_cpprev; ++ commit_transaction->t_cpnext->t_cpprev = ++ commit_transaction; ++ commit_transaction->t_cpprev->t_cpnext = + commit_transaction; ++ } + } + spin_unlock(&journal->j_list_lock); +- /* Drop all spin_locks because commit_callback may be block. +- * __journal_remove_checkpoint() can not destroy transaction +- * under us because it is not marked as T_FINISHED yet */ ++ + if (journal->j_commit_callback) + journal->j_commit_callback(journal, commit_transaction); + + trace_jbd2_end_commit(journal, commit_transaction); + jbd_debug(1, "JBD2: commit %d complete, head %d\n", + journal->j_commit_sequence, journal->j_tail_sequence); +- +- write_lock(&journal->j_state_lock); +- spin_lock(&journal->j_list_lock); +- commit_transaction->t_state = T_FINISHED; +- /* Recheck checkpoint lists after j_list_lock was dropped */ +- if (commit_transaction->t_checkpoint_list == NULL && +- commit_transaction->t_checkpoint_io_list == NULL) { +- __jbd2_journal_drop_transaction(journal, commit_transaction); ++ if (to_free) + jbd2_journal_free_transaction(commit_transaction); +- } +- spin_unlock(&journal->j_list_lock); +- write_unlock(&journal->j_state_lock); ++ + wake_up(&journal->j_wait_done_commit); + } +diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c +index 42f8cf6c..dbf41f9 100644 +--- a/fs/jbd2/journal.c ++++ b/fs/jbd2/journal.c +@@ -698,37 +698,6 @@ int jbd2_log_wait_commit(journal_t *journal, tid_t tid) + } + + /* +- * When this function returns the transaction corresponding to tid +- * will be completed. If the transaction has currently running, start +- * committing that transaction before waiting for it to complete. If +- * the transaction id is stale, it is by definition already completed, +- * so just return SUCCESS. +- */ +-int jbd2_complete_transaction(journal_t *journal, tid_t tid) +-{ +- int need_to_wait = 1; +- +- read_lock(&journal->j_state_lock); +- if (journal->j_running_transaction && +- journal->j_running_transaction->t_tid == tid) { +- if (journal->j_commit_request != tid) { +- /* transaction not yet started, so request it */ +- read_unlock(&journal->j_state_lock); +- jbd2_log_start_commit(journal, tid); +- goto wait_commit; +- } +- } else if (!(journal->j_committing_transaction && +- journal->j_committing_transaction->t_tid == tid)) +- need_to_wait = 0; +- read_unlock(&journal->j_state_lock); +- if (!need_to_wait) +- return 0; +-wait_commit: +- return jbd2_log_wait_commit(journal, tid); +-} +-EXPORT_SYMBOL(jbd2_complete_transaction); +- +-/* + * Log buffer allocation routines: + */ + +diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c +index 193f04c..ca0a080 100644 +--- a/fs/lockd/clntlock.c ++++ b/fs/lockd/clntlock.c +@@ -144,9 +144,6 @@ int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout) + timeout); + if (ret < 0) + return -ERESTARTSYS; +- /* Reset the lock status after a server reboot so we resend */ +- if (block->b_status == nlm_lck_denied_grace_period) +- block->b_status = nlm_lck_blocked; + req->a_res.status = block->b_status; + return 0; + } +diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c +index 54f9e6c..52e5120 100644 +--- a/fs/lockd/clntproc.c ++++ b/fs/lockd/clntproc.c +@@ -550,6 +550,9 @@ again: + status = nlmclnt_block(block, req, NLMCLNT_POLL_TIMEOUT); + if (status < 0) + break; ++ /* Resend the blocking lock request after a server reboot */ ++ if (resp->status == nlm_lck_denied_grace_period) ++ continue; + if (resp->status != nlm_lck_blocked) + break; + } +diff --git a/fs/namespace.c b/fs/namespace.c +index 0361843..5dd7709 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -52,7 +52,6 @@ EXPORT_SYMBOL_GPL(fs_kobj); + * tree or hash is modified or when a vfsmount structure is modified. + */ + DEFINE_BRLOCK(vfsmount_lock); +-EXPORT_SYMBOL(vfsmount_lock); + + static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry) + { +@@ -426,7 +425,6 @@ void __mnt_drop_write(struct vfsmount *mnt) + mnt_dec_writers(real_mount(mnt)); + preempt_enable(); + } +-EXPORT_SYMBOL_GPL(__mnt_drop_write); + + /** + * mnt_drop_write - give up write access to a mount +@@ -1437,7 +1435,6 @@ int iterate_mounts(int (*f)(struct vfsmount *, void *), void *arg, + } + return 0; + } +-EXPORT_SYMBOL(iterate_mounts); + + static void cleanup_group_ids(struct mount *mnt, struct mount *end) + { +diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig +index 169e5ab..13ca196 100644 +--- a/fs/nfs/Kconfig ++++ b/fs/nfs/Kconfig +@@ -39,19 +39,6 @@ config NFS_V2 + + If unsure, say Y. + +-config NFS_DEF_FILE_IO_SIZE +- int "Default size for NFS I/O read and write at runtime" +- depends on NFS_FS +- default "4096" +- help +- To change the default rsize and wsize supported by the NFS client, +- adjust NFS_DEF_FILE_IO_SIZE. 64KB is a typical maximum, but some +- servers can support a megabyte or more. The default is left at 4096 +- bytes, which is reasonable for NFS over UDP, however, for some +- systems, setting a smaller value like 1024 can work around +- limitations in the driver or hardware and result in overall +- improved performance. +- + config NFS_V3 + tristate "NFS client support for NFS version 3" + depends on NFS_FS +diff --git a/fs/nfs/client.c b/fs/nfs/client.c +index 8bab9b3..9f3c664 100644 +--- a/fs/nfs/client.c ++++ b/fs/nfs/client.c +@@ -9,6 +9,7 @@ + * 2 of the License, or (at your option) any later version. + */ + ++ + #include + #include + #include +@@ -69,7 +70,7 @@ static const struct rpc_version *nfs_version[5] = { + [4] = NULL, + }; + +-struct rpc_program nfs_program = { ++const struct rpc_program nfs_program = { + .name = "nfs", + .number = NFS_PROGRAM, + .nrvers = ARRAY_SIZE(nfs_version), +@@ -160,7 +161,6 @@ struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init) + try_module_get(clp->cl_nfs_mod->owner); + + clp->rpc_ops = clp->cl_nfs_mod->rpc_ops; +- clp->nfs_prog = cl_init->nfs_prog; + + atomic_set(&clp->cl_count, 1); + clp->cl_cons_state = NFS_CS_INITING; +@@ -419,9 +419,6 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat + /* Match nfsv4 minorversion */ + if (clp->cl_minorversion != data->minorversion) + continue; +- if (clp->nfs_prog != data->nfs_prog) +- continue; +- + /* Match the full socket address */ + if (!nfs_sockaddr_cmp(sap, clap)) + continue; +@@ -601,10 +598,6 @@ int nfs_create_rpc_client(struct nfs_client *clp, + if (!IS_ERR(clp->cl_rpcclient)) + return 0; + +- if (clp->nfs_prog) +- nfs_program.number = clp->nfs_prog; +- else +- nfs_program.number = NFS_PROGRAM; + clnt = rpc_create(&args); + if (IS_ERR(clnt)) { + dprintk("%s: cannot create RPC client. Error = %ld\n", +@@ -748,7 +741,6 @@ static int nfs_init_server(struct nfs_server *server, + .nfs_mod = nfs_mod, + .proto = data->nfs_server.protocol, + .net = data->net, +- .nfs_prog = data->nfs_prog, + }; + struct rpc_timeout timeparms; + struct nfs_client *clp; +diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h +index 5ff7498..f0e6c7d 100644 +--- a/fs/nfs/internal.h ++++ b/fs/nfs/internal.h +@@ -73,7 +73,6 @@ struct nfs_client_initdata { + int proto; + u32 minorversion; + struct net *net; +- int nfs_prog; + }; + + /* +@@ -85,8 +84,6 @@ struct nfs_parsed_mount_data { + unsigned int timeo, retrans; + unsigned int acregmin, acregmax, + acdirmin, acdirmax; +- int nfs_prog; +- int mount_prog; + unsigned int namlen; + unsigned int options; + unsigned int bsize; +@@ -143,11 +140,11 @@ struct nfs_mount_info { + struct nfs_fh *mntfh; + }; + +-extern int nfs_mount(struct nfs_mount_request *info, int prog); ++extern int nfs_mount(struct nfs_mount_request *info); + extern void nfs_umount(const struct nfs_mount_request *info); + + /* client.c */ +-extern struct rpc_program nfs_program; ++extern const struct rpc_program nfs_program; + extern void nfs_clients_init(struct net *net); + extern struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *); + int nfs_create_rpc_client(struct nfs_client *, const struct rpc_timeout *, rpc_authflavor_t); +diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c +index 09eeebc..91a6faf 100644 +--- a/fs/nfs/mount_clnt.c ++++ b/fs/nfs/mount_clnt.c +@@ -67,7 +67,7 @@ enum { + MOUNTPROC3_EXPORT = 5, + }; + +-static struct rpc_program mnt_program; ++static const struct rpc_program mnt_program; + + /* + * Defined by OpenGroup XNFS Version 3W, chapter 8 +@@ -141,7 +141,7 @@ struct mnt_fhstatus { + * + * Uses default timeout parameters specified by underlying transport. + */ +-int nfs_mount(struct nfs_mount_request *info, int m_prog) ++int nfs_mount(struct nfs_mount_request *info) + { + struct mountres result = { + .fh = info->fh, +@@ -175,7 +175,6 @@ int nfs_mount(struct nfs_mount_request *info, int m_prog) + if (info->noresvport) + args.flags |= RPC_CLNT_CREATE_NONPRIVPORT; + +- mnt_program.number = m_prog; + mnt_clnt = rpc_create(&args); + if (IS_ERR(mnt_clnt)) + goto out_clnt_err; +@@ -515,7 +514,7 @@ static const struct rpc_version *mnt_version[] = { + + static struct rpc_stat mnt_stats; + +-static struct rpc_program mnt_program = { ++static const struct rpc_program mnt_program = { + .name = "mount", + .number = NFS_MNT_PROGRAM, + .nrvers = ARRAY_SIZE(mnt_version), +diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c +index e3c6121..3d905e3 100644 +--- a/fs/nfs/nfs4proc.c ++++ b/fs/nfs/nfs4proc.c +@@ -1374,12 +1374,6 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state + case -ENOMEM: + err = 0; + goto out; +- case -NFS4ERR_DELAY: +- case -NFS4ERR_GRACE: +- set_bit(NFS_DELEGATED_STATE, &state->flags); +- ssleep(1); +- err = -EAGAIN; +- goto out; + } + err = nfs4_handle_exception(server, err, &exception); + } while (exception.retry); +@@ -4513,9 +4507,9 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock * + if (status != 0) + goto out; + /* Is this a delegated lock? */ +- lsp = request->fl_u.nfs4_fl.owner; +- if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) == 0) ++ if (test_bit(NFS_DELEGATED_STATE, &state->flags)) + goto out; ++ lsp = request->fl_u.nfs4_fl.owner; + seqid = nfs_alloc_seqid(&lsp->ls_seqid, GFP_KERNEL); + status = -ENOMEM; + if (seqid == NULL) +diff --git a/fs/nfs/super.c b/fs/nfs/super.c +index c9d9825..b056b16 100644 +--- a/fs/nfs/super.c ++++ b/fs/nfs/super.c +@@ -103,8 +103,6 @@ enum { + Opt_mountport, + Opt_mountvers, + Opt_minorversion, +- Opt_mountprog, +- Opt_nfsprog, + + /* Mount options that take string arguments */ + Opt_nfsvers, +@@ -170,8 +168,6 @@ static const match_table_t nfs_mount_option_tokens = { + { Opt_mountport, "mountport=%s" }, + { Opt_mountvers, "mountvers=%s" }, + { Opt_minorversion, "minorversion=%s" }, +- { Opt_mountprog, "mountprog=%s" }, +- { Opt_nfsprog, "nfsprog=%s" }, + + { Opt_nfsvers, "nfsvers=%s" }, + { Opt_nfsvers, "vers=%s" }, +@@ -966,8 +962,6 @@ static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(void) + data->acregmax = NFS_DEF_ACREGMAX; + data->acdirmin = NFS_DEF_ACDIRMIN; + data->acdirmax = NFS_DEF_ACDIRMAX; +- data->nfs_prog = NFS_PROGRAM; +- data->mount_prog = NFS_MNT_PROGRAM; + data->mount_server.port = NFS_UNSPEC_PORT; + data->nfs_server.port = NFS_UNSPEC_PORT; + data->nfs_server.protocol = XPRT_TRANSPORT_TCP; +@@ -1367,26 +1361,6 @@ static int nfs_parse_mount_options(char *raw, + goto out_invalid_value; + mnt->acdirmax = option; + break; +- case Opt_mountprog: +- string = match_strdup(args); +- if (string == NULL) +- goto out_nomem; +- rc = strict_strtoul(string, 10, &option); +- kfree(string); +- if (rc != 0) +- goto out_invalid_value; +- mnt->mount_prog = option; +- break; +- case Opt_nfsprog: +- string = match_strdup(args); +- if (string == NULL) +- goto out_nomem; +- rc = strict_strtoul(string, 10, &option); +- kfree(string); +- if (rc != 0) +- goto out_invalid_value; +- mnt->nfs_prog = option; +- break; + case Opt_actimeo: + if (nfs_get_option_ul(args, &option)) + goto out_invalid_value; +@@ -1777,7 +1751,7 @@ static int nfs_request_mount(struct nfs_parsed_mount_data *args, + * Now ask the mount server to map our export path + * to a file handle. + */ +- status = nfs_mount(&request,args->mount_prog); ++ status = nfs_mount(&request); + if (status != 0) { + dfprintk(MOUNT, "NFS: unable to mount server %s, error %d\n", + request.hostname, status); +@@ -1909,7 +1883,6 @@ static int nfs23_validate_mount_data(void *options, + { + struct nfs_mount_data *data = (struct nfs_mount_data *)options; + struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address; +- args->nfs_prog = NFS_PROGRAM; + + if (data == NULL) + goto out_no_data; +@@ -1930,8 +1903,6 @@ static int nfs23_validate_mount_data(void *options, + goto out_no_sec; + case 5: + memset(data->context, 0, sizeof(data->context)); +- case 7: +- args->nfs_prog = (data->version >= 7) ? data->nfs_prog : NFS_PROGRAM; + case 6: + if (data->flags & NFS_MOUNT_VER3) { + if (data->root.size > NFS3_FHSIZE || data->root.size == 0) +@@ -2661,8 +2632,6 @@ static int nfs4_validate_mount_data(void *options, + + args->version = 4; + +- args->nfs_prog = NFS_PROGRAM; +- + switch (data->version) { + case 1: + if (data->host_addrlen > sizeof(args->nfs_server.address)) +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index ec668e1..9d1c5db 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -931,14 +931,14 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + nfs4_lock_state(); + status = nfs4_preprocess_stateid_op(SVC_NET(rqstp), + cstate, stateid, WR_STATE, &filp); ++ if (filp) ++ get_file(filp); ++ nfs4_unlock_state(); ++ + if (status) { +- nfs4_unlock_state(); + dprintk("NFSD: nfsd4_write: couldn't process stateid!\n"); + return status; + } +- if (filp) +- get_file(filp); +- nfs4_unlock_state(); + + cnt = write->wr_buflen; + write->wr_how_written = write->wr_stable_how; +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 53a7c64..a8309c6 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -210,7 +210,13 @@ static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag) + { + if (atomic_dec_and_test(&fp->fi_access[oflag])) { + nfs4_file_put_fd(fp, oflag); +- if (atomic_read(&fp->fi_access[1 - oflag]) == 0) ++ /* ++ * It's also safe to get rid of the RDWR open *if* ++ * we no longer have need of the other kind of access ++ * or if we already have the other kind of open: ++ */ ++ if (fp->fi_fds[1-oflag] ++ || atomic_read(&fp->fi_access[1 - oflag]) == 0) + nfs4_file_put_fd(fp, O_RDWR); + } + } +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index cd5e6c1..d1dd710 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -344,7 +344,10 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, + all 32 bits of 'nseconds'. */ + READ_BUF(12); + len += 12; +- READ64(iattr->ia_atime.tv_sec); ++ READ32(dummy32); ++ if (dummy32) ++ return nfserr_inval; ++ READ32(iattr->ia_atime.tv_sec); + READ32(iattr->ia_atime.tv_nsec); + if (iattr->ia_atime.tv_nsec >= (u32)1000000000) + return nfserr_inval; +@@ -367,7 +370,10 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, + all 32 bits of 'nseconds'. */ + READ_BUF(12); + len += 12; +- READ64(iattr->ia_mtime.tv_sec); ++ READ32(dummy32); ++ if (dummy32) ++ return nfserr_inval; ++ READ32(iattr->ia_mtime.tv_sec); + READ32(iattr->ia_mtime.tv_nsec); + if (iattr->ia_mtime.tv_nsec >= (u32)1000000000) + return nfserr_inval; +@@ -2380,7 +2386,8 @@ out_acl: + if (bmval1 & FATTR4_WORD1_TIME_ACCESS) { + if ((buflen -= 12) < 0) + goto out_resource; +- WRITE64((s64)stat.atime.tv_sec); ++ WRITE32(0); ++ WRITE32(stat.atime.tv_sec); + WRITE32(stat.atime.tv_nsec); + } + if (bmval1 & FATTR4_WORD1_TIME_DELTA) { +@@ -2393,13 +2400,15 @@ out_acl: + if (bmval1 & FATTR4_WORD1_TIME_METADATA) { + if ((buflen -= 12) < 0) + goto out_resource; +- WRITE64((s64)stat.ctime.tv_sec); ++ WRITE32(0); ++ WRITE32(stat.ctime.tv_sec); + WRITE32(stat.ctime.tv_nsec); + } + if (bmval1 & FATTR4_WORD1_TIME_MODIFY) { + if ((buflen -= 12) < 0) + goto out_resource; +- WRITE64((s64)stat.mtime.tv_sec); ++ WRITE32(0); ++ WRITE32(stat.mtime.tv_sec); + WRITE32(stat.mtime.tv_nsec); + } + if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) { +diff --git a/fs/notify/group.c b/fs/notify/group.c +index 2ff2a0f..bd2625b 100644 +--- a/fs/notify/group.c ++++ b/fs/notify/group.c +@@ -22,7 +22,6 @@ + #include + #include + #include +-#include + + #include + #include "fsnotify.h" +@@ -66,7 +65,6 @@ void fsnotify_get_group(struct fsnotify_group *group) + { + atomic_inc(&group->refcnt); + } +-EXPORT_SYMBOL(fsnotify_get_group); + + /* + * Drop a reference to a group. Free it if it's through. +@@ -76,7 +74,6 @@ void fsnotify_put_group(struct fsnotify_group *group) + if (atomic_dec_and_test(&group->refcnt)) + fsnotify_final_destroy_group(group); + } +-EXPORT_SYMBOL(fsnotify_put_group); + + /* + * Create a new fsnotify_group and hold a reference for the group returned. +@@ -105,7 +102,6 @@ struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops) + + return group; + } +-EXPORT_SYMBOL(fsnotify_alloc_group); + + int fsnotify_fasync(int fd, struct file *file, int on) + { +diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c +index 595343e..07f7a92 100644 +--- a/fs/notify/inotify/inotify_user.c ++++ b/fs/notify/inotify/inotify_user.c +@@ -574,6 +574,7 @@ static int inotify_update_existing_watch(struct fsnotify_group *group, + int add = (arg & IN_MASK_ADD); + int ret; + ++ /* don't allow invalid bits: we don't want flags set */ + mask = inotify_arg_to_mask(arg); + + fsn_mark = fsnotify_find_inode_mark(group, inode); +@@ -624,6 +625,7 @@ static int inotify_new_watch(struct fsnotify_group *group, + struct idr *idr = &group->inotify_data.idr; + spinlock_t *idr_lock = &group->inotify_data.idr_lock; + ++ /* don't allow invalid bits: we don't want flags set */ + mask = inotify_arg_to_mask(arg); + + tmp_i_mark = kmem_cache_alloc(inotify_inode_mark_cachep, GFP_KERNEL); +@@ -751,10 +753,6 @@ SYSCALL_DEFINE3(inotify_add_watch, int, fd, const char __user *, pathname, + int ret; + unsigned flags = 0; + +- /* don't allow invalid bits: we don't want flags set */ +- if (unlikely(!(mask & ALL_INOTIFY_BITS))) +- return -EINVAL; +- + f = fdget(fd); + if (unlikely(!f.file)) + return -EBADF; +diff --git a/fs/notify/mark.c b/fs/notify/mark.c +index a6bb87d..fc6b49b 100644 +--- a/fs/notify/mark.c ++++ b/fs/notify/mark.c +@@ -115,7 +115,6 @@ void fsnotify_put_mark(struct fsnotify_mark *mark) + mark->free_mark(mark); + } + } +-EXPORT_SYMBOL(fsnotify_put_mark); + + /* + * Any time a mark is getting freed we end up here. +@@ -198,7 +197,6 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark, + fsnotify_destroy_mark_locked(mark, group); + mutex_unlock(&group->mark_mutex); + } +-EXPORT_SYMBOL(fsnotify_destroy_mark); + + void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask) + { +@@ -283,7 +281,6 @@ err: + + return ret; + } +-EXPORT_SYMBOL(fsnotify_add_mark); + + int fsnotify_add_mark(struct fsnotify_mark *mark, struct fsnotify_group *group, + struct inode *inode, struct vfsmount *mnt, int allow_dups) +@@ -345,7 +342,6 @@ void fsnotify_init_mark(struct fsnotify_mark *mark, + atomic_set(&mark->refcnt, 1); + mark->free_mark = free_mark; + } +-EXPORT_SYMBOL(fsnotify_init_mark); + + static int fsnotify_mark_destroy(void *ignored) + { +diff --git a/fs/open.c b/fs/open.c +index e3365035..9b33c0c 100644 +--- a/fs/open.c ++++ b/fs/open.c +@@ -60,7 +60,6 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, + mutex_unlock(&dentry->d_inode->i_mutex); + return ret; + } +-EXPORT_SYMBOL(do_truncate); + + long vfs_truncate(struct path *path, loff_t length) + { +diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c +index 8b29ab7..b1822dd 100644 +--- a/fs/proc/nommu.c ++++ b/fs/proc/nommu.c +@@ -46,10 +46,6 @@ static int nommu_region_show(struct seq_file *m, struct vm_region *region) + + if (file) { + struct inode *inode = region->vm_file->f_path.dentry->d_inode; +- if (region->vm_prfile) { +- file = region->vm_prfile; +- inode = file->f_path.dentry->d_inode; +- } + dev = inode->i_sb->s_dev; + ino = inode->i_ino; + } +diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c +index 45db66f..ca5ce7f 100644 +--- a/fs/proc/task_mmu.c ++++ b/fs/proc/task_mmu.c +@@ -272,10 +272,6 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid) + + if (file) { + struct inode *inode = vma->vm_file->f_path.dentry->d_inode; +- if (vma->vm_prfile) { +- file = vma->vm_prfile; +- inode = file->f_path.dentry->d_inode; +- } + dev = inode->i_sb->s_dev; + ino = inode->i_ino; + pgoff = ((loff_t)vma->vm_pgoff) << PAGE_SHIFT; +@@ -1289,8 +1285,6 @@ static int show_numa_map(struct seq_file *m, void *v, int is_pid) + + if (file) { + seq_printf(m, " file="); +- if (vma->vm_prfile) +- file = vma->vm_prfile; + seq_path(m, &file->f_path, "\n\t= "); + } else if (vma->vm_start <= mm->brk && vma->vm_end >= mm->start_brk) { + seq_printf(m, " heap"); +diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c +index c39acb5..1ccfa53 100644 +--- a/fs/proc/task_nommu.c ++++ b/fs/proc/task_nommu.c +@@ -150,10 +150,6 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma, + + if (file) { + struct inode *inode = vma->vm_file->f_path.dentry->d_inode; +- if (vma->vm_prfile) { +- file = vma->vm_prfile; +- inode = file->f_path.dentry->d_inode; +- } + dev = inode->i_sb->s_dev; + ino = inode->i_ino; + pgoff = (loff_t)vma->vm_pgoff << PAGE_SHIFT; +diff --git a/fs/splice.c b/fs/splice.c +index a622ade..6909d89 100644 +--- a/fs/splice.c ++++ b/fs/splice.c +@@ -1092,8 +1092,8 @@ EXPORT_SYMBOL(generic_splice_sendpage); + /* + * Attempt to initiate a splice from pipe to file. + */ +-long do_splice_from(struct pipe_inode_info *pipe, struct file *out, +- loff_t *ppos, size_t len, unsigned int flags) ++static long do_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); +@@ -1116,14 +1116,13 @@ long do_splice_from(struct pipe_inode_info *pipe, struct file *out, + + return splice_write(pipe, out, ppos, len, flags); + } +-EXPORT_SYMBOL(do_splice_from); + + /* + * Attempt to initiate a splice from a file to a pipe. + */ +-long do_splice_to(struct file *in, loff_t *ppos, +- struct pipe_inode_info *pipe, size_t len, +- unsigned int flags) ++static long do_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); +@@ -1143,7 +1142,6 @@ long do_splice_to(struct file *in, loff_t *ppos, + + return splice_read(in, ppos, pipe, len, flags); + } +-EXPORT_SYMBOL(do_splice_to); + + /** + * splice_direct_to_actor - splices data directly between two non-pipes +diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c +index d924812..1f8c823 100644 +--- a/fs/sysfs/dir.c ++++ b/fs/sysfs/dir.c +@@ -1012,7 +1012,6 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) + enum kobj_ns_type type; + const void *ns; + ino_t ino; +- loff_t off; + + type = sysfs_ns_type(parent_sd); + ns = sysfs_info(dentry->d_sb)->ns[type]; +@@ -1035,7 +1034,6 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) + return 0; + } + mutex_lock(&sysfs_mutex); +- off = filp->f_pos; + for (pos = sysfs_dir_pos(ns, parent_sd, filp->f_pos, pos); + pos; + pos = sysfs_dir_next_pos(ns, parent_sd, filp->f_pos, pos)) { +@@ -1047,24 +1045,19 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) + len = strlen(name); + ino = pos->s_ino; + type = dt_type(pos); +- off = filp->f_pos = pos->s_hash; ++ filp->f_pos = pos->s_hash; + filp->private_data = sysfs_get(pos); + + mutex_unlock(&sysfs_mutex); +- ret = filldir(dirent, name, len, off, ino, type); ++ ret = filldir(dirent, name, len, filp->f_pos, ino, type); + mutex_lock(&sysfs_mutex); + if (ret < 0) + break; + } + mutex_unlock(&sysfs_mutex); +- +- /* don't reference last entry if its refcount is dropped */ +- if (!pos) { ++ if ((filp->f_pos > 1) && !pos) { /* EOF */ ++ filp->f_pos = INT_MAX; + filp->private_data = NULL; +- +- /* EOF and not changed as 0 or 1 in read/write path */ +- if (off == filp->f_pos && off > 1) +- filp->f_pos = INT_MAX; + } + return 0; + } +diff --git a/fs/yaffs2/Kconfig b/fs/yaffs2/Kconfig +deleted file mode 100644 +index 658feea..0000000 +--- a/fs/yaffs2/Kconfig ++++ /dev/null +@@ -1,161 +0,0 @@ +-# +-# yaffs file system configurations +-# +- +-config YAFFS_FS +- tristate "yaffs2 file system support" +- default n +- depends on MTD_BLOCK +- select YAFFS_YAFFS1 +- select YAFFS_YAFFS2 +- help +- yaffs2, or Yet Another Flash File System, is a file system +- optimised for NAND Flash chips. +- +- To compile the yaffs2 file system support as a module, choose M +- here: the module will be called yaffs2. +- +- If unsure, say N. +- +- Further information on yaffs2 is available at +- . +- +-config YAFFS_YAFFS1 +- bool "512 byte / page devices" +- depends on YAFFS_FS +- default y +- help +- Enable yaffs1 support -- yaffs for 512 byte / page devices +- +- Not needed for 2K-page devices. +- +- If unsure, say Y. +- +-config YAFFS_9BYTE_TAGS +- bool "Use older-style on-NAND data format with pageStatus byte" +- depends on YAFFS_YAFFS1 +- default n +- help +- +- Older-style on-NAND data format has a "pageStatus" byte to record +- chunk/page state. This byte is zero when the page is discarded. +- Choose this option if you have existing on-NAND data using this +- format that you need to continue to support. New data written +- also uses the older-style format. Note: Use of this option +- generally requires that MTD's oob layout be adjusted to use the +- older-style format. See notes on tags formats and MTD versions +- in yaffs_mtdif1.c. +- +- If unsure, say N. +- +-config YAFFS_DOES_ECC +- bool "Lets yaffs do its own ECC" +- depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS +- default n +- help +- This enables yaffs to use its own ECC functions instead of using +- the ones from the generic MTD-NAND driver. +- +- If unsure, say N. +- +-config YAFFS_ECC_WRONG_ORDER +- bool "Use the same ecc byte order as Steven Hill's nand_ecc.c" +- depends on YAFFS_FS && YAFFS_DOES_ECC && !YAFFS_9BYTE_TAGS +- default n +- help +- This makes yaffs_ecc.c use the same ecc byte order as Steven +- Hill's nand_ecc.c. If not set, then you get the same ecc byte +- order as SmartMedia. +- +- If unsure, say N. +- +-config YAFFS_YAFFS2 +- bool "2048 byte (or larger) / page devices" +- depends on YAFFS_FS +- default y +- help +- Enable yaffs2 support -- yaffs for >= 2K bytes per page devices +- +- If unsure, say Y. +- +-config YAFFS_AUTO_YAFFS2 +- bool "Autoselect yaffs2 format" +- depends on YAFFS_YAFFS2 +- default y +- help +- Without this, you need to explicitely use yaffs2 as the file +- system type. With this, you can say "yaffs" and yaffs or yaffs2 +- will be used depending on the device page size (yaffs on +- 512-byte page devices, yaffs2 on 2K page devices). +- +- If unsure, say Y. +- +-config YAFFS_DISABLE_TAGS_ECC +- bool "Disable yaffs from doing ECC on tags by default" +- depends on YAFFS_FS && YAFFS_YAFFS2 +- default n +- help +- This defaults yaffs to using its own ECC calculations on tags instead of +- just relying on the MTD. +- This behavior can also be overridden with tags_ecc_on and +- tags_ecc_off mount options. +- +- If unsure, say N. +- +-config YAFFS_ALWAYS_CHECK_CHUNK_ERASED +- bool "Force chunk erase check" +- depends on YAFFS_FS +- default n +- help +- Normally yaffs only checks chunks before writing until an erased +- chunk is found. This helps to detect any partially written +- chunks that might have happened due to power loss. +- +- Enabling this forces on the test that chunks are erased in flash +- before writing to them. This takes more time but is potentially +- a bit more secure. +- +- Suggest setting Y during development and ironing out driver +- issues etc. Suggest setting to N if you want faster writing. +- +- If unsure, say Y. +- +-config YAFFS_EMPTY_LOST_AND_FOUND +- bool "Empty lost and found on boot" +- depends on YAFFS_FS +- default n +- help +- If this is enabled then the contents of lost and found is +- automatically dumped at mount. +- +- If unsure, say N. +- +-config YAFFS_DISABLE_BLOCK_REFRESHING +- bool "Disable yaffs2 block refreshing" +- depends on YAFFS_FS +- default n +- help +- If this is set, then block refreshing is disabled. +- Block refreshing infrequently refreshes the oldest block in +- a yaffs2 file system. This mechanism helps to refresh flash to +- mitigate against data loss. This is particularly useful for MLC. +- +- If unsure, say N. +- +-config YAFFS_DISABLE_BACKGROUND +- bool "Disable yaffs2 background processing" +- depends on YAFFS_FS +- default n +- help +- If this is set, then background processing is disabled. +- Background processing makes many foreground activities faster. +- +- If unsure, say N. +- +-config YAFFS_XATTR +- bool "Enable yaffs2 xattr support" +- depends on YAFFS_FS +- default y +- help +- If this is set then yaffs2 will provide xattr support. +- If unsure, say Y. +diff --git a/fs/yaffs2/Makefile b/fs/yaffs2/Makefile +deleted file mode 100644 +index f9a9fb1..0000000 +--- a/fs/yaffs2/Makefile ++++ /dev/null +@@ -1,18 +0,0 @@ +-# +-# Makefile for the linux YAFFS filesystem routines. +-# +- +-obj-$(CONFIG_YAFFS_FS) += yaffs.o +- +-yaffs-y := yaffs_ecc.o yaffs_vfs.o yaffs_guts.o yaffs_checkptrw.o +-yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o +-yaffs-y += yaffs_tagscompat.o yaffs_tagsmarshall.o +-yaffs-y += yaffs_mtdif.o +-yaffs-y += yaffs_nameval.o yaffs_attribs.o +-yaffs-y += yaffs_allocator.o +-yaffs-y += yaffs_yaffs1.o +-yaffs-y += yaffs_yaffs2.o +-yaffs-y += yaffs_bitmap.o +-yaffs-y += yaffs_summary.o +-yaffs-y += yaffs_verify.o +- +diff --git a/fs/yaffs2/yaffs_allocator.c b/fs/yaffs2/yaffs_allocator.c +deleted file mode 100644 +index c8f2861..0000000 +--- a/fs/yaffs2/yaffs_allocator.c ++++ /dev/null +@@ -1,357 +0,0 @@ +-/* +- * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * 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 "yaffs_allocator.h" +-#include "yaffs_guts.h" +-#include "yaffs_trace.h" +-#include "yportenv.h" +- +-/* +- * Each entry in yaffs_tnode_list and yaffs_obj_list hold blocks +- * of approx 100 objects that are themn allocated singly. +- * This is basically a simplified slab allocator. +- * +- * We don't use the Linux slab allocator because slab does not allow +- * us to dump all the objects in one hit when we do a umount and tear +- * down all the tnodes and objects. slab requires that we first free +- * the individual objects. +- * +- * Once yaffs has been mainlined I shall try to motivate for a change +- * to slab to provide the extra features we need here. +- */ +- +-struct yaffs_tnode_list { +- struct yaffs_tnode_list *next; +- struct yaffs_tnode *tnodes; +-}; +- +-struct yaffs_obj_list { +- struct yaffs_obj_list *next; +- struct yaffs_obj *objects; +-}; +- +-struct yaffs_allocator { +- int n_tnodes_created; +- struct yaffs_tnode *free_tnodes; +- int n_free_tnodes; +- struct yaffs_tnode_list *alloc_tnode_list; +- +- int n_obj_created; +- struct list_head free_objs; +- int n_free_objects; +- +- struct yaffs_obj_list *allocated_obj_list; +-}; +- +-static void yaffs_deinit_raw_tnodes(struct yaffs_dev *dev) +-{ +- struct yaffs_allocator *allocator = +- (struct yaffs_allocator *)dev->allocator; +- struct yaffs_tnode_list *tmp; +- +- if (!allocator) { +- BUG(); +- return; +- } +- +- while (allocator->alloc_tnode_list) { +- tmp = allocator->alloc_tnode_list->next; +- +- kfree(allocator->alloc_tnode_list->tnodes); +- kfree(allocator->alloc_tnode_list); +- allocator->alloc_tnode_list = tmp; +- } +- +- allocator->free_tnodes = NULL; +- allocator->n_free_tnodes = 0; +- allocator->n_tnodes_created = 0; +-} +- +-static void yaffs_init_raw_tnodes(struct yaffs_dev *dev) +-{ +- struct yaffs_allocator *allocator = dev->allocator; +- +- if (!allocator) { +- BUG(); +- return; +- } +- +- allocator->alloc_tnode_list = NULL; +- allocator->free_tnodes = NULL; +- allocator->n_free_tnodes = 0; +- allocator->n_tnodes_created = 0; +-} +- +-static int yaffs_create_tnodes(struct yaffs_dev *dev, int n_tnodes) +-{ +- struct yaffs_allocator *allocator = +- (struct yaffs_allocator *)dev->allocator; +- int i; +- struct yaffs_tnode *new_tnodes; +- u8 *mem; +- struct yaffs_tnode *curr; +- struct yaffs_tnode *next; +- struct yaffs_tnode_list *tnl; +- +- if (!allocator) { +- BUG(); +- return YAFFS_FAIL; +- } +- +- if (n_tnodes < 1) +- return YAFFS_OK; +- +- /* make these things */ +- new_tnodes = kmalloc(n_tnodes * dev->tnode_size, GFP_NOFS); +- mem = (u8 *) new_tnodes; +- +- if (!new_tnodes) { +- yaffs_trace(YAFFS_TRACE_ERROR, +- "yaffs: Could not allocate Tnodes"); +- return YAFFS_FAIL; +- } +- +- /* New hookup for wide tnodes */ +- for (i = 0; i < n_tnodes - 1; i++) { +- curr = (struct yaffs_tnode *)&mem[i * dev->tnode_size]; +- next = (struct yaffs_tnode *)&mem[(i + 1) * dev->tnode_size]; +- curr->internal[0] = next; +- } +- +- curr = (struct yaffs_tnode *)&mem[(n_tnodes - 1) * dev->tnode_size]; +- curr->internal[0] = allocator->free_tnodes; +- allocator->free_tnodes = (struct yaffs_tnode *)mem; +- +- allocator->n_free_tnodes += n_tnodes; +- allocator->n_tnodes_created += n_tnodes; +- +- /* Now add this bunch of tnodes to a list for freeing up. +- * NB If we can't add this to the management list it isn't fatal +- * but it just means we can't free this bunch of tnodes later. +- */ +- tnl = kmalloc(sizeof(struct yaffs_tnode_list), GFP_NOFS); +- if (!tnl) { +- yaffs_trace(YAFFS_TRACE_ERROR, +- "Could not add tnodes to management list"); +- return YAFFS_FAIL; +- } else { +- tnl->tnodes = new_tnodes; +- tnl->next = allocator->alloc_tnode_list; +- allocator->alloc_tnode_list = tnl; +- } +- +- yaffs_trace(YAFFS_TRACE_ALLOCATE, "Tnodes added"); +- +- return YAFFS_OK; +-} +- +-struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev) +-{ +- struct yaffs_allocator *allocator = +- (struct yaffs_allocator *)dev->allocator; +- struct yaffs_tnode *tn = NULL; +- +- if (!allocator) { +- BUG(); +- return NULL; +- } +- +- /* If there are none left make more */ +- if (!allocator->free_tnodes) +- yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES); +- +- if (allocator->free_tnodes) { +- tn = allocator->free_tnodes; +- allocator->free_tnodes = allocator->free_tnodes->internal[0]; +- allocator->n_free_tnodes--; +- } +- +- return tn; +-} +- +-/* FreeTnode frees up a tnode and puts it back on the free list */ +-void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn) +-{ +- struct yaffs_allocator *allocator = dev->allocator; +- +- if (!allocator) { +- BUG(); +- return; +- } +- +- if (tn) { +- tn->internal[0] = allocator->free_tnodes; +- allocator->free_tnodes = tn; +- allocator->n_free_tnodes++; +- } +- dev->checkpoint_blocks_required = 0; /* force recalculation */ +-} +- +-/*--------------- yaffs_obj alloaction ------------------------ +- * +- * Free yaffs_objs are stored in a list using obj->siblings. +- * The blocks of allocated objects are stored in a linked list. +- */ +- +-static void yaffs_init_raw_objs(struct yaffs_dev *dev) +-{ +- struct yaffs_allocator *allocator = dev->allocator; +- +- if (!allocator) { +- BUG(); +- return; +- } +- +- allocator->allocated_obj_list = NULL; +- INIT_LIST_HEAD(&allocator->free_objs); +- allocator->n_free_objects = 0; +-} +- +-static void yaffs_deinit_raw_objs(struct yaffs_dev *dev) +-{ +- struct yaffs_allocator *allocator = dev->allocator; +- struct yaffs_obj_list *tmp; +- +- if (!allocator) { +- BUG(); +- return; +- } +- +- while (allocator->allocated_obj_list) { +- tmp = allocator->allocated_obj_list->next; +- kfree(allocator->allocated_obj_list->objects); +- kfree(allocator->allocated_obj_list); +- allocator->allocated_obj_list = tmp; +- } +- +- INIT_LIST_HEAD(&allocator->free_objs); +- allocator->n_free_objects = 0; +- allocator->n_obj_created = 0; +-} +- +-static int yaffs_create_free_objs(struct yaffs_dev *dev, int n_obj) +-{ +- struct yaffs_allocator *allocator = dev->allocator; +- int i; +- struct yaffs_obj *new_objs; +- struct yaffs_obj_list *list; +- +- if (!allocator) { +- BUG(); +- return YAFFS_FAIL; +- } +- +- if (n_obj < 1) +- return YAFFS_OK; +- +- /* make these things */ +- new_objs = kmalloc(n_obj * sizeof(struct yaffs_obj), GFP_NOFS); +- list = kmalloc(sizeof(struct yaffs_obj_list), GFP_NOFS); +- +- if (!new_objs || !list) { +- kfree(new_objs); +- new_objs = NULL; +- kfree(list); +- list = NULL; +- yaffs_trace(YAFFS_TRACE_ALLOCATE, +- "Could not allocate more objects"); +- return YAFFS_FAIL; +- } +- +- /* Hook them into the free list */ +- for (i = 0; i < n_obj; i++) +- list_add(&new_objs[i].siblings, &allocator->free_objs); +- +- allocator->n_free_objects += n_obj; +- allocator->n_obj_created += n_obj; +- +- /* Now add this bunch of Objects to a list for freeing up. */ +- +- list->objects = new_objs; +- list->next = allocator->allocated_obj_list; +- allocator->allocated_obj_list = list; +- +- return YAFFS_OK; +-} +- +-struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev) +-{ +- struct yaffs_obj *obj = NULL; +- struct list_head *lh; +- struct yaffs_allocator *allocator = dev->allocator; +- +- if (!allocator) { +- BUG(); +- return obj; +- } +- +- /* If there are none left make more */ +- if (list_empty(&allocator->free_objs)) +- yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS); +- +- if (!list_empty(&allocator->free_objs)) { +- lh = allocator->free_objs.next; +- obj = list_entry(lh, struct yaffs_obj, siblings); +- list_del_init(lh); +- allocator->n_free_objects--; +- } +- +- return obj; +-} +- +-void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj) +-{ +- +- struct yaffs_allocator *allocator = dev->allocator; +- +- if (!allocator) { +- BUG(); +- return; +- } +- +- /* Link into the free list. */ +- list_add(&obj->siblings, &allocator->free_objs); +- allocator->n_free_objects++; +-} +- +-void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev) +-{ +- +- if (!dev->allocator) { +- BUG(); +- return; +- } +- +- yaffs_deinit_raw_tnodes(dev); +- yaffs_deinit_raw_objs(dev); +- kfree(dev->allocator); +- dev->allocator = NULL; +-} +- +-void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev) +-{ +- struct yaffs_allocator *allocator; +- +- if (dev->allocator) { +- BUG(); +- return; +- } +- +- allocator = kmalloc(sizeof(struct yaffs_allocator), GFP_NOFS); +- if (allocator) { +- dev->allocator = allocator; +- yaffs_init_raw_tnodes(dev); +- yaffs_init_raw_objs(dev); +- } +-} +- +diff --git a/fs/yaffs2/yaffs_allocator.h b/fs/yaffs2/yaffs_allocator.h +deleted file mode 100644 +index a8cc322..0000000 +--- a/fs/yaffs2/yaffs_allocator.h ++++ /dev/null +@@ -1,30 +0,0 @@ +-/* +- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU Lesser General Public License version 2.1 as +- * published by the Free Software Foundation. +- * +- * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +- */ +- +-#ifndef __YAFFS_ALLOCATOR_H__ +-#define __YAFFS_ALLOCATOR_H__ +- +-#include "yaffs_guts.h" +- +-void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev); +-void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev); +- +-struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev); +-void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn); +- +-struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev); +-void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj); +- +-#endif +diff --git a/fs/yaffs2/yaffs_attribs.c b/fs/yaffs2/yaffs_attribs.c +deleted file mode 100644 +index 3d778f2..0000000 +--- a/fs/yaffs2/yaffs_attribs.c ++++ /dev/null +@@ -1,124 +0,0 @@ +-/* +- * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * 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 "yaffs_guts.h" +-#include "yaffs_attribs.h" +- +-void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh) +-{ +- obj->yst_uid = oh->yst_uid; +- obj->yst_gid = oh->yst_gid; +- obj->yst_atime = oh->yst_atime; +- obj->yst_mtime = oh->yst_mtime; +- obj->yst_ctime = oh->yst_ctime; +- obj->yst_rdev = oh->yst_rdev; +-} +- +-void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj) +-{ +- oh->yst_uid = obj->yst_uid; +- oh->yst_gid = obj->yst_gid; +- oh->yst_atime = obj->yst_atime; +- oh->yst_mtime = obj->yst_mtime; +- oh->yst_ctime = obj->yst_ctime; +- oh->yst_rdev = obj->yst_rdev; +- +-} +- +-void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c) +-{ +- obj->yst_mtime = Y_CURRENT_TIME; +- if (do_a) +- obj->yst_atime = obj->yst_mtime; +- if (do_c) +- obj->yst_ctime = obj->yst_mtime; +-} +- +-void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev) +-{ +- yaffs_load_current_time(obj, 1, 1); +- obj->yst_rdev = rdev; +- obj->yst_uid = uid; +- obj->yst_gid = gid; +-} +- +-static loff_t yaffs_get_file_size(struct yaffs_obj *obj) +-{ +- YCHAR *alias = NULL; +- obj = yaffs_get_equivalent_obj(obj); +- +- switch (obj->variant_type) { +- case YAFFS_OBJECT_TYPE_FILE: +- return obj->variant.file_variant.file_size; +- case YAFFS_OBJECT_TYPE_SYMLINK: +- alias = obj->variant.symlink_variant.alias; +- if (!alias) +- return 0; +- return strnlen(alias, YAFFS_MAX_ALIAS_LENGTH); +- default: +- return 0; +- } +-} +- +-int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr) +-{ +- unsigned int valid = attr->ia_valid; +- +- if (valid & ATTR_MODE) +- obj->yst_mode = attr->ia_mode; +- if (valid & ATTR_UID) +- obj->yst_uid = attr->ia_uid; +- if (valid & ATTR_GID) +- obj->yst_gid = attr->ia_gid; +- +- if (valid & ATTR_ATIME) +- obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime); +- if (valid & ATTR_CTIME) +- obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime); +- if (valid & ATTR_MTIME) +- obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime); +- +- if (valid & ATTR_SIZE) +- yaffs_resize_file(obj, attr->ia_size); +- +- yaffs_update_oh(obj, NULL, 1, 0, 0, NULL); +- +- return YAFFS_OK; +- +-} +- +-int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr) +-{ +- unsigned int valid = 0; +- +- attr->ia_mode = obj->yst_mode; +- valid |= ATTR_MODE; +- attr->ia_uid = obj->yst_uid; +- valid |= ATTR_UID; +- attr->ia_gid = obj->yst_gid; +- valid |= ATTR_GID; +- +- Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime; +- valid |= ATTR_ATIME; +- Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime; +- valid |= ATTR_CTIME; +- Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime; +- valid |= ATTR_MTIME; +- +- attr->ia_size = yaffs_get_file_size(obj); +- valid |= ATTR_SIZE; +- +- attr->ia_valid = valid; +- +- return YAFFS_OK; +-} +diff --git a/fs/yaffs2/yaffs_attribs.h b/fs/yaffs2/yaffs_attribs.h +deleted file mode 100644 +index 5b21b08..0000000 +--- a/fs/yaffs2/yaffs_attribs.h ++++ /dev/null +@@ -1,28 +0,0 @@ +-/* +- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU Lesser General Public License version 2.1 as +- * published by the Free Software Foundation. +- * +- * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +- */ +- +-#ifndef __YAFFS_ATTRIBS_H__ +-#define __YAFFS_ATTRIBS_H__ +- +-#include "yaffs_guts.h" +- +-void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh); +-void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj); +-void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev); +-void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c); +-int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr); +-int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr); +- +-#endif +diff --git a/fs/yaffs2/yaffs_bitmap.c b/fs/yaffs2/yaffs_bitmap.c +deleted file mode 100644 +index 4440e93..0000000 +--- a/fs/yaffs2/yaffs_bitmap.c ++++ /dev/null +@@ -1,97 +0,0 @@ +-/* +- * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * 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 "yaffs_bitmap.h" +-#include "yaffs_trace.h" +-/* +- * Chunk bitmap manipulations +- */ +- +-static inline u8 *yaffs_block_bits(struct yaffs_dev *dev, int blk) +-{ +- if (blk < dev->internal_start_block || blk > dev->internal_end_block) { +- yaffs_trace(YAFFS_TRACE_ERROR, +- "BlockBits block %d is not valid", +- blk); +- BUG(); +- } +- return dev->chunk_bits + +- (dev->chunk_bit_stride * (blk - dev->internal_start_block)); +-} +- +-void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk) +-{ +- if (blk < dev->internal_start_block || blk > dev->internal_end_block || +- chunk < 0 || chunk >= dev->param.chunks_per_block) { +- yaffs_trace(YAFFS_TRACE_ERROR, +- "Chunk Id (%d:%d) invalid", +- blk, chunk); +- BUG(); +- } +-} +- +-void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk) +-{ +- u8 *blk_bits = yaffs_block_bits(dev, blk); +- +- memset(blk_bits, 0, dev->chunk_bit_stride); +-} +- +-void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk) +-{ +- u8 *blk_bits = yaffs_block_bits(dev, blk); +- +- yaffs_verify_chunk_bit_id(dev, blk, chunk); +- blk_bits[chunk / 8] &= ~(1 << (chunk & 7)); +-} +- +-void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk) +-{ +- u8 *blk_bits = yaffs_block_bits(dev, blk); +- +- yaffs_verify_chunk_bit_id(dev, blk, chunk); +- blk_bits[chunk / 8] |= (1 << (chunk & 7)); +-} +- +-int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk) +-{ +- u8 *blk_bits = yaffs_block_bits(dev, blk); +- +- yaffs_verify_chunk_bit_id(dev, blk, chunk); +- return (blk_bits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0; +-} +- +-int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk) +-{ +- u8 *blk_bits = yaffs_block_bits(dev, blk); +- int i; +- +- for (i = 0; i < dev->chunk_bit_stride; i++) { +- if (*blk_bits) +- return 1; +- blk_bits++; +- } +- return 0; +-} +- +-int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk) +-{ +- u8 *blk_bits = yaffs_block_bits(dev, blk); +- int i; +- int n = 0; +- +- for (i = 0; i < dev->chunk_bit_stride; i++, blk_bits++) +- n += hweight8(*blk_bits); +- +- return n; +-} +diff --git a/fs/yaffs2/yaffs_bitmap.h b/fs/yaffs2/yaffs_bitmap.h +deleted file mode 100644 +index e26b37d..0000000 +--- a/fs/yaffs2/yaffs_bitmap.h ++++ /dev/null +@@ -1,33 +0,0 @@ +-/* +- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU Lesser General Public License version 2.1 as +- * published by the Free Software Foundation. +- * +- * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +- */ +- +-/* +- * Chunk bitmap manipulations +- */ +- +-#ifndef __YAFFS_BITMAP_H__ +-#define __YAFFS_BITMAP_H__ +- +-#include "yaffs_guts.h" +- +-void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk); +-void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk); +-void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk); +-void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk); +-int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk); +-int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk); +-int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk); +- +-#endif +diff --git a/fs/yaffs2/yaffs_checkptrw.c b/fs/yaffs2/yaffs_checkptrw.c +deleted file mode 100644 +index e739fb4..0000000 +--- a/fs/yaffs2/yaffs_checkptrw.c ++++ /dev/null +@@ -1,474 +0,0 @@ +-/* +- * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * 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 "yaffs_checkptrw.h" +-#include "yaffs_getblockinfo.h" +- +-struct yaffs_checkpt_chunk_hdr { +- int version; +- int seq; +- u32 sum; +- u32 xor; +-} ; +- +- +-static int apply_chunk_offset(struct yaffs_dev *dev, int chunk) +-{ +- return chunk - dev->chunk_offset; +-} +- +-static int apply_block_offset(struct yaffs_dev *dev, int block) +-{ +- return block - dev->block_offset; +-} +- +-static void yaffs2_checkpt_init_chunk_hdr(struct yaffs_dev *dev) +-{ +- struct yaffs_checkpt_chunk_hdr hdr; +- +- hdr.version = YAFFS_CHECKPOINT_VERSION; +- hdr.seq = dev->checkpt_page_seq; +- hdr.sum = dev->checkpt_sum; +- hdr.xor = dev->checkpt_xor; +- +- dev->checkpt_byte_offs = sizeof(hdr); +- +- memcpy(dev->checkpt_buffer, &hdr, sizeof(hdr)); +-} +- +-static int yaffs2_checkpt_check_chunk_hdr(struct yaffs_dev *dev) +-{ +- struct yaffs_checkpt_chunk_hdr hdr; +- +- memcpy(&hdr, dev->checkpt_buffer, sizeof(hdr)); +- +- dev->checkpt_byte_offs = sizeof(hdr); +- +- return hdr.version == YAFFS_CHECKPOINT_VERSION && +- hdr.seq == dev->checkpt_page_seq && +- hdr.sum == dev->checkpt_sum && +- hdr.xor == dev->checkpt_xor; +-} +- +-static int yaffs2_checkpt_space_ok(struct yaffs_dev *dev) +-{ +- int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks; +- +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, +- "checkpt blocks_avail = %d", blocks_avail); +- +- return (blocks_avail <= 0) ? 0 : 1; +-} +- +-static int yaffs_checkpt_erase(struct yaffs_dev *dev) +-{ +- int i; +- +- if (!dev->drv.drv_erase_fn) +- return 0; +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, +- "checking blocks %d to %d", +- dev->internal_start_block, dev->internal_end_block); +- +- for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { +- struct yaffs_block_info *bi = yaffs_get_block_info(dev, i); +- int offset_i = apply_block_offset(dev, i); +- int result; +- +- if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) { +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, +- "erasing checkpt block %d", i); +- +- dev->n_erasures++; +- +- result = dev->drv.drv_erase_fn(dev, offset_i); +- if(result) { +- bi->block_state = YAFFS_BLOCK_STATE_EMPTY; +- dev->n_erased_blocks++; +- dev->n_free_chunks += +- dev->param.chunks_per_block; +- } else { +- dev->drv.drv_mark_bad_fn(dev, offset_i); +- bi->block_state = YAFFS_BLOCK_STATE_DEAD; +- } +- } +- } +- +- dev->blocks_in_checkpt = 0; +- +- return 1; +-} +- +-static void yaffs2_checkpt_find_erased_block(struct yaffs_dev *dev) +-{ +- int i; +- int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks; +- +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, +- "allocating checkpt block: erased %d reserved %d avail %d next %d ", +- dev->n_erased_blocks, dev->param.n_reserved_blocks, +- blocks_avail, dev->checkpt_next_block); +- +- if (dev->checkpt_next_block >= 0 && +- dev->checkpt_next_block <= dev->internal_end_block && +- blocks_avail > 0) { +- +- for (i = dev->checkpt_next_block; i <= dev->internal_end_block; +- i++) { +- struct yaffs_block_info *bi; +- +- bi = yaffs_get_block_info(dev, i); +- if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) { +- dev->checkpt_next_block = i + 1; +- dev->checkpt_cur_block = i; +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, +- "allocating checkpt block %d", i); +- return; +- } +- } +- } +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, "out of checkpt blocks"); +- +- dev->checkpt_next_block = -1; +- dev->checkpt_cur_block = -1; +-} +- +-static void yaffs2_checkpt_find_block(struct yaffs_dev *dev) +-{ +- int i; +- struct yaffs_ext_tags tags; +- +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, +- "find next checkpt block: start: blocks %d next %d", +- dev->blocks_in_checkpt, dev->checkpt_next_block); +- +- if (dev->blocks_in_checkpt < dev->checkpt_max_blocks) +- for (i = dev->checkpt_next_block; i <= dev->internal_end_block; +- i++) { +- int chunk = i * dev->param.chunks_per_block; +- enum yaffs_block_state state; +- u32 seq; +- +- dev->tagger.read_chunk_tags_fn(dev, +- apply_chunk_offset(dev, chunk), +- NULL, &tags); +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, +- "find next checkpt block: search: block %d state %d oid %d seq %d eccr %d", +- i, (int) state, +- tags.obj_id, tags.seq_number, +- tags.ecc_result); +- +- if (tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA) +- continue; +- +- dev->tagger.query_block_fn(dev, +- apply_block_offset(dev, i), +- &state, &seq); +- if (state == YAFFS_BLOCK_STATE_DEAD) +- continue; +- +- /* Right kind of block */ +- dev->checkpt_next_block = tags.obj_id; +- dev->checkpt_cur_block = i; +- dev->checkpt_block_list[dev->blocks_in_checkpt] = i; +- dev->blocks_in_checkpt++; +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, +- "found checkpt block %d", i); +- return; +- } +- +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, "found no more checkpt blocks"); +- +- dev->checkpt_next_block = -1; +- dev->checkpt_cur_block = -1; +-} +- +-int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing) +-{ +- int i; +- +- dev->checkpt_open_write = writing; +- +- /* Got the functions we need? */ +- if (!dev->tagger.write_chunk_tags_fn || +- !dev->tagger.read_chunk_tags_fn || +- !dev->drv.drv_erase_fn || +- !dev->drv.drv_mark_bad_fn) +- return 0; +- +- if (writing && !yaffs2_checkpt_space_ok(dev)) +- return 0; +- +- if (!dev->checkpt_buffer) +- dev->checkpt_buffer = +- kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS); +- if (!dev->checkpt_buffer) +- return 0; +- +- dev->checkpt_page_seq = 0; +- dev->checkpt_byte_count = 0; +- dev->checkpt_sum = 0; +- dev->checkpt_xor = 0; +- dev->checkpt_cur_block = -1; +- dev->checkpt_cur_chunk = -1; +- dev->checkpt_next_block = dev->internal_start_block; +- +- if (writing) { +- memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk); +- yaffs2_checkpt_init_chunk_hdr(dev); +- return yaffs_checkpt_erase(dev); +- } +- +- /* Opening for a read */ +- /* Set to a value that will kick off a read */ +- dev->checkpt_byte_offs = dev->data_bytes_per_chunk; +- /* A checkpoint block list of 1 checkpoint block per 16 block is +- * (hopefully) going to be way more than we need */ +- dev->blocks_in_checkpt = 0; +- dev->checkpt_max_blocks = +- (dev->internal_end_block - dev->internal_start_block) / 16 + 2; +- dev->checkpt_block_list = +- kmalloc(sizeof(int) * dev->checkpt_max_blocks, GFP_NOFS); +- +- if (!dev->checkpt_block_list) +- return 0; +- +- for (i = 0; i < dev->checkpt_max_blocks; i++) +- dev->checkpt_block_list[i] = -1; +- +- return 1; +-} +- +-int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum) +-{ +- u32 composite_sum; +- +- composite_sum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xff); +- *sum = composite_sum; +- return 1; +-} +- +-static int yaffs2_checkpt_flush_buffer(struct yaffs_dev *dev) +-{ +- int chunk; +- int offset_chunk; +- struct yaffs_ext_tags tags; +- +- if (dev->checkpt_cur_block < 0) { +- yaffs2_checkpt_find_erased_block(dev); +- dev->checkpt_cur_chunk = 0; +- } +- +- if (dev->checkpt_cur_block < 0) +- return 0; +- +- tags.is_deleted = 0; +- tags.obj_id = dev->checkpt_next_block; /* Hint to next place to look */ +- tags.chunk_id = dev->checkpt_page_seq + 1; +- tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA; +- tags.n_bytes = dev->data_bytes_per_chunk; +- if (dev->checkpt_cur_chunk == 0) { +- /* First chunk we write for the block? Set block state to +- checkpoint */ +- struct yaffs_block_info *bi = +- yaffs_get_block_info(dev, dev->checkpt_cur_block); +- bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT; +- dev->blocks_in_checkpt++; +- } +- +- chunk = +- dev->checkpt_cur_block * dev->param.chunks_per_block + +- dev->checkpt_cur_chunk; +- +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, +- "checkpoint wite buffer nand %d(%d:%d) objid %d chId %d", +- chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk, +- tags.obj_id, tags.chunk_id); +- +- offset_chunk = apply_chunk_offset(dev, chunk); +- +- dev->n_page_writes++; +- +- dev->tagger.write_chunk_tags_fn(dev, offset_chunk, +- dev->checkpt_buffer, &tags); +- dev->checkpt_page_seq++; +- dev->checkpt_cur_chunk++; +- if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) { +- dev->checkpt_cur_chunk = 0; +- dev->checkpt_cur_block = -1; +- } +- memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk); +- +- yaffs2_checkpt_init_chunk_hdr(dev); +- +- +- return 1; +-} +- +-int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes) +-{ +- int i = 0; +- int ok = 1; +- u8 *data_bytes = (u8 *) data; +- +- if (!dev->checkpt_buffer) +- return 0; +- +- if (!dev->checkpt_open_write) +- return -1; +- +- while (i < n_bytes && ok) { +- dev->checkpt_buffer[dev->checkpt_byte_offs] = *data_bytes; +- dev->checkpt_sum += *data_bytes; +- dev->checkpt_xor ^= *data_bytes; +- +- dev->checkpt_byte_offs++; +- i++; +- data_bytes++; +- dev->checkpt_byte_count++; +- +- if (dev->checkpt_byte_offs < 0 || +- dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) +- ok = yaffs2_checkpt_flush_buffer(dev); +- } +- +- return i; +-} +- +-int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes) +-{ +- int i = 0; +- int ok = 1; +- struct yaffs_ext_tags tags; +- int chunk; +- int offset_chunk; +- u8 *data_bytes = (u8 *) data; +- +- if (!dev->checkpt_buffer) +- return 0; +- +- if (dev->checkpt_open_write) +- return -1; +- +- while (i < n_bytes && ok) { +- +- if (dev->checkpt_byte_offs < 0 || +- dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) { +- +- if (dev->checkpt_cur_block < 0) { +- yaffs2_checkpt_find_block(dev); +- dev->checkpt_cur_chunk = 0; +- } +- +- if (dev->checkpt_cur_block < 0) { +- ok = 0; +- break; +- } +- +- chunk = dev->checkpt_cur_block * +- dev->param.chunks_per_block + +- dev->checkpt_cur_chunk; +- +- offset_chunk = apply_chunk_offset(dev, chunk); +- dev->n_page_reads++; +- +- /* read in the next chunk */ +- dev->tagger.read_chunk_tags_fn(dev, +- offset_chunk, +- dev->checkpt_buffer, +- &tags); +- +- if (tags.chunk_id != (dev->checkpt_page_seq + 1) || +- tags.ecc_result > YAFFS_ECC_RESULT_FIXED || +- tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA) { +- ok = 0; +- break; +- } +- if(!yaffs2_checkpt_check_chunk_hdr(dev)) { +- ok = 0; +- break; +- } +- +- dev->checkpt_page_seq++; +- dev->checkpt_cur_chunk++; +- +- if (dev->checkpt_cur_chunk >= +- dev->param.chunks_per_block) +- dev->checkpt_cur_block = -1; +- +- } +- +- *data_bytes = dev->checkpt_buffer[dev->checkpt_byte_offs]; +- dev->checkpt_sum += *data_bytes; +- dev->checkpt_xor ^= *data_bytes; +- dev->checkpt_byte_offs++; +- i++; +- data_bytes++; +- dev->checkpt_byte_count++; +- } +- +- return i; +-} +- +-int yaffs_checkpt_close(struct yaffs_dev *dev) +-{ +- int i; +- +- if (dev->checkpt_open_write) { +- if (dev->checkpt_byte_offs != +- sizeof(sizeof(struct yaffs_checkpt_chunk_hdr))) +- yaffs2_checkpt_flush_buffer(dev); +- } else if (dev->checkpt_block_list) { +- for (i = 0; +- i < dev->blocks_in_checkpt && +- dev->checkpt_block_list[i] >= 0; i++) { +- int blk = dev->checkpt_block_list[i]; +- struct yaffs_block_info *bi = NULL; +- +- if (dev->internal_start_block <= blk && +- blk <= dev->internal_end_block) +- bi = yaffs_get_block_info(dev, blk); +- if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY) +- bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT; +- } +- kfree(dev->checkpt_block_list); +- dev->checkpt_block_list = NULL; +- } +- +- dev->n_free_chunks -= +- dev->blocks_in_checkpt * dev->param.chunks_per_block; +- dev->n_erased_blocks -= dev->blocks_in_checkpt; +- +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, "checkpoint byte count %d", +- dev->checkpt_byte_count); +- +- if (dev->checkpt_buffer) { +- /* free the buffer */ +- kfree(dev->checkpt_buffer); +- dev->checkpt_buffer = NULL; +- return 1; +- } else { +- return 0; +- } +-} +- +-int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev) +-{ +- /* Erase the checkpoint data */ +- +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, +- "checkpoint invalidate of %d blocks", +- dev->blocks_in_checkpt); +- +- return yaffs_checkpt_erase(dev); +-} +diff --git a/fs/yaffs2/yaffs_checkptrw.h b/fs/yaffs2/yaffs_checkptrw.h +deleted file mode 100644 +index cdbaba7..0000000 +--- a/fs/yaffs2/yaffs_checkptrw.h ++++ /dev/null +@@ -1,33 +0,0 @@ +-/* +- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU Lesser General Public License version 2.1 as +- * published by the Free Software Foundation. +- * +- * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +- */ +- +-#ifndef __YAFFS_CHECKPTRW_H__ +-#define __YAFFS_CHECKPTRW_H__ +- +-#include "yaffs_guts.h" +- +-int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing); +- +-int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes); +- +-int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes); +- +-int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum); +- +-int yaffs_checkpt_close(struct yaffs_dev *dev); +- +-int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev); +- +-#endif +diff --git a/fs/yaffs2/yaffs_ecc.c b/fs/yaffs2/yaffs_ecc.c +deleted file mode 100644 +index 9294107..0000000 +--- a/fs/yaffs2/yaffs_ecc.c ++++ /dev/null +@@ -1,281 +0,0 @@ +-/* +- * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * 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. +- */ +- +-/* +- * This code implements the ECC algorithm used in SmartMedia. +- * +- * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. +- * The two unused bit are set to 1. +- * The ECC can correct single bit errors in a 256-byte page of data. Thus, two +- * such ECC blocks are used on a 512-byte NAND page. +- * +- */ +- +-#include "yportenv.h" +- +-#include "yaffs_ecc.h" +- +-/* Table generated by gen-ecc.c +- * Using a table means we do not have to calculate p1..p4 and p1'..p4' +- * for each byte of data. These are instead provided in a table in bits7..2. +- * Bit 0 of each entry indicates whether the entry has an odd or even parity, +- * and therefore this bytes influence on the line parity. +- */ +- +-static const unsigned char column_parity_table[] = { +- 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, +- 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, +- 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, +- 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, +- 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, +- 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, +- 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, +- 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, +- 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, +- 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, +- 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, +- 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, +- 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, +- 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, +- 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, +- 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, +- 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, +- 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, +- 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, +- 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, +- 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, +- 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, +- 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, +- 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, +- 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, +- 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, +- 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, +- 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, +- 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, +- 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, +- 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, +- 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, +-}; +- +- +-/* Calculate the ECC for a 256-byte block of data */ +-void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc) +-{ +- unsigned int i; +- unsigned char col_parity = 0; +- unsigned char line_parity = 0; +- unsigned char line_parity_prime = 0; +- unsigned char t; +- unsigned char b; +- +- for (i = 0; i < 256; i++) { +- b = column_parity_table[*data++]; +- col_parity ^= b; +- +- if (b & 0x01) { /* odd number of bits in the byte */ +- line_parity ^= i; +- line_parity_prime ^= ~i; +- } +- } +- +- ecc[2] = (~col_parity) | 0x03; +- +- t = 0; +- if (line_parity & 0x80) +- t |= 0x80; +- if (line_parity_prime & 0x80) +- t |= 0x40; +- if (line_parity & 0x40) +- t |= 0x20; +- if (line_parity_prime & 0x40) +- t |= 0x10; +- if (line_parity & 0x20) +- t |= 0x08; +- if (line_parity_prime & 0x20) +- t |= 0x04; +- if (line_parity & 0x10) +- t |= 0x02; +- if (line_parity_prime & 0x10) +- t |= 0x01; +- ecc[1] = ~t; +- +- t = 0; +- if (line_parity & 0x08) +- t |= 0x80; +- if (line_parity_prime & 0x08) +- t |= 0x40; +- if (line_parity & 0x04) +- t |= 0x20; +- if (line_parity_prime & 0x04) +- t |= 0x10; +- if (line_parity & 0x02) +- t |= 0x08; +- if (line_parity_prime & 0x02) +- t |= 0x04; +- if (line_parity & 0x01) +- t |= 0x02; +- if (line_parity_prime & 0x01) +- t |= 0x01; +- ecc[0] = ~t; +- +-} +- +-/* Correct the ECC on a 256 byte block of data */ +- +-int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc, +- const unsigned char *test_ecc) +-{ +- unsigned char d0, d1, d2; /* deltas */ +- +- d0 = read_ecc[0] ^ test_ecc[0]; +- d1 = read_ecc[1] ^ test_ecc[1]; +- d2 = read_ecc[2] ^ test_ecc[2]; +- +- if ((d0 | d1 | d2) == 0) +- return 0; /* no error */ +- +- if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 && +- ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 && +- ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) { +- /* Single bit (recoverable) error in data */ +- +- unsigned byte; +- unsigned bit; +- +- bit = byte = 0; +- +- if (d1 & 0x80) +- byte |= 0x80; +- if (d1 & 0x20) +- byte |= 0x40; +- if (d1 & 0x08) +- byte |= 0x20; +- if (d1 & 0x02) +- byte |= 0x10; +- if (d0 & 0x80) +- byte |= 0x08; +- if (d0 & 0x20) +- byte |= 0x04; +- if (d0 & 0x08) +- byte |= 0x02; +- if (d0 & 0x02) +- byte |= 0x01; +- +- if (d2 & 0x80) +- bit |= 0x04; +- if (d2 & 0x20) +- bit |= 0x02; +- if (d2 & 0x08) +- bit |= 0x01; +- +- data[byte] ^= (1 << bit); +- +- return 1; /* Corrected the error */ +- } +- +- if ((hweight8(d0) + hweight8(d1) + hweight8(d2)) == 1) { +- /* Reccoverable error in ecc */ +- +- read_ecc[0] = test_ecc[0]; +- read_ecc[1] = test_ecc[1]; +- read_ecc[2] = test_ecc[2]; +- +- return 1; /* Corrected the error */ +- } +- +- /* Unrecoverable error */ +- +- return -1; +- +-} +- +-/* +- * ECCxxxOther does ECC calcs on arbitrary n bytes of data +- */ +-void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes, +- struct yaffs_ecc_other *ecc_other) +-{ +- unsigned int i; +- unsigned char col_parity = 0; +- unsigned line_parity = 0; +- unsigned line_parity_prime = 0; +- unsigned char b; +- +- for (i = 0; i < n_bytes; i++) { +- b = column_parity_table[*data++]; +- col_parity ^= b; +- +- if (b & 0x01) { +- /* odd number of bits in the byte */ +- line_parity ^= i; +- line_parity_prime ^= ~i; +- } +- +- } +- +- ecc_other->col_parity = (col_parity >> 2) & 0x3f; +- ecc_other->line_parity = line_parity; +- ecc_other->line_parity_prime = line_parity_prime; +-} +- +-int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes, +- struct yaffs_ecc_other *read_ecc, +- const struct yaffs_ecc_other *test_ecc) +-{ +- unsigned char delta_col; /* column parity delta */ +- unsigned delta_line; /* line parity delta */ +- unsigned delta_line_prime; /* line parity delta */ +- unsigned bit; +- +- delta_col = read_ecc->col_parity ^ test_ecc->col_parity; +- delta_line = read_ecc->line_parity ^ test_ecc->line_parity; +- delta_line_prime = +- read_ecc->line_parity_prime ^ test_ecc->line_parity_prime; +- +- if ((delta_col | delta_line | delta_line_prime) == 0) +- return 0; /* no error */ +- +- if (delta_line == ~delta_line_prime && +- (((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) { +- /* Single bit (recoverable) error in data */ +- +- bit = 0; +- +- if (delta_col & 0x20) +- bit |= 0x04; +- if (delta_col & 0x08) +- bit |= 0x02; +- if (delta_col & 0x02) +- bit |= 0x01; +- +- if (delta_line >= n_bytes) +- return -1; +- +- data[delta_line] ^= (1 << bit); +- +- return 1; /* corrected */ +- } +- +- if ((hweight32(delta_line) + +- hweight32(delta_line_prime) + +- hweight8(delta_col)) == 1) { +- /* Reccoverable error in ecc */ +- +- *read_ecc = *test_ecc; +- return 1; /* corrected */ +- } +- +- /* Unrecoverable error */ +- +- return -1; +-} +diff --git a/fs/yaffs2/yaffs_ecc.h b/fs/yaffs2/yaffs_ecc.h +deleted file mode 100644 +index 17d47bd..0000000 +--- a/fs/yaffs2/yaffs_ecc.h ++++ /dev/null +@@ -1,44 +0,0 @@ +-/* +- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU Lesser General Public License version 2.1 as +- * published by the Free Software Foundation. +- * +- * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +- */ +- +-/* +- * This code implements the ECC algorithm used in SmartMedia. +- * +- * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. +- * The two unused bit are set to 1. +- * The ECC can correct single bit errors in a 256-byte page of data. +- * Thus, two such ECC blocks are used on a 512-byte NAND page. +- * +- */ +- +-#ifndef __YAFFS_ECC_H__ +-#define __YAFFS_ECC_H__ +- +-struct yaffs_ecc_other { +- unsigned char col_parity; +- unsigned line_parity; +- unsigned line_parity_prime; +-}; +- +-void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc); +-int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc, +- const unsigned char *test_ecc); +- +-void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes, +- struct yaffs_ecc_other *ecc); +-int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes, +- struct yaffs_ecc_other *read_ecc, +- const struct yaffs_ecc_other *test_ecc); +-#endif +diff --git a/fs/yaffs2/yaffs_getblockinfo.h b/fs/yaffs2/yaffs_getblockinfo.h +deleted file mode 100644 +index 8fd0802..0000000 +--- a/fs/yaffs2/yaffs_getblockinfo.h ++++ /dev/null +@@ -1,35 +0,0 @@ +-/* +- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU Lesser General Public License version 2.1 as +- * published by the Free Software Foundation. +- * +- * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +- */ +- +-#ifndef __YAFFS_GETBLOCKINFO_H__ +-#define __YAFFS_GETBLOCKINFO_H__ +- +-#include "yaffs_guts.h" +-#include "yaffs_trace.h" +- +-/* Function to manipulate block info */ +-static inline struct yaffs_block_info *yaffs_get_block_info(struct yaffs_dev +- *dev, int blk) +-{ +- if (blk < dev->internal_start_block || blk > dev->internal_end_block) { +- yaffs_trace(YAFFS_TRACE_ERROR, +- "**>> yaffs: get_block_info block %d is not valid", +- blk); +- BUG(); +- } +- return &dev->block_info[blk - dev->internal_start_block]; +-} +- +-#endif +diff --git a/fs/yaffs2/yaffs_guts.c b/fs/yaffs2/yaffs_guts.c +deleted file mode 100644 +index 9f6b409..0000000 +--- a/fs/yaffs2/yaffs_guts.c ++++ /dev/null +@@ -1,5059 +0,0 @@ +-/* +- * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * 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 "yportenv.h" +-#include "yaffs_trace.h" +- +-#include "yaffs_guts.h" +-#include "yaffs_getblockinfo.h" +-#include "yaffs_tagscompat.h" +-#include "yaffs_tagsmarshall.h" +-#include "yaffs_nand.h" +-#include "yaffs_yaffs1.h" +-#include "yaffs_yaffs2.h" +-#include "yaffs_bitmap.h" +-#include "yaffs_verify.h" +-#include "yaffs_nand.h" +-#include "yaffs_packedtags2.h" +-#include "yaffs_nameval.h" +-#include "yaffs_allocator.h" +-#include "yaffs_attribs.h" +-#include "yaffs_summary.h" +- +-/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */ +-#define YAFFS_GC_GOOD_ENOUGH 2 +-#define YAFFS_GC_PASSIVE_THRESHOLD 4 +- +-#include "yaffs_ecc.h" +- +-/* Forward declarations */ +- +-static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk, +- const u8 *buffer, int n_bytes, int use_reserve); +- +-static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name, +- int buffer_size); +- +-/* Function to calculate chunk and offset */ +- +-void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr, +- int *chunk_out, u32 *offset_out) +-{ +- int chunk; +- u32 offset; +- +- chunk = (u32) (addr >> dev->chunk_shift); +- +- if (dev->chunk_div == 1) { +- /* easy power of 2 case */ +- offset = (u32) (addr & dev->chunk_mask); +- } else { +- /* Non power-of-2 case */ +- +- loff_t chunk_base; +- +- chunk /= dev->chunk_div; +- +- chunk_base = ((loff_t) chunk) * dev->data_bytes_per_chunk; +- offset = (u32) (addr - chunk_base); +- } +- +- *chunk_out = chunk; +- *offset_out = offset; +-} +- +-/* Function to return the number of shifts for a power of 2 greater than or +- * equal to the given number +- * Note we don't try to cater for all possible numbers and this does not have to +- * be hellishly efficient. +- */ +- +-static inline u32 calc_shifts_ceiling(u32 x) +-{ +- int extra_bits; +- int shifts; +- +- shifts = extra_bits = 0; +- +- while (x > 1) { +- if (x & 1) +- extra_bits++; +- x >>= 1; +- shifts++; +- } +- +- if (extra_bits) +- shifts++; +- +- return shifts; +-} +- +-/* Function to return the number of shifts to get a 1 in bit 0 +- */ +- +-static inline u32 calc_shifts(u32 x) +-{ +- u32 shifts; +- +- shifts = 0; +- +- if (!x) +- return 0; +- +- while (!(x & 1)) { +- x >>= 1; +- shifts++; +- } +- +- return shifts; +-} +- +-/* +- * Temporary buffer manipulations. +- */ +- +-static int yaffs_init_tmp_buffers(struct yaffs_dev *dev) +-{ +- int i; +- u8 *buf = (u8 *) 1; +- +- memset(dev->temp_buffer, 0, sizeof(dev->temp_buffer)); +- +- for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) { +- dev->temp_buffer[i].in_use = 0; +- buf = kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS); +- dev->temp_buffer[i].buffer = buf; +- } +- +- return buf ? YAFFS_OK : YAFFS_FAIL; +-} +- +-u8 *yaffs_get_temp_buffer(struct yaffs_dev * dev) +-{ +- int i; +- +- dev->temp_in_use++; +- if (dev->temp_in_use > dev->max_temp) +- dev->max_temp = dev->temp_in_use; +- +- for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { +- if (dev->temp_buffer[i].in_use == 0) { +- dev->temp_buffer[i].in_use = 1; +- return dev->temp_buffer[i].buffer; +- } +- } +- +- yaffs_trace(YAFFS_TRACE_BUFFERS, "Out of temp buffers"); +- /* +- * If we got here then we have to allocate an unmanaged one +- * This is not good. +- */ +- +- dev->unmanaged_buffer_allocs++; +- return kmalloc(dev->data_bytes_per_chunk, GFP_NOFS); +- +-} +- +-void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer) +-{ +- int i; +- +- dev->temp_in_use--; +- +- for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { +- if (dev->temp_buffer[i].buffer == buffer) { +- dev->temp_buffer[i].in_use = 0; +- return; +- } +- } +- +- if (buffer) { +- /* assume it is an unmanaged one. */ +- yaffs_trace(YAFFS_TRACE_BUFFERS, +- "Releasing unmanaged temp buffer"); +- kfree(buffer); +- dev->unmanaged_buffer_deallocs++; +- } +- +-} +- +-/* +- * Functions for robustisizing TODO +- * +- */ +- +-static void yaffs_handle_chunk_wr_ok(struct yaffs_dev *dev, int nand_chunk, +- const u8 *data, +- const struct yaffs_ext_tags *tags) +-{ +- (void) dev; +- (void) nand_chunk; +- (void) data; +- (void) tags; +-} +- +-static void yaffs_handle_chunk_update(struct yaffs_dev *dev, int nand_chunk, +- const struct yaffs_ext_tags *tags) +-{ +- (void) dev; +- (void) nand_chunk; +- (void) tags; +-} +- +-void yaffs_handle_chunk_error(struct yaffs_dev *dev, +- struct yaffs_block_info *bi) +-{ +- if (!bi->gc_prioritise) { +- bi->gc_prioritise = 1; +- dev->has_pending_prioritised_gc = 1; +- bi->chunk_error_strikes++; +- +- if (bi->chunk_error_strikes > 3) { +- bi->needs_retiring = 1; /* Too many stikes, so retire */ +- yaffs_trace(YAFFS_TRACE_ALWAYS, +- "yaffs: Block struck out"); +- +- } +- } +-} +- +-static void yaffs_handle_chunk_wr_error(struct yaffs_dev *dev, int nand_chunk, +- int erased_ok) +-{ +- int flash_block = nand_chunk / dev->param.chunks_per_block; +- struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block); +- +- yaffs_handle_chunk_error(dev, bi); +- +- if (erased_ok) { +- /* Was an actual write failure, +- * so mark the block for retirement.*/ +- bi->needs_retiring = 1; +- yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, +- "**>> Block %d needs retiring", flash_block); +- } +- +- /* Delete the chunk */ +- yaffs_chunk_del(dev, nand_chunk, 1, __LINE__); +- yaffs_skip_rest_of_block(dev); +-} +- +-/* +- * Verification code +- */ +- +-/* +- * Simple hash function. Needs to have a reasonable spread +- */ +- +-static inline int yaffs_hash_fn(int n) +-{ +- if (n < 0) +- n = -n; +- return n % YAFFS_NOBJECT_BUCKETS; +-} +- +-/* +- * Access functions to useful fake objects. +- * Note that root might have a presence in NAND if permissions are set. +- */ +- +-struct yaffs_obj *yaffs_root(struct yaffs_dev *dev) +-{ +- return dev->root_dir; +-} +- +-struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev) +-{ +- return dev->lost_n_found; +-} +- +-/* +- * Erased NAND checking functions +- */ +- +-int yaffs_check_ff(u8 *buffer, int n_bytes) +-{ +- /* Horrible, slow implementation */ +- while (n_bytes--) { +- if (*buffer != 0xff) +- return 0; +- buffer++; +- } +- return 1; +-} +- +-static int yaffs_check_chunk_erased(struct yaffs_dev *dev, int nand_chunk) +-{ +- int retval = YAFFS_OK; +- u8 *data = yaffs_get_temp_buffer(dev); +- struct yaffs_ext_tags tags; +- int result; +- +- result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, data, &tags); +- +- if (tags.ecc_result > YAFFS_ECC_RESULT_NO_ERROR) +- retval = YAFFS_FAIL; +- +- if (!yaffs_check_ff(data, dev->data_bytes_per_chunk) || +- tags.chunk_used) { +- yaffs_trace(YAFFS_TRACE_NANDACCESS, +- "Chunk %d not erased", nand_chunk); +- retval = YAFFS_FAIL; +- } +- +- yaffs_release_temp_buffer(dev, data); +- +- return retval; +- +-} +- +-static int yaffs_verify_chunk_written(struct yaffs_dev *dev, +- int nand_chunk, +- const u8 *data, +- struct yaffs_ext_tags *tags) +-{ +- int retval = YAFFS_OK; +- struct yaffs_ext_tags temp_tags; +- u8 *buffer = yaffs_get_temp_buffer(dev); +- int result; +- +- result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, buffer, &temp_tags); +- if (memcmp(buffer, data, dev->data_bytes_per_chunk) || +- temp_tags.obj_id != tags->obj_id || +- temp_tags.chunk_id != tags->chunk_id || +- temp_tags.n_bytes != tags->n_bytes) +- retval = YAFFS_FAIL; +- +- yaffs_release_temp_buffer(dev, buffer); +- +- return retval; +-} +- +- +-int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks) +-{ +- int reserved_chunks; +- int reserved_blocks = dev->param.n_reserved_blocks; +- int checkpt_blocks; +- +- checkpt_blocks = yaffs_calc_checkpt_blocks_required(dev); +- +- reserved_chunks = +- (reserved_blocks + checkpt_blocks) * dev->param.chunks_per_block; +- +- return (dev->n_free_chunks > (reserved_chunks + n_chunks)); +-} +- +-static int yaffs_find_alloc_block(struct yaffs_dev *dev) +-{ +- int i; +- struct yaffs_block_info *bi; +- +- if (dev->n_erased_blocks < 1) { +- /* Hoosterman we've got a problem. +- * Can't get space to gc +- */ +- yaffs_trace(YAFFS_TRACE_ERROR, +- "yaffs tragedy: no more erased blocks"); +- +- return -1; +- } +- +- /* Find an empty block. */ +- +- for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { +- dev->alloc_block_finder++; +- if (dev->alloc_block_finder < dev->internal_start_block +- || dev->alloc_block_finder > dev->internal_end_block) { +- dev->alloc_block_finder = dev->internal_start_block; +- } +- +- bi = yaffs_get_block_info(dev, dev->alloc_block_finder); +- +- if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) { +- bi->block_state = YAFFS_BLOCK_STATE_ALLOCATING; +- dev->seq_number++; +- bi->seq_number = dev->seq_number; +- dev->n_erased_blocks--; +- yaffs_trace(YAFFS_TRACE_ALLOCATE, +- "Allocated block %d, seq %d, %d left" , +- dev->alloc_block_finder, dev->seq_number, +- dev->n_erased_blocks); +- return dev->alloc_block_finder; +- } +- } +- +- yaffs_trace(YAFFS_TRACE_ALWAYS, +- "yaffs tragedy: no more erased blocks, but there should have been %d", +- dev->n_erased_blocks); +- +- return -1; +-} +- +-static int yaffs_alloc_chunk(struct yaffs_dev *dev, int use_reserver, +- struct yaffs_block_info **block_ptr) +-{ +- int ret_val; +- struct yaffs_block_info *bi; +- +- if (dev->alloc_block < 0) { +- /* Get next block to allocate off */ +- dev->alloc_block = yaffs_find_alloc_block(dev); +- dev->alloc_page = 0; +- } +- +- if (!use_reserver && !yaffs_check_alloc_available(dev, 1)) { +- /* No space unless we're allowed to use the reserve. */ +- return -1; +- } +- +- if (dev->n_erased_blocks < dev->param.n_reserved_blocks +- && dev->alloc_page == 0) +- yaffs_trace(YAFFS_TRACE_ALLOCATE, "Allocating reserve"); +- +- /* Next page please.... */ +- if (dev->alloc_block >= 0) { +- bi = yaffs_get_block_info(dev, dev->alloc_block); +- +- ret_val = (dev->alloc_block * dev->param.chunks_per_block) + +- dev->alloc_page; +- bi->pages_in_use++; +- yaffs_set_chunk_bit(dev, dev->alloc_block, dev->alloc_page); +- +- dev->alloc_page++; +- +- dev->n_free_chunks--; +- +- /* If the block is full set the state to full */ +- if (dev->alloc_page >= dev->param.chunks_per_block) { +- bi->block_state = YAFFS_BLOCK_STATE_FULL; +- dev->alloc_block = -1; +- } +- +- if (block_ptr) +- *block_ptr = bi; +- +- return ret_val; +- } +- +- yaffs_trace(YAFFS_TRACE_ERROR, +- "!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!"); +- +- return -1; +-} +- +-static int yaffs_get_erased_chunks(struct yaffs_dev *dev) +-{ +- int n; +- +- n = dev->n_erased_blocks * dev->param.chunks_per_block; +- +- if (dev->alloc_block > 0) +- n += (dev->param.chunks_per_block - dev->alloc_page); +- +- return n; +- +-} +- +-/* +- * yaffs_skip_rest_of_block() skips over the rest of the allocation block +- * if we don't want to write to it. +- */ +-void yaffs_skip_rest_of_block(struct yaffs_dev *dev) +-{ +- struct yaffs_block_info *bi; +- +- if (dev->alloc_block > 0) { +- bi = yaffs_get_block_info(dev, dev->alloc_block); +- if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) { +- bi->block_state = YAFFS_BLOCK_STATE_FULL; +- dev->alloc_block = -1; +- } +- } +-} +- +-static int yaffs_write_new_chunk(struct yaffs_dev *dev, +- const u8 *data, +- struct yaffs_ext_tags *tags, int use_reserver) +-{ +- int attempts = 0; +- int write_ok = 0; +- int chunk; +- +- yaffs2_checkpt_invalidate(dev); +- +- do { +- struct yaffs_block_info *bi = 0; +- int erased_ok = 0; +- +- chunk = yaffs_alloc_chunk(dev, use_reserver, &bi); +- if (chunk < 0) { +- /* no space */ +- break; +- } +- +- /* First check this chunk is erased, if it needs +- * checking. The checking policy (unless forced +- * always on) is as follows: +- * +- * Check the first page we try to write in a block. +- * If the check passes then we don't need to check any +- * more. If the check fails, we check again... +- * If the block has been erased, we don't need to check. +- * +- * However, if the block has been prioritised for gc, +- * then we think there might be something odd about +- * this block and stop using it. +- * +- * Rationale: We should only ever see chunks that have +- * not been erased if there was a partially written +- * chunk due to power loss. This checking policy should +- * catch that case with very few checks and thus save a +- * lot of checks that are most likely not needed. +- * +- * Mods to the above +- * If an erase check fails or the write fails we skip the +- * rest of the block. +- */ +- +- /* let's give it a try */ +- attempts++; +- +- if (dev->param.always_check_erased) +- bi->skip_erased_check = 0; +- +- if (!bi->skip_erased_check) { +- erased_ok = yaffs_check_chunk_erased(dev, chunk); +- if (erased_ok != YAFFS_OK) { +- yaffs_trace(YAFFS_TRACE_ERROR, +- "**>> yaffs chunk %d was not erased", +- chunk); +- +- /* If not erased, delete this one, +- * skip rest of block and +- * try another chunk */ +- yaffs_chunk_del(dev, chunk, 1, __LINE__); +- yaffs_skip_rest_of_block(dev); +- continue; +- } +- } +- +- write_ok = yaffs_wr_chunk_tags_nand(dev, chunk, data, tags); +- +- if (!bi->skip_erased_check) +- write_ok = +- yaffs_verify_chunk_written(dev, chunk, data, tags); +- +- if (write_ok != YAFFS_OK) { +- /* Clean up aborted write, skip to next block and +- * try another chunk */ +- yaffs_handle_chunk_wr_error(dev, chunk, erased_ok); +- continue; +- } +- +- bi->skip_erased_check = 1; +- +- /* Copy the data into the robustification buffer */ +- yaffs_handle_chunk_wr_ok(dev, chunk, data, tags); +- +- } while (write_ok != YAFFS_OK && +- (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts)); +- +- if (!write_ok) +- chunk = -1; +- +- if (attempts > 1) { +- yaffs_trace(YAFFS_TRACE_ERROR, +- "**>> yaffs write required %d attempts", +- attempts); +- dev->n_retried_writes += (attempts - 1); +- } +- +- return chunk; +-} +- +-/* +- * Block retiring for handling a broken block. +- */ +- +-static void yaffs_retire_block(struct yaffs_dev *dev, int flash_block) +-{ +- struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block); +- +- yaffs2_checkpt_invalidate(dev); +- +- yaffs2_clear_oldest_dirty_seq(dev, bi); +- +- if (yaffs_mark_bad(dev, flash_block) != YAFFS_OK) { +- if (yaffs_erase_block(dev, flash_block) != YAFFS_OK) { +- yaffs_trace(YAFFS_TRACE_ALWAYS, +- "yaffs: Failed to mark bad and erase block %d", +- flash_block); +- } else { +- struct yaffs_ext_tags tags; +- int chunk_id = +- flash_block * dev->param.chunks_per_block; +- +- u8 *buffer = yaffs_get_temp_buffer(dev); +- +- memset(buffer, 0xff, dev->data_bytes_per_chunk); +- memset(&tags, 0, sizeof(tags)); +- tags.seq_number = YAFFS_SEQUENCE_BAD_BLOCK; +- if (dev->tagger.write_chunk_tags_fn(dev, chunk_id - +- dev->chunk_offset, +- buffer, +- &tags) != YAFFS_OK) +- yaffs_trace(YAFFS_TRACE_ALWAYS, +- "yaffs: Failed to write bad block marker to block %d", +- flash_block); +- +- yaffs_release_temp_buffer(dev, buffer); +- } +- } +- +- bi->block_state = YAFFS_BLOCK_STATE_DEAD; +- bi->gc_prioritise = 0; +- bi->needs_retiring = 0; +- +- dev->n_retired_blocks++; +-} +- +-/*---------------- Name handling functions ------------*/ +- +-static u16 yaffs_calc_name_sum(const YCHAR *name) +-{ +- u16 sum = 0; +- u16 i = 1; +- +- if (!name) +- return 0; +- +- while ((*name) && i < (YAFFS_MAX_NAME_LENGTH / 2)) { +- +- /* 0x1f mask is case insensitive */ +- sum += ((*name) & 0x1f) * i; +- i++; +- name++; +- } +- return sum; +-} +- +- +-void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR * name) +-{ +- memset(obj->short_name, 0, sizeof(obj->short_name)); +- +- if (name && !name[0]) { +- yaffs_fix_null_name(obj, obj->short_name, +- YAFFS_SHORT_NAME_LENGTH); +- name = obj->short_name; +- } else if (name && +- strnlen(name, YAFFS_SHORT_NAME_LENGTH + 1) <= +- YAFFS_SHORT_NAME_LENGTH) { +- strcpy(obj->short_name, name); +- } +- +- obj->sum = yaffs_calc_name_sum(name); +-} +- +-void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj, +- const struct yaffs_obj_hdr *oh) +-{ +-#ifdef CONFIG_YAFFS_AUTO_UNICODE +- YCHAR tmp_name[YAFFS_MAX_NAME_LENGTH + 1]; +- memset(tmp_name, 0, sizeof(tmp_name)); +- yaffs_load_name_from_oh(obj->my_dev, tmp_name, oh->name, +- YAFFS_MAX_NAME_LENGTH + 1); +- yaffs_set_obj_name(obj, tmp_name); +-#else +- yaffs_set_obj_name(obj, oh->name); +-#endif +-} +- +-loff_t yaffs_max_file_size(struct yaffs_dev *dev) +-{ +- if(sizeof(loff_t) < 8) +- return YAFFS_MAX_FILE_SIZE_32; +- else +- return ((loff_t) YAFFS_MAX_CHUNK_ID) * dev->data_bytes_per_chunk; +-} +- +-/*-------------------- TNODES ------------------- +- +- * List of spare tnodes +- * The list is hooked together using the first pointer +- * in the tnode. +- */ +- +-struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev) +-{ +- struct yaffs_tnode *tn = yaffs_alloc_raw_tnode(dev); +- +- if (tn) { +- memset(tn, 0, dev->tnode_size); +- dev->n_tnodes++; +- } +- +- dev->checkpoint_blocks_required = 0; /* force recalculation */ +- +- return tn; +-} +- +-/* FreeTnode frees up a tnode and puts it back on the free list */ +-static void yaffs_free_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn) +-{ +- yaffs_free_raw_tnode(dev, tn); +- dev->n_tnodes--; +- dev->checkpoint_blocks_required = 0; /* force recalculation */ +-} +- +-static void yaffs_deinit_tnodes_and_objs(struct yaffs_dev *dev) +-{ +- yaffs_deinit_raw_tnodes_and_objs(dev); +- dev->n_obj = 0; +- dev->n_tnodes = 0; +-} +- +-static void yaffs_load_tnode_0(struct yaffs_dev *dev, struct yaffs_tnode *tn, +- unsigned pos, unsigned val) +-{ +- u32 *map = (u32 *) tn; +- u32 bit_in_map; +- u32 bit_in_word; +- u32 word_in_map; +- u32 mask; +- +- pos &= YAFFS_TNODES_LEVEL0_MASK; +- val >>= dev->chunk_grp_bits; +- +- bit_in_map = pos * dev->tnode_width; +- word_in_map = bit_in_map / 32; +- bit_in_word = bit_in_map & (32 - 1); +- +- mask = dev->tnode_mask << bit_in_word; +- +- map[word_in_map] &= ~mask; +- map[word_in_map] |= (mask & (val << bit_in_word)); +- +- if (dev->tnode_width > (32 - bit_in_word)) { +- bit_in_word = (32 - bit_in_word); +- word_in_map++; +- mask = +- dev->tnode_mask >> bit_in_word; +- map[word_in_map] &= ~mask; +- map[word_in_map] |= (mask & (val >> bit_in_word)); +- } +-} +- +-u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn, +- unsigned pos) +-{ +- u32 *map = (u32 *) tn; +- u32 bit_in_map; +- u32 bit_in_word; +- u32 word_in_map; +- u32 val; +- +- pos &= YAFFS_TNODES_LEVEL0_MASK; +- +- bit_in_map = pos * dev->tnode_width; +- word_in_map = bit_in_map / 32; +- bit_in_word = bit_in_map & (32 - 1); +- +- val = map[word_in_map] >> bit_in_word; +- +- if (dev->tnode_width > (32 - bit_in_word)) { +- bit_in_word = (32 - bit_in_word); +- word_in_map++; +- val |= (map[word_in_map] << bit_in_word); +- } +- +- val &= dev->tnode_mask; +- val <<= dev->chunk_grp_bits; +- +- return val; +-} +- +-/* ------------------- End of individual tnode manipulation -----------------*/ +- +-/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------ +- * The look up tree is represented by the top tnode and the number of top_level +- * in the tree. 0 means only the level 0 tnode is in the tree. +- */ +- +-/* FindLevel0Tnode finds the level 0 tnode, if one exists. */ +-struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev, +- struct yaffs_file_var *file_struct, +- u32 chunk_id) +-{ +- struct yaffs_tnode *tn = file_struct->top; +- u32 i; +- int required_depth; +- int level = file_struct->top_level; +- +- (void) dev; +- +- /* Check sane level and chunk Id */ +- if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL) +- return NULL; +- +- if (chunk_id > YAFFS_MAX_CHUNK_ID) +- return NULL; +- +- /* First check we're tall enough (ie enough top_level) */ +- +- i = chunk_id >> YAFFS_TNODES_LEVEL0_BITS; +- required_depth = 0; +- while (i) { +- i >>= YAFFS_TNODES_INTERNAL_BITS; +- required_depth++; +- } +- +- if (required_depth > file_struct->top_level) +- return NULL; /* Not tall enough, so we can't find it */ +- +- /* Traverse down to level 0 */ +- while (level > 0 && tn) { +- tn = tn->internal[(chunk_id >> +- (YAFFS_TNODES_LEVEL0_BITS + +- (level - 1) * +- YAFFS_TNODES_INTERNAL_BITS)) & +- YAFFS_TNODES_INTERNAL_MASK]; +- level--; +- } +- +- return tn; +-} +- +-/* add_find_tnode_0 finds the level 0 tnode if it exists, +- * otherwise first expands the tree. +- * This happens in two steps: +- * 1. If the tree isn't tall enough, then make it taller. +- * 2. Scan down the tree towards the level 0 tnode adding tnodes if required. +- * +- * Used when modifying the tree. +- * +- * If the tn argument is NULL, then a fresh tnode will be added otherwise the +- * specified tn will be plugged into the ttree. +- */ +- +-struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev, +- struct yaffs_file_var *file_struct, +- u32 chunk_id, +- struct yaffs_tnode *passed_tn) +-{ +- int required_depth; +- int i; +- int l; +- struct yaffs_tnode *tn; +- u32 x; +- +- /* Check sane level and page Id */ +- if (file_struct->top_level < 0 || +- file_struct->top_level > YAFFS_TNODES_MAX_LEVEL) +- return NULL; +- +- if (chunk_id > YAFFS_MAX_CHUNK_ID) +- return NULL; +- +- /* First check we're tall enough (ie enough top_level) */ +- +- x = chunk_id >> YAFFS_TNODES_LEVEL0_BITS; +- required_depth = 0; +- while (x) { +- x >>= YAFFS_TNODES_INTERNAL_BITS; +- required_depth++; +- } +- +- if (required_depth > file_struct->top_level) { +- /* Not tall enough, gotta make the tree taller */ +- for (i = file_struct->top_level; i < required_depth; i++) { +- +- tn = yaffs_get_tnode(dev); +- +- if (tn) { +- tn->internal[0] = file_struct->top; +- file_struct->top = tn; +- file_struct->top_level++; +- } else { +- yaffs_trace(YAFFS_TRACE_ERROR, +- "yaffs: no more tnodes"); +- return NULL; +- } +- } +- } +- +- /* Traverse down to level 0, adding anything we need */ +- +- l = file_struct->top_level; +- tn = file_struct->top; +- +- if (l > 0) { +- while (l > 0 && tn) { +- x = (chunk_id >> +- (YAFFS_TNODES_LEVEL0_BITS + +- (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) & +- YAFFS_TNODES_INTERNAL_MASK; +- +- if ((l > 1) && !tn->internal[x]) { +- /* Add missing non-level-zero tnode */ +- tn->internal[x] = yaffs_get_tnode(dev); +- if (!tn->internal[x]) +- return NULL; +- } else if (l == 1) { +- /* Looking from level 1 at level 0 */ +- if (passed_tn) { +- /* If we already have one, release it */ +- if (tn->internal[x]) +- yaffs_free_tnode(dev, +- tn->internal[x]); +- tn->internal[x] = passed_tn; +- +- } else if (!tn->internal[x]) { +- /* Don't have one, none passed in */ +- tn->internal[x] = yaffs_get_tnode(dev); +- if (!tn->internal[x]) +- return NULL; +- } +- } +- +- tn = tn->internal[x]; +- l--; +- } +- } else { +- /* top is level 0 */ +- if (passed_tn) { +- memcpy(tn, passed_tn, +- (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8); +- yaffs_free_tnode(dev, passed_tn); +- } +- } +- +- return tn; +-} +- +-static int yaffs_tags_match(const struct yaffs_ext_tags *tags, int obj_id, +- int chunk_obj) +-{ +- return (tags->chunk_id == chunk_obj && +- tags->obj_id == obj_id && +- !tags->is_deleted) ? 1 : 0; +- +-} +- +-static int yaffs_find_chunk_in_group(struct yaffs_dev *dev, int the_chunk, +- struct yaffs_ext_tags *tags, int obj_id, +- int inode_chunk) +-{ +- int j; +- +- for (j = 0; the_chunk && j < dev->chunk_grp_size; j++) { +- if (yaffs_check_chunk_bit +- (dev, the_chunk / dev->param.chunks_per_block, +- the_chunk % dev->param.chunks_per_block)) { +- +- if (dev->chunk_grp_size == 1) +- return the_chunk; +- else { +- yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL, +- tags); +- if (yaffs_tags_match(tags, +- obj_id, inode_chunk)) { +- /* found it; */ +- return the_chunk; +- } +- } +- } +- the_chunk++; +- } +- return -1; +-} +- +-static int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk, +- struct yaffs_ext_tags *tags) +-{ +- /*Get the Tnode, then get the level 0 offset chunk offset */ +- struct yaffs_tnode *tn; +- int the_chunk = -1; +- struct yaffs_ext_tags local_tags; +- int ret_val = -1; +- struct yaffs_dev *dev = in->my_dev; +- +- if (!tags) { +- /* Passed a NULL, so use our own tags space */ +- tags = &local_tags; +- } +- +- tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk); +- +- if (!tn) +- return ret_val; +- +- the_chunk = yaffs_get_group_base(dev, tn, inode_chunk); +- +- ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id, +- inode_chunk); +- return ret_val; +-} +- +-static int yaffs_find_del_file_chunk(struct yaffs_obj *in, int inode_chunk, +- struct yaffs_ext_tags *tags) +-{ +- /* Get the Tnode, then get the level 0 offset chunk offset */ +- struct yaffs_tnode *tn; +- int the_chunk = -1; +- struct yaffs_ext_tags local_tags; +- struct yaffs_dev *dev = in->my_dev; +- int ret_val = -1; +- +- if (!tags) { +- /* Passed a NULL, so use our own tags space */ +- tags = &local_tags; +- } +- +- tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk); +- +- if (!tn) +- return ret_val; +- +- the_chunk = yaffs_get_group_base(dev, tn, inode_chunk); +- +- ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id, +- inode_chunk); +- +- /* Delete the entry in the filestructure (if found) */ +- if (ret_val != -1) +- yaffs_load_tnode_0(dev, tn, inode_chunk, 0); +- +- return ret_val; +-} +- +-int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk, +- int nand_chunk, int in_scan) +-{ +- /* NB in_scan is zero unless scanning. +- * For forward scanning, in_scan is > 0; +- * for backward scanning in_scan is < 0 +- * +- * nand_chunk = 0 is a dummy insert to make sure the tnodes are there. +- */ +- +- struct yaffs_tnode *tn; +- struct yaffs_dev *dev = in->my_dev; +- int existing_cunk; +- struct yaffs_ext_tags existing_tags; +- struct yaffs_ext_tags new_tags; +- unsigned existing_serial, new_serial; +- +- if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) { +- /* Just ignore an attempt at putting a chunk into a non-file +- * during scanning. +- * If it is not during Scanning then something went wrong! +- */ +- if (!in_scan) { +- yaffs_trace(YAFFS_TRACE_ERROR, +- "yaffs tragedy:attempt to put data chunk into a non-file" +- ); +- BUG(); +- } +- +- yaffs_chunk_del(dev, nand_chunk, 1, __LINE__); +- return YAFFS_OK; +- } +- +- tn = yaffs_add_find_tnode_0(dev, +- &in->variant.file_variant, +- inode_chunk, NULL); +- if (!tn) +- return YAFFS_FAIL; +- +- if (!nand_chunk) +- /* Dummy insert, bail now */ +- return YAFFS_OK; +- +- existing_cunk = yaffs_get_group_base(dev, tn, inode_chunk); +- +- if (in_scan != 0) { +- /* If we're scanning then we need to test for duplicates +- * NB This does not need to be efficient since it should only +- * happen when the power fails during a write, then only one +- * chunk should ever be affected. +- * +- * Correction for YAFFS2: This could happen quite a lot and we +- * need to think about efficiency! TODO +- * Update: For backward scanning we don't need to re-read tags +- * so this is quite cheap. +- */ +- +- if (existing_cunk > 0) { +- /* NB Right now existing chunk will not be real +- * chunk_id if the chunk group size > 1 +- * thus we have to do a FindChunkInFile to get the +- * real chunk id. +- * +- * We have a duplicate now we need to decide which +- * one to use: +- * +- * Backwards scanning YAFFS2: The old one is what +- * we use, dump the new one. +- * YAFFS1: Get both sets of tags and compare serial +- * numbers. +- */ +- +- if (in_scan > 0) { +- /* Only do this for forward scanning */ +- yaffs_rd_chunk_tags_nand(dev, +- nand_chunk, +- NULL, &new_tags); +- +- /* Do a proper find */ +- existing_cunk = +- yaffs_find_chunk_in_file(in, inode_chunk, +- &existing_tags); +- } +- +- if (existing_cunk <= 0) { +- /*Hoosterman - how did this happen? */ +- +- yaffs_trace(YAFFS_TRACE_ERROR, +- "yaffs tragedy: existing chunk < 0 in scan" +- ); +- +- } +- +- /* NB The deleted flags should be false, otherwise +- * the chunks will not be loaded during a scan +- */ +- +- if (in_scan > 0) { +- new_serial = new_tags.serial_number; +- existing_serial = existing_tags.serial_number; +- } +- +- if ((in_scan > 0) && +- (existing_cunk <= 0 || +- ((existing_serial + 1) & 3) == new_serial)) { +- /* Forward scanning. +- * Use new +- * Delete the old one and drop through to +- * update the tnode +- */ +- yaffs_chunk_del(dev, existing_cunk, 1, +- __LINE__); +- } else { +- /* Backward scanning or we want to use the +- * existing one +- * Delete the new one and return early so that +- * the tnode isn't changed +- */ +- yaffs_chunk_del(dev, nand_chunk, 1, __LINE__); +- return YAFFS_OK; +- } +- } +- +- } +- +- if (existing_cunk == 0) +- in->n_data_chunks++; +- +- yaffs_load_tnode_0(dev, tn, inode_chunk, nand_chunk); +- +- return YAFFS_OK; +-} +- +-static void yaffs_soft_del_chunk(struct yaffs_dev *dev, int chunk) +-{ +- struct yaffs_block_info *the_block; +- unsigned block_no; +- +- yaffs_trace(YAFFS_TRACE_DELETION, "soft delete chunk %d", chunk); +- +- block_no = chunk / dev->param.chunks_per_block; +- the_block = yaffs_get_block_info(dev, block_no); +- if (the_block) { +- the_block->soft_del_pages++; +- dev->n_free_chunks++; +- yaffs2_update_oldest_dirty_seq(dev, block_no, the_block); +- } +-} +- +-/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all +- * the chunks in the file. +- * All soft deleting does is increment the block's softdelete count and pulls +- * the chunk out of the tnode. +- * Thus, essentially this is the same as DeleteWorker except that the chunks +- * are soft deleted. +- */ +- +-static int yaffs_soft_del_worker(struct yaffs_obj *in, struct yaffs_tnode *tn, +- u32 level, int chunk_offset) +-{ +- int i; +- int the_chunk; +- int all_done = 1; +- struct yaffs_dev *dev = in->my_dev; +- +- if (!tn) +- return 1; +- +- if (level > 0) { +- for (i = YAFFS_NTNODES_INTERNAL - 1; +- all_done && i >= 0; +- i--) { +- if (tn->internal[i]) { +- all_done = +- yaffs_soft_del_worker(in, +- tn->internal[i], +- level - 1, +- (chunk_offset << +- YAFFS_TNODES_INTERNAL_BITS) +- + i); +- if (all_done) { +- yaffs_free_tnode(dev, +- tn->internal[i]); +- tn->internal[i] = NULL; +- } else { +- /* Can this happen? */ +- } +- } +- } +- return (all_done) ? 1 : 0; +- } +- +- /* level 0 */ +- for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) { +- the_chunk = yaffs_get_group_base(dev, tn, i); +- if (the_chunk) { +- yaffs_soft_del_chunk(dev, the_chunk); +- yaffs_load_tnode_0(dev, tn, i, 0); +- } +- } +- return 1; +-} +- +-static void yaffs_remove_obj_from_dir(struct yaffs_obj *obj) +-{ +- struct yaffs_dev *dev = obj->my_dev; +- struct yaffs_obj *parent; +- +- yaffs_verify_obj_in_dir(obj); +- parent = obj->parent; +- +- yaffs_verify_dir(parent); +- +- if (dev && dev->param.remove_obj_fn) +- dev->param.remove_obj_fn(obj); +- +- list_del_init(&obj->siblings); +- obj->parent = NULL; +- +- yaffs_verify_dir(parent); +-} +- +-void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj) +-{ +- if (!directory) { +- yaffs_trace(YAFFS_TRACE_ALWAYS, +- "tragedy: Trying to add an object to a null pointer directory" +- ); +- BUG(); +- return; +- } +- if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { +- yaffs_trace(YAFFS_TRACE_ALWAYS, +- "tragedy: Trying to add an object to a non-directory" +- ); +- BUG(); +- } +- +- if (obj->siblings.prev == NULL) { +- /* Not initialised */ +- BUG(); +- } +- +- yaffs_verify_dir(directory); +- +- yaffs_remove_obj_from_dir(obj); +- +- /* Now add it */ +- list_add(&obj->siblings, &directory->variant.dir_variant.children); +- obj->parent = directory; +- +- if (directory == obj->my_dev->unlinked_dir +- || directory == obj->my_dev->del_dir) { +- obj->unlinked = 1; +- obj->my_dev->n_unlinked_files++; +- obj->rename_allowed = 0; +- } +- +- yaffs_verify_dir(directory); +- yaffs_verify_obj_in_dir(obj); +-} +- +-static int yaffs_change_obj_name(struct yaffs_obj *obj, +- struct yaffs_obj *new_dir, +- const YCHAR *new_name, int force, int shadows) +-{ +- int unlink_op; +- int del_op; +- struct yaffs_obj *existing_target; +- +- if (new_dir == NULL) +- new_dir = obj->parent; /* use the old directory */ +- +- if (new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { +- yaffs_trace(YAFFS_TRACE_ALWAYS, +- "tragedy: yaffs_change_obj_name: new_dir is not a directory" +- ); +- BUG(); +- } +- +- unlink_op = (new_dir == obj->my_dev->unlinked_dir); +- del_op = (new_dir == obj->my_dev->del_dir); +- +- existing_target = yaffs_find_by_name(new_dir, new_name); +- +- /* If the object is a file going into the unlinked directory, +- * then it is OK to just stuff it in since duplicate names are OK. +- * else only proceed if the new name does not exist and we're putting +- * it into a directory. +- */ +- if (!(unlink_op || del_op || force || +- shadows > 0 || !existing_target) || +- new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) +- return YAFFS_FAIL; +- +- yaffs_set_obj_name(obj, new_name); +- obj->dirty = 1; +- yaffs_add_obj_to_dir(new_dir, obj); +- +- if (unlink_op) +- obj->unlinked = 1; +- +- /* If it is a deletion then we mark it as a shrink for gc */ +- if (yaffs_update_oh(obj, new_name, 0, del_op, shadows, NULL) >= 0) +- return YAFFS_OK; +- +- return YAFFS_FAIL; +-} +- +-/*------------------------ Short Operations Cache ------------------------------ +- * In many situations where there is no high level buffering a lot of +- * reads might be short sequential reads, and a lot of writes may be short +- * sequential writes. eg. scanning/writing a jpeg file. +- * In these cases, a short read/write cache can provide a huge perfomance +- * benefit with dumb-as-a-rock code. +- * In Linux, the page cache provides read buffering and the short op cache +- * provides write buffering. +- * +- * There are a small number (~10) of cache chunks per device so that we don't +- * need a very intelligent search. +- */ +- +-static int yaffs_obj_cache_dirty(struct yaffs_obj *obj) +-{ +- struct yaffs_dev *dev = obj->my_dev; +- int i; +- struct yaffs_cache *cache; +- int n_caches = obj->my_dev->param.n_caches; +- +- for (i = 0; i < n_caches; i++) { +- cache = &dev->cache[i]; +- if (cache->object == obj && cache->dirty) +- return 1; +- } +- +- return 0; +-} +- +-static void yaffs_flush_file_cache(struct yaffs_obj *obj) +-{ +- struct yaffs_dev *dev = obj->my_dev; +- int lowest = -99; /* Stop compiler whining. */ +- int i; +- struct yaffs_cache *cache; +- int chunk_written = 0; +- int n_caches = obj->my_dev->param.n_caches; +- +- if (n_caches < 1) +- return; +- do { +- cache = NULL; +- +- /* Find the lowest dirty chunk for this object */ +- for (i = 0; i < n_caches; i++) { +- if (dev->cache[i].object == obj && +- dev->cache[i].dirty) { +- if (!cache || +- dev->cache[i].chunk_id < lowest) { +- cache = &dev->cache[i]; +- lowest = cache->chunk_id; +- } +- } +- } +- +- if (cache && !cache->locked) { +- /* Write it out and free it up */ +- chunk_written = +- yaffs_wr_data_obj(cache->object, +- cache->chunk_id, +- cache->data, +- cache->n_bytes, 1); +- cache->dirty = 0; +- cache->object = NULL; +- } +- } while (cache && chunk_written > 0); +- +- if (cache) +- /* Hoosterman, disk full while writing cache out. */ +- yaffs_trace(YAFFS_TRACE_ERROR, +- "yaffs tragedy: no space during cache write"); +-} +- +-/*yaffs_flush_whole_cache(dev) +- * +- * +- */ +- +-void yaffs_flush_whole_cache(struct yaffs_dev *dev) +-{ +- struct yaffs_obj *obj; +- int n_caches = dev->param.n_caches; +- int i; +- +- /* Find a dirty object in the cache and flush it... +- * until there are no further dirty objects. +- */ +- do { +- obj = NULL; +- for (i = 0; i < n_caches && !obj; i++) { +- if (dev->cache[i].object && dev->cache[i].dirty) +- obj = dev->cache[i].object; +- } +- if (obj) +- yaffs_flush_file_cache(obj); +- } while (obj); +- +-} +- +-/* Grab us a cache chunk for use. +- * First look for an empty one. +- * Then look for the least recently used non-dirty one. +- * Then look for the least recently used dirty one...., flush and look again. +- */ +-static struct yaffs_cache *yaffs_grab_chunk_worker(struct yaffs_dev *dev) +-{ +- int i; +- +- if (dev->param.n_caches > 0) { +- for (i = 0; i < dev->param.n_caches; i++) { +- if (!dev->cache[i].object) +- return &dev->cache[i]; +- } +- } +- return NULL; +-} +- +-static struct yaffs_cache *yaffs_grab_chunk_cache(struct yaffs_dev *dev) +-{ +- struct yaffs_cache *cache; +- struct yaffs_obj *the_obj; +- int usage; +- int i; +- int pushout; +- +- if (dev->param.n_caches < 1) +- return NULL; +- +- /* Try find a non-dirty one... */ +- +- cache = yaffs_grab_chunk_worker(dev); +- +- if (!cache) { +- /* They were all dirty, find the LRU object and flush +- * its cache, then find again. +- * NB what's here is not very accurate, +- * we actually flush the object with the LRU chunk. +- */ +- +- /* With locking we can't assume we can use entry zero, +- * Set the_obj to a valid pointer for Coverity. */ +- the_obj = dev->cache[0].object; +- usage = -1; +- cache = NULL; +- pushout = -1; +- +- for (i = 0; i < dev->param.n_caches; i++) { +- if (dev->cache[i].object && +- !dev->cache[i].locked && +- (dev->cache[i].last_use < usage || +- !cache)) { +- usage = dev->cache[i].last_use; +- the_obj = dev->cache[i].object; +- cache = &dev->cache[i]; +- pushout = i; +- } +- } +- +- if (!cache || cache->dirty) { +- /* Flush and try again */ +- yaffs_flush_file_cache(the_obj); +- cache = yaffs_grab_chunk_worker(dev); +- } +- } +- return cache; +-} +- +-/* Find a cached chunk */ +-static struct yaffs_cache *yaffs_find_chunk_cache(const struct yaffs_obj *obj, +- int chunk_id) +-{ +- struct yaffs_dev *dev = obj->my_dev; +- int i; +- +- if (dev->param.n_caches < 1) +- return NULL; +- +- for (i = 0; i < dev->param.n_caches; i++) { +- if (dev->cache[i].object == obj && +- dev->cache[i].chunk_id == chunk_id) { +- dev->cache_hits++; +- +- return &dev->cache[i]; +- } +- } +- return NULL; +-} +- +-/* Mark the chunk for the least recently used algorithym */ +-static void yaffs_use_cache(struct yaffs_dev *dev, struct yaffs_cache *cache, +- int is_write) +-{ +- int i; +- +- if (dev->param.n_caches < 1) +- return; +- +- if (dev->cache_last_use < 0 || +- dev->cache_last_use > 100000000) { +- /* Reset the cache usages */ +- for (i = 1; i < dev->param.n_caches; i++) +- dev->cache[i].last_use = 0; +- +- dev->cache_last_use = 0; +- } +- dev->cache_last_use++; +- cache->last_use = dev->cache_last_use; +- +- if (is_write) +- cache->dirty = 1; +-} +- +-/* Invalidate a single cache page. +- * Do this when a whole page gets written, +- * ie the short cache for this page is no longer valid. +- */ +-static void yaffs_invalidate_chunk_cache(struct yaffs_obj *object, int chunk_id) +-{ +- struct yaffs_cache *cache; +- +- if (object->my_dev->param.n_caches > 0) { +- cache = yaffs_find_chunk_cache(object, chunk_id); +- +- if (cache) +- cache->object = NULL; +- } +-} +- +-/* Invalidate all the cache pages associated with this object +- * Do this whenever ther file is deleted or resized. +- */ +-static void yaffs_invalidate_whole_cache(struct yaffs_obj *in) +-{ +- int i; +- struct yaffs_dev *dev = in->my_dev; +- +- if (dev->param.n_caches > 0) { +- /* Invalidate it. */ +- for (i = 0; i < dev->param.n_caches; i++) { +- if (dev->cache[i].object == in) +- dev->cache[i].object = NULL; +- } +- } +-} +- +-static void yaffs_unhash_obj(struct yaffs_obj *obj) +-{ +- int bucket; +- struct yaffs_dev *dev = obj->my_dev; +- +- /* If it is still linked into the bucket list, free from the list */ +- if (!list_empty(&obj->hash_link)) { +- list_del_init(&obj->hash_link); +- bucket = yaffs_hash_fn(obj->obj_id); +- dev->obj_bucket[bucket].count--; +- } +-} +- +-/* FreeObject frees up a Object and puts it back on the free list */ +-static void yaffs_free_obj(struct yaffs_obj *obj) +-{ +- struct yaffs_dev *dev; +- +- if (!obj) { +- BUG(); +- return; +- } +- dev = obj->my_dev; +- yaffs_trace(YAFFS_TRACE_OS, "FreeObject %p inode %p", +- obj, obj->my_inode); +- if (obj->parent) +- BUG(); +- if (!list_empty(&obj->siblings)) +- BUG(); +- +- if (obj->my_inode) { +- /* We're still hooked up to a cached inode. +- * Don't delete now, but mark for later deletion +- */ +- obj->defered_free = 1; +- return; +- } +- +- yaffs_unhash_obj(obj); +- +- yaffs_free_raw_obj(dev, obj); +- dev->n_obj--; +- dev->checkpoint_blocks_required = 0; /* force recalculation */ +-} +- +-void yaffs_handle_defered_free(struct yaffs_obj *obj) +-{ +- if (obj->defered_free) +- yaffs_free_obj(obj); +-} +- +-static int yaffs_generic_obj_del(struct yaffs_obj *in) +-{ +- /* Iinvalidate the file's data in the cache, without flushing. */ +- yaffs_invalidate_whole_cache(in); +- +- if (in->my_dev->param.is_yaffs2 && in->parent != in->my_dev->del_dir) { +- /* Move to unlinked directory so we have a deletion record */ +- yaffs_change_obj_name(in, in->my_dev->del_dir, _Y("deleted"), 0, +- 0); +- } +- +- yaffs_remove_obj_from_dir(in); +- yaffs_chunk_del(in->my_dev, in->hdr_chunk, 1, __LINE__); +- in->hdr_chunk = 0; +- +- yaffs_free_obj(in); +- return YAFFS_OK; +- +-} +- +-static void yaffs_soft_del_file(struct yaffs_obj *obj) +-{ +- if (!obj->deleted || +- obj->variant_type != YAFFS_OBJECT_TYPE_FILE || +- obj->soft_del) +- return; +- +- if (obj->n_data_chunks <= 0) { +- /* Empty file with no duplicate object headers, +- * just delete it immediately */ +- yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top); +- obj->variant.file_variant.top = NULL; +- yaffs_trace(YAFFS_TRACE_TRACING, +- "yaffs: Deleting empty file %d", +- obj->obj_id); +- yaffs_generic_obj_del(obj); +- } else { +- yaffs_soft_del_worker(obj, +- obj->variant.file_variant.top, +- obj->variant. +- file_variant.top_level, 0); +- obj->soft_del = 1; +- } +-} +- +-/* Pruning removes any part of the file structure tree that is beyond the +- * bounds of the file (ie that does not point to chunks). +- * +- * A file should only get pruned when its size is reduced. +- * +- * Before pruning, the chunks must be pulled from the tree and the +- * level 0 tnode entries must be zeroed out. +- * Could also use this for file deletion, but that's probably better handled +- * by a special case. +- * +- * This function is recursive. For levels > 0 the function is called again on +- * any sub-tree. For level == 0 we just check if the sub-tree has data. +- * If there is no data in a subtree then it is pruned. +- */ +- +-static struct yaffs_tnode *yaffs_prune_worker(struct yaffs_dev *dev, +- struct yaffs_tnode *tn, u32 level, +- int del0) +-{ +- int i; +- int has_data; +- +- if (!tn) +- return tn; +- +- has_data = 0; +- +- if (level > 0) { +- for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) { +- if (tn->internal[i]) { +- tn->internal[i] = +- yaffs_prune_worker(dev, +- tn->internal[i], +- level - 1, +- (i == 0) ? del0 : 1); +- } +- +- if (tn->internal[i]) +- has_data++; +- } +- } else { +- int tnode_size_u32 = dev->tnode_size / sizeof(u32); +- u32 *map = (u32 *) tn; +- +- for (i = 0; !has_data && i < tnode_size_u32; i++) { +- if (map[i]) +- has_data++; +- } +- } +- +- if (has_data == 0 && del0) { +- /* Free and return NULL */ +- yaffs_free_tnode(dev, tn); +- tn = NULL; +- } +- return tn; +-} +- +-static int yaffs_prune_tree(struct yaffs_dev *dev, +- struct yaffs_file_var *file_struct) +-{ +- int i; +- int has_data; +- int done = 0; +- struct yaffs_tnode *tn; +- +- if (file_struct->top_level < 1) +- return YAFFS_OK; +- +- file_struct->top = +- yaffs_prune_worker(dev, file_struct->top, file_struct->top_level, 0); +- +- /* Now we have a tree with all the non-zero branches NULL but +- * the height is the same as it was. +- * Let's see if we can trim internal tnodes to shorten the tree. +- * We can do this if only the 0th element in the tnode is in use +- * (ie all the non-zero are NULL) +- */ +- +- while (file_struct->top_level && !done) { +- tn = file_struct->top; +- +- has_data = 0; +- for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) { +- if (tn->internal[i]) +- has_data++; +- } +- +- if (!has_data) { +- file_struct->top = tn->internal[0]; +- file_struct->top_level--; +- yaffs_free_tnode(dev, tn); +- } else { +- done = 1; +- } +- } +- +- return YAFFS_OK; +-} +- +-/*-------------------- End of File Structure functions.-------------------*/ +- +-/* alloc_empty_obj gets us a clean Object.*/ +-static struct yaffs_obj *yaffs_alloc_empty_obj(struct yaffs_dev *dev) +-{ +- struct yaffs_obj *obj = yaffs_alloc_raw_obj(dev); +- +- if (!obj) +- return obj; +- +- dev->n_obj++; +- +- /* Now sweeten it up... */ +- +- memset(obj, 0, sizeof(struct yaffs_obj)); +- obj->being_created = 1; +- +- obj->my_dev = dev; +- obj->hdr_chunk = 0; +- obj->variant_type = YAFFS_OBJECT_TYPE_UNKNOWN; +- INIT_LIST_HEAD(&(obj->hard_links)); +- INIT_LIST_HEAD(&(obj->hash_link)); +- INIT_LIST_HEAD(&obj->siblings); +- +- /* Now make the directory sane */ +- if (dev->root_dir) { +- obj->parent = dev->root_dir; +- list_add(&(obj->siblings), +- &dev->root_dir->variant.dir_variant.children); +- } +- +- /* Add it to the lost and found directory. +- * NB Can't put root or lost-n-found in lost-n-found so +- * check if lost-n-found exists first +- */ +- if (dev->lost_n_found) +- yaffs_add_obj_to_dir(dev->lost_n_found, obj); +- +- obj->being_created = 0; +- +- dev->checkpoint_blocks_required = 0; /* force recalculation */ +- +- return obj; +-} +- +-static int yaffs_find_nice_bucket(struct yaffs_dev *dev) +-{ +- int i; +- int l = 999; +- int lowest = 999999; +- +- /* Search for the shortest list or one that +- * isn't too long. +- */ +- +- for (i = 0; i < 10 && lowest > 4; i++) { +- dev->bucket_finder++; +- dev->bucket_finder %= YAFFS_NOBJECT_BUCKETS; +- if (dev->obj_bucket[dev->bucket_finder].count < lowest) { +- lowest = dev->obj_bucket[dev->bucket_finder].count; +- l = dev->bucket_finder; +- } +- } +- +- return l; +-} +- +-static int yaffs_new_obj_id(struct yaffs_dev *dev) +-{ +- int bucket = yaffs_find_nice_bucket(dev); +- int found = 0; +- struct list_head *i; +- u32 n = (u32) bucket; +- +- /* Now find an object value that has not already been taken +- * by scanning the list. +- */ +- +- while (!found) { +- found = 1; +- n += YAFFS_NOBJECT_BUCKETS; +- if (1 || dev->obj_bucket[bucket].count > 0) { +- list_for_each(i, &dev->obj_bucket[bucket].list) { +- /* If there is already one in the list */ +- if (i && list_entry(i, struct yaffs_obj, +- hash_link)->obj_id == n) { +- found = 0; +- } +- } +- } +- } +- return n; +-} +- +-static void yaffs_hash_obj(struct yaffs_obj *in) +-{ +- int bucket = yaffs_hash_fn(in->obj_id); +- struct yaffs_dev *dev = in->my_dev; +- +- list_add(&in->hash_link, &dev->obj_bucket[bucket].list); +- dev->obj_bucket[bucket].count++; +-} +- +-struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number) +-{ +- int bucket = yaffs_hash_fn(number); +- struct list_head *i; +- struct yaffs_obj *in; +- +- list_for_each(i, &dev->obj_bucket[bucket].list) { +- /* Look if it is in the list */ +- in = list_entry(i, struct yaffs_obj, hash_link); +- if (in->obj_id == number) { +- /* Don't show if it is defered free */ +- if (in->defered_free) +- return NULL; +- return in; +- } +- } +- +- return NULL; +-} +- +-static struct yaffs_obj *yaffs_new_obj(struct yaffs_dev *dev, int number, +- enum yaffs_obj_type type) +-{ +- struct yaffs_obj *the_obj = NULL; +- struct yaffs_tnode *tn = NULL; +- +- if (number < 0) +- number = yaffs_new_obj_id(dev); +- +- if (type == YAFFS_OBJECT_TYPE_FILE) { +- tn = yaffs_get_tnode(dev); +- if (!tn) +- return NULL; +- } +- +- the_obj = yaffs_alloc_empty_obj(dev); +- if (!the_obj) { +- if (tn) +- yaffs_free_tnode(dev, tn); +- return NULL; +- } +- +- the_obj->fake = 0; +- the_obj->rename_allowed = 1; +- the_obj->unlink_allowed = 1; +- the_obj->obj_id = number; +- yaffs_hash_obj(the_obj); +- the_obj->variant_type = type; +- yaffs_load_current_time(the_obj, 1, 1); +- +- switch (type) { +- case YAFFS_OBJECT_TYPE_FILE: +- the_obj->variant.file_variant.file_size = 0; +- the_obj->variant.file_variant.scanned_size = 0; +- the_obj->variant.file_variant.shrink_size = +- yaffs_max_file_size(dev); +- the_obj->variant.file_variant.top_level = 0; +- the_obj->variant.file_variant.top = tn; +- break; +- case YAFFS_OBJECT_TYPE_DIRECTORY: +- INIT_LIST_HEAD(&the_obj->variant.dir_variant.children); +- INIT_LIST_HEAD(&the_obj->variant.dir_variant.dirty); +- break; +- case YAFFS_OBJECT_TYPE_SYMLINK: +- case YAFFS_OBJECT_TYPE_HARDLINK: +- case YAFFS_OBJECT_TYPE_SPECIAL: +- /* No action required */ +- break; +- case YAFFS_OBJECT_TYPE_UNKNOWN: +- /* todo this should not happen */ +- break; +- } +- return the_obj; +-} +- +-static struct yaffs_obj *yaffs_create_fake_dir(struct yaffs_dev *dev, +- int number, u32 mode) +-{ +- +- struct yaffs_obj *obj = +- yaffs_new_obj(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY); +- +- if (!obj) +- return NULL; +- +- obj->fake = 1; /* it is fake so it might not use NAND */ +- obj->rename_allowed = 0; +- obj->unlink_allowed = 0; +- obj->deleted = 0; +- obj->unlinked = 0; +- obj->yst_mode = mode; +- obj->my_dev = dev; +- obj->hdr_chunk = 0; /* Not a valid chunk. */ +- return obj; +- +-} +- +- +-static void yaffs_init_tnodes_and_objs(struct yaffs_dev *dev) +-{ +- int i; +- +- dev->n_obj = 0; +- dev->n_tnodes = 0; +- yaffs_init_raw_tnodes_and_objs(dev); +- +- for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { +- INIT_LIST_HEAD(&dev->obj_bucket[i].list); +- dev->obj_bucket[i].count = 0; +- } +-} +- +-struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev, +- int number, +- enum yaffs_obj_type type) +-{ +- struct yaffs_obj *the_obj = NULL; +- +- if (number > 0) +- the_obj = yaffs_find_by_number(dev, number); +- +- if (!the_obj) +- the_obj = yaffs_new_obj(dev, number, type); +- +- return the_obj; +- +-} +- +-YCHAR *yaffs_clone_str(const YCHAR *str) +-{ +- YCHAR *new_str = NULL; +- int len; +- +- if (!str) +- str = _Y(""); +- +- len = strnlen(str, YAFFS_MAX_ALIAS_LENGTH); +- new_str = kmalloc((len + 1) * sizeof(YCHAR), GFP_NOFS); +- if (new_str) { +- strncpy(new_str, str, len); +- new_str[len] = 0; +- } +- return new_str; +- +-} +-/* +- *yaffs_update_parent() handles fixing a directories mtime and ctime when a new +- * link (ie. name) is created or deleted in the directory. +- * +- * ie. +- * create dir/a : update dir's mtime/ctime +- * rm dir/a: update dir's mtime/ctime +- * modify dir/a: don't update dir's mtimme/ctime +- * +- * This can be handled immediately or defered. Defering helps reduce the number +- * of updates when many files in a directory are changed within a brief period. +- * +- * If the directory updating is defered then yaffs_update_dirty_dirs must be +- * called periodically. +- */ +- +-static void yaffs_update_parent(struct yaffs_obj *obj) +-{ +- struct yaffs_dev *dev; +- +- if (!obj) +- return; +- dev = obj->my_dev; +- obj->dirty = 1; +- yaffs_load_current_time(obj, 0, 1); +- if (dev->param.defered_dir_update) { +- struct list_head *link = &obj->variant.dir_variant.dirty; +- +- if (list_empty(link)) { +- list_add(link, &dev->dirty_dirs); +- yaffs_trace(YAFFS_TRACE_BACKGROUND, +- "Added object %d to dirty directories", +- obj->obj_id); +- } +- +- } else { +- yaffs_update_oh(obj, NULL, 0, 0, 0, NULL); +- } +-} +- +-void yaffs_update_dirty_dirs(struct yaffs_dev *dev) +-{ +- struct list_head *link; +- struct yaffs_obj *obj; +- struct yaffs_dir_var *d_s; +- union yaffs_obj_var *o_v; +- +- yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update dirty directories"); +- +- while (!list_empty(&dev->dirty_dirs)) { +- link = dev->dirty_dirs.next; +- list_del_init(link); +- +- d_s = list_entry(link, struct yaffs_dir_var, dirty); +- o_v = list_entry(d_s, union yaffs_obj_var, dir_variant); +- obj = list_entry(o_v, struct yaffs_obj, variant); +- +- yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update directory %d", +- obj->obj_id); +- +- if (obj->dirty) +- yaffs_update_oh(obj, NULL, 0, 0, 0, NULL); +- } +-} +- +-/* +- * Mknod (create) a new object. +- * equiv_obj only has meaning for a hard link; +- * alias_str only has meaning for a symlink. +- * rdev only has meaning for devices (a subset of special objects) +- */ +- +-static struct yaffs_obj *yaffs_create_obj(enum yaffs_obj_type type, +- struct yaffs_obj *parent, +- const YCHAR *name, +- u32 mode, +- u32 uid, +- u32 gid, +- struct yaffs_obj *equiv_obj, +- const YCHAR *alias_str, u32 rdev) +-{ +- struct yaffs_obj *in; +- YCHAR *str = NULL; +- struct yaffs_dev *dev = parent->my_dev; +- +- /* Check if the entry exists. +- * If it does then fail the call since we don't want a dup. */ +- if (yaffs_find_by_name(parent, name)) +- return NULL; +- +- if (type == YAFFS_OBJECT_TYPE_SYMLINK) { +- str = yaffs_clone_str(alias_str); +- if (!str) +- return NULL; +- } +- +- in = yaffs_new_obj(dev, -1, type); +- +- if (!in) { +- kfree(str); +- return NULL; +- } +- +- in->hdr_chunk = 0; +- in->valid = 1; +- in->variant_type = type; +- +- in->yst_mode = mode; +- +- yaffs_attribs_init(in, gid, uid, rdev); +- +- in->n_data_chunks = 0; +- +- yaffs_set_obj_name(in, name); +- in->dirty = 1; +- +- yaffs_add_obj_to_dir(parent, in); +- +- in->my_dev = parent->my_dev; +- +- switch (type) { +- case YAFFS_OBJECT_TYPE_SYMLINK: +- in->variant.symlink_variant.alias = str; +- break; +- case YAFFS_OBJECT_TYPE_HARDLINK: +- in->variant.hardlink_variant.equiv_obj = equiv_obj; +- in->variant.hardlink_variant.equiv_id = equiv_obj->obj_id; +- list_add(&in->hard_links, &equiv_obj->hard_links); +- break; +- case YAFFS_OBJECT_TYPE_FILE: +- case YAFFS_OBJECT_TYPE_DIRECTORY: +- case YAFFS_OBJECT_TYPE_SPECIAL: +- case YAFFS_OBJECT_TYPE_UNKNOWN: +- /* do nothing */ +- break; +- } +- +- if (yaffs_update_oh(in, name, 0, 0, 0, NULL) < 0) { +- /* Could not create the object header, fail */ +- yaffs_del_obj(in); +- in = NULL; +- } +- +- if (in) +- yaffs_update_parent(parent); +- +- return in; +-} +- +-struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent, +- const YCHAR *name, u32 mode, u32 uid, +- u32 gid) +-{ +- return yaffs_create_obj(YAFFS_OBJECT_TYPE_FILE, parent, name, mode, +- uid, gid, NULL, NULL, 0); +-} +- +-struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name, +- u32 mode, u32 uid, u32 gid) +-{ +- return yaffs_create_obj(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name, +- mode, uid, gid, NULL, NULL, 0); +-} +- +-struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent, +- const YCHAR *name, u32 mode, u32 uid, +- u32 gid, u32 rdev) +-{ +- return yaffs_create_obj(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode, +- uid, gid, NULL, NULL, rdev); +-} +- +-struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent, +- const YCHAR *name, u32 mode, u32 uid, +- u32 gid, const YCHAR *alias) +-{ +- return yaffs_create_obj(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode, +- uid, gid, NULL, alias, 0); +-} +- +-/* yaffs_link_obj returns the object id of the equivalent object.*/ +-struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR * name, +- struct yaffs_obj *equiv_obj) +-{ +- /* Get the real object in case we were fed a hard link obj */ +- equiv_obj = yaffs_get_equivalent_obj(equiv_obj); +- +- if (yaffs_create_obj(YAFFS_OBJECT_TYPE_HARDLINK, +- parent, name, 0, 0, 0, +- equiv_obj, NULL, 0)) +- return equiv_obj; +- +- return NULL; +- +-} +- +- +- +-/*---------------------- Block Management and Page Allocation -------------*/ +- +-static void yaffs_deinit_blocks(struct yaffs_dev *dev) +-{ +- if (dev->block_info_alt && dev->block_info) +- vfree(dev->block_info); +- else +- kfree(dev->block_info); +- +- dev->block_info_alt = 0; +- +- dev->block_info = NULL; +- +- if (dev->chunk_bits_alt && dev->chunk_bits) +- vfree(dev->chunk_bits); +- else +- kfree(dev->chunk_bits); +- dev->chunk_bits_alt = 0; +- dev->chunk_bits = NULL; +-} +- +-static int yaffs_init_blocks(struct yaffs_dev *dev) +-{ +- int n_blocks = dev->internal_end_block - dev->internal_start_block + 1; +- +- dev->block_info = NULL; +- dev->chunk_bits = NULL; +- dev->alloc_block = -1; /* force it to get a new one */ +- +- /* If the first allocation strategy fails, thry the alternate one */ +- dev->block_info = +- kmalloc(n_blocks * sizeof(struct yaffs_block_info), GFP_NOFS); +- if (!dev->block_info) { +- dev->block_info = +- vmalloc(n_blocks * sizeof(struct yaffs_block_info)); +- dev->block_info_alt = 1; +- } else { +- dev->block_info_alt = 0; +- } +- +- if (!dev->block_info) +- goto alloc_error; +- +- /* Set up dynamic blockinfo stuff. Round up bytes. */ +- dev->chunk_bit_stride = (dev->param.chunks_per_block + 7) / 8; +- dev->chunk_bits = +- kmalloc(dev->chunk_bit_stride * n_blocks, GFP_NOFS); +- if (!dev->chunk_bits) { +- dev->chunk_bits = +- vmalloc(dev->chunk_bit_stride * n_blocks); +- dev->chunk_bits_alt = 1; +- } else { +- dev->chunk_bits_alt = 0; +- } +- if (!dev->chunk_bits) +- goto alloc_error; +- +- +- memset(dev->block_info, 0, n_blocks * sizeof(struct yaffs_block_info)); +- memset(dev->chunk_bits, 0, dev->chunk_bit_stride * n_blocks); +- return YAFFS_OK; +- +-alloc_error: +- yaffs_deinit_blocks(dev); +- return YAFFS_FAIL; +-} +- +- +-void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no) +-{ +- struct yaffs_block_info *bi = yaffs_get_block_info(dev, block_no); +- int erased_ok = 0; +- int i; +- +- /* If the block is still healthy erase it and mark as clean. +- * If the block has had a data failure, then retire it. +- */ +- +- yaffs_trace(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE, +- "yaffs_block_became_dirty block %d state %d %s", +- block_no, bi->block_state, +- (bi->needs_retiring) ? "needs retiring" : ""); +- +- yaffs2_clear_oldest_dirty_seq(dev, bi); +- +- bi->block_state = YAFFS_BLOCK_STATE_DIRTY; +- +- /* If this is the block being garbage collected then stop gc'ing */ +- if (block_no == dev->gc_block) +- dev->gc_block = 0; +- +- /* If this block is currently the best candidate for gc +- * then drop as a candidate */ +- if (block_no == dev->gc_dirtiest) { +- dev->gc_dirtiest = 0; +- dev->gc_pages_in_use = 0; +- } +- +- if (!bi->needs_retiring) { +- yaffs2_checkpt_invalidate(dev); +- erased_ok = yaffs_erase_block(dev, block_no); +- if (!erased_ok) { +- dev->n_erase_failures++; +- yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, +- "**>> Erasure failed %d", block_no); +- } +- } +- +- /* Verify erasure if needed */ +- if (erased_ok && +- ((yaffs_trace_mask & YAFFS_TRACE_ERASE) || +- !yaffs_skip_verification(dev))) { +- for (i = 0; i < dev->param.chunks_per_block; i++) { +- if (!yaffs_check_chunk_erased(dev, +- block_no * dev->param.chunks_per_block + i)) { +- yaffs_trace(YAFFS_TRACE_ERROR, +- ">>Block %d erasure supposedly OK, but chunk %d not erased", +- block_no, i); +- } +- } +- } +- +- if (!erased_ok) { +- /* We lost a block of free space */ +- dev->n_free_chunks -= dev->param.chunks_per_block; +- yaffs_retire_block(dev, block_no); +- yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, +- "**>> Block %d retired", block_no); +- return; +- } +- +- /* Clean it up... */ +- bi->block_state = YAFFS_BLOCK_STATE_EMPTY; +- bi->seq_number = 0; +- dev->n_erased_blocks++; +- bi->pages_in_use = 0; +- bi->soft_del_pages = 0; +- bi->has_shrink_hdr = 0; +- bi->skip_erased_check = 1; /* Clean, so no need to check */ +- bi->gc_prioritise = 0; +- bi->has_summary = 0; +- +- yaffs_clear_chunk_bits(dev, block_no); +- +- yaffs_trace(YAFFS_TRACE_ERASE, "Erased block %d", block_no); +-} +- +-static inline int yaffs_gc_process_chunk(struct yaffs_dev *dev, +- struct yaffs_block_info *bi, +- int old_chunk, u8 *buffer) +-{ +- int new_chunk; +- int mark_flash = 1; +- struct yaffs_ext_tags tags; +- struct yaffs_obj *object; +- int matching_chunk; +- int ret_val = YAFFS_OK; +- +- memset(&tags, 0, sizeof(tags)); +- yaffs_rd_chunk_tags_nand(dev, old_chunk, +- buffer, &tags); +- object = yaffs_find_by_number(dev, tags.obj_id); +- +- yaffs_trace(YAFFS_TRACE_GC_DETAIL, +- "Collecting chunk in block %d, %d %d %d ", +- dev->gc_chunk, tags.obj_id, +- tags.chunk_id, tags.n_bytes); +- +- if (object && !yaffs_skip_verification(dev)) { +- if (tags.chunk_id == 0) +- matching_chunk = +- object->hdr_chunk; +- else if (object->soft_del) +- /* Defeat the test */ +- matching_chunk = old_chunk; +- else +- matching_chunk = +- yaffs_find_chunk_in_file +- (object, tags.chunk_id, +- NULL); +- +- if (old_chunk != matching_chunk) +- yaffs_trace(YAFFS_TRACE_ERROR, +- "gc: page in gc mismatch: %d %d %d %d", +- old_chunk, +- matching_chunk, +- tags.obj_id, +- tags.chunk_id); +- } +- +- if (!object) { +- yaffs_trace(YAFFS_TRACE_ERROR, +- "page %d in gc has no object: %d %d %d ", +- old_chunk, +- tags.obj_id, tags.chunk_id, +- tags.n_bytes); +- } +- +- if (object && +- object->deleted && +- object->soft_del && tags.chunk_id != 0) { +- /* Data chunk in a soft deleted file, +- * throw it away. +- * It's a soft deleted data chunk, +- * No need to copy this, just forget +- * about it and fix up the object. +- */ +- +- /* Free chunks already includes +- * softdeleted chunks, how ever this +- * chunk is going to soon be really +- * deleted which will increment free +- * chunks. We have to decrement free +- * chunks so this works out properly. +- */ +- dev->n_free_chunks--; +- bi->soft_del_pages--; +- +- object->n_data_chunks--; +- if (object->n_data_chunks <= 0) { +- /* remeber to clean up obj */ +- dev->gc_cleanup_list[dev->n_clean_ups] = tags.obj_id; +- dev->n_clean_ups++; +- } +- mark_flash = 0; +- } else if (object) { +- /* It's either a data chunk in a live +- * file or an ObjectHeader, so we're +- * interested in it. +- * NB Need to keep the ObjectHeaders of +- * deleted files until the whole file +- * has been deleted off +- */ +- tags.serial_number++; +- dev->n_gc_copies++; +- +- if (tags.chunk_id == 0) { +- /* It is an object Id, +- * We need to nuke the +- * shrinkheader flags since its +- * work is done. +- * Also need to clean up +- * shadowing. +- */ +- struct yaffs_obj_hdr *oh; +- oh = (struct yaffs_obj_hdr *) buffer; +- +- oh->is_shrink = 0; +- tags.extra_is_shrink = 0; +- oh->shadows_obj = 0; +- oh->inband_shadowed_obj_id = 0; +- tags.extra_shadows = 0; +- +- /* Update file size */ +- if (object->variant_type == YAFFS_OBJECT_TYPE_FILE) { +- yaffs_oh_size_load(oh, +- object->variant.file_variant.file_size); +- tags.extra_file_size = +- object->variant.file_variant.file_size; +- } +- +- yaffs_verify_oh(object, oh, &tags, 1); +- new_chunk = +- yaffs_write_new_chunk(dev, (u8 *) oh, &tags, 1); +- } else { +- new_chunk = +- yaffs_write_new_chunk(dev, buffer, &tags, 1); +- } +- +- if (new_chunk < 0) { +- ret_val = YAFFS_FAIL; +- } else { +- +- /* Now fix up the Tnodes etc. */ +- +- if (tags.chunk_id == 0) { +- /* It's a header */ +- object->hdr_chunk = new_chunk; +- object->serial = tags.serial_number; +- } else { +- /* It's a data chunk */ +- yaffs_put_chunk_in_file(object, tags.chunk_id, +- new_chunk, 0); +- } +- } +- } +- if (ret_val == YAFFS_OK) +- yaffs_chunk_del(dev, old_chunk, mark_flash, __LINE__); +- return ret_val; +-} +- +-static int yaffs_gc_block(struct yaffs_dev *dev, int block, int whole_block) +-{ +- int old_chunk; +- int ret_val = YAFFS_OK; +- int i; +- int is_checkpt_block; +- int max_copies; +- int chunks_before = yaffs_get_erased_chunks(dev); +- int chunks_after; +- struct yaffs_block_info *bi = yaffs_get_block_info(dev, block); +- +- is_checkpt_block = (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT); +- +- yaffs_trace(YAFFS_TRACE_TRACING, +- "Collecting block %d, in use %d, shrink %d, whole_block %d", +- block, bi->pages_in_use, bi->has_shrink_hdr, +- whole_block); +- +- /*yaffs_verify_free_chunks(dev); */ +- +- if (bi->block_state == YAFFS_BLOCK_STATE_FULL) +- bi->block_state = YAFFS_BLOCK_STATE_COLLECTING; +- +- bi->has_shrink_hdr = 0; /* clear the flag so that the block can erase */ +- +- dev->gc_disable = 1; +- +- yaffs_summary_gc(dev, block); +- +- if (is_checkpt_block || !yaffs_still_some_chunks(dev, block)) { +- yaffs_trace(YAFFS_TRACE_TRACING, +- "Collecting block %d that has no chunks in use", +- block); +- yaffs_block_became_dirty(dev, block); +- } else { +- +- u8 *buffer = yaffs_get_temp_buffer(dev); +- +- yaffs_verify_blk(dev, bi, block); +- +- max_copies = (whole_block) ? dev->param.chunks_per_block : 5; +- old_chunk = block * dev->param.chunks_per_block + dev->gc_chunk; +- +- for (/* init already done */ ; +- ret_val == YAFFS_OK && +- dev->gc_chunk < dev->param.chunks_per_block && +- (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) && +- max_copies > 0; +- dev->gc_chunk++, old_chunk++) { +- if (yaffs_check_chunk_bit(dev, block, dev->gc_chunk)) { +- /* Page is in use and might need to be copied */ +- max_copies--; +- ret_val = yaffs_gc_process_chunk(dev, bi, +- old_chunk, buffer); +- } +- } +- yaffs_release_temp_buffer(dev, buffer); +- } +- +- yaffs_verify_collected_blk(dev, bi, block); +- +- if (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) { +- /* +- * The gc did not complete. Set block state back to FULL +- * because checkpointing does not restore gc. +- */ +- bi->block_state = YAFFS_BLOCK_STATE_FULL; +- } else { +- /* The gc completed. */ +- /* Do any required cleanups */ +- for (i = 0; i < dev->n_clean_ups; i++) { +- /* Time to delete the file too */ +- struct yaffs_obj *object = +- yaffs_find_by_number(dev, dev->gc_cleanup_list[i]); +- if (object) { +- yaffs_free_tnode(dev, +- object->variant.file_variant.top); +- object->variant.file_variant.top = NULL; +- yaffs_trace(YAFFS_TRACE_GC, +- "yaffs: About to finally delete object %d", +- object->obj_id); +- yaffs_generic_obj_del(object); +- object->my_dev->n_deleted_files--; +- } +- +- } +- chunks_after = yaffs_get_erased_chunks(dev); +- if (chunks_before >= chunks_after) +- yaffs_trace(YAFFS_TRACE_GC, +- "gc did not increase free chunks before %d after %d", +- chunks_before, chunks_after); +- dev->gc_block = 0; +- dev->gc_chunk = 0; +- dev->n_clean_ups = 0; +- } +- +- dev->gc_disable = 0; +- +- return ret_val; +-} +- +-/* +- * find_gc_block() selects the dirtiest block (or close enough) +- * for garbage collection. +- */ +- +-static unsigned yaffs_find_gc_block(struct yaffs_dev *dev, +- int aggressive, int background) +-{ +- int i; +- int iterations; +- unsigned selected = 0; +- int prioritised = 0; +- int prioritised_exist = 0; +- struct yaffs_block_info *bi; +- int threshold; +- +- /* First let's see if we need to grab a prioritised block */ +- if (dev->has_pending_prioritised_gc && !aggressive) { +- dev->gc_dirtiest = 0; +- bi = dev->block_info; +- for (i = dev->internal_start_block; +- i <= dev->internal_end_block && !selected; i++) { +- +- if (bi->gc_prioritise) { +- prioritised_exist = 1; +- if (bi->block_state == YAFFS_BLOCK_STATE_FULL && +- yaffs_block_ok_for_gc(dev, bi)) { +- selected = i; +- prioritised = 1; +- } +- } +- bi++; +- } +- +- /* +- * If there is a prioritised block and none was selected then +- * this happened because there is at least one old dirty block +- * gumming up the works. Let's gc the oldest dirty block. +- */ +- +- if (prioritised_exist && +- !selected && dev->oldest_dirty_block > 0) +- selected = dev->oldest_dirty_block; +- +- if (!prioritised_exist) /* None found, so we can clear this */ +- dev->has_pending_prioritised_gc = 0; +- } +- +- /* If we're doing aggressive GC then we are happy to take a less-dirty +- * block, and search harder. +- * else (leasurely gc), then we only bother to do this if the +- * block has only a few pages in use. +- */ +- +- if (!selected) { +- int pages_used; +- int n_blocks = +- dev->internal_end_block - dev->internal_start_block + 1; +- if (aggressive) { +- threshold = dev->param.chunks_per_block; +- iterations = n_blocks; +- } else { +- int max_threshold; +- +- if (background) +- max_threshold = dev->param.chunks_per_block / 2; +- else +- max_threshold = dev->param.chunks_per_block / 8; +- +- if (max_threshold < YAFFS_GC_PASSIVE_THRESHOLD) +- max_threshold = YAFFS_GC_PASSIVE_THRESHOLD; +- +- threshold = background ? (dev->gc_not_done + 2) * 2 : 0; +- if (threshold < YAFFS_GC_PASSIVE_THRESHOLD) +- threshold = YAFFS_GC_PASSIVE_THRESHOLD; +- if (threshold > max_threshold) +- threshold = max_threshold; +- +- iterations = n_blocks / 16 + 1; +- if (iterations > 100) +- iterations = 100; +- } +- +- for (i = 0; +- i < iterations && +- (dev->gc_dirtiest < 1 || +- dev->gc_pages_in_use > YAFFS_GC_GOOD_ENOUGH); +- i++) { +- dev->gc_block_finder++; +- if (dev->gc_block_finder < dev->internal_start_block || +- dev->gc_block_finder > dev->internal_end_block) +- dev->gc_block_finder = +- dev->internal_start_block; +- +- bi = yaffs_get_block_info(dev, dev->gc_block_finder); +- +- pages_used = bi->pages_in_use - bi->soft_del_pages; +- +- if (bi->block_state == YAFFS_BLOCK_STATE_FULL && +- pages_used < dev->param.chunks_per_block && +- (dev->gc_dirtiest < 1 || +- pages_used < dev->gc_pages_in_use) && +- yaffs_block_ok_for_gc(dev, bi)) { +- dev->gc_dirtiest = dev->gc_block_finder; +- dev->gc_pages_in_use = pages_used; +- } +- } +- +- if (dev->gc_dirtiest > 0 && dev->gc_pages_in_use <= threshold) +- selected = dev->gc_dirtiest; +- } +- +- /* +- * If nothing has been selected for a while, try the oldest dirty +- * because that's gumming up the works. +- */ +- +- if (!selected && dev->param.is_yaffs2 && +- dev->gc_not_done >= (background ? 10 : 20)) { +- yaffs2_find_oldest_dirty_seq(dev); +- if (dev->oldest_dirty_block > 0) { +- selected = dev->oldest_dirty_block; +- dev->gc_dirtiest = selected; +- dev->oldest_dirty_gc_count++; +- bi = yaffs_get_block_info(dev, selected); +- dev->gc_pages_in_use = +- bi->pages_in_use - bi->soft_del_pages; +- } else { +- dev->gc_not_done = 0; +- } +- } +- +- if (selected) { +- yaffs_trace(YAFFS_TRACE_GC, +- "GC Selected block %d with %d free, prioritised:%d", +- selected, +- dev->param.chunks_per_block - dev->gc_pages_in_use, +- prioritised); +- +- dev->n_gc_blocks++; +- if (background) +- dev->bg_gcs++; +- +- dev->gc_dirtiest = 0; +- dev->gc_pages_in_use = 0; +- dev->gc_not_done = 0; +- if (dev->refresh_skip > 0) +- dev->refresh_skip--; +- } else { +- dev->gc_not_done++; +- yaffs_trace(YAFFS_TRACE_GC, +- "GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s", +- dev->gc_block_finder, dev->gc_not_done, threshold, +- dev->gc_dirtiest, dev->gc_pages_in_use, +- dev->oldest_dirty_block, background ? " bg" : ""); +- } +- +- return selected; +-} +- +-/* New garbage collector +- * If we're very low on erased blocks then we do aggressive garbage collection +- * otherwise we do "leasurely" garbage collection. +- * Aggressive gc looks further (whole array) and will accept less dirty blocks. +- * Passive gc only inspects smaller areas and only accepts more dirty blocks. +- * +- * The idea is to help clear out space in a more spread-out manner. +- * Dunno if it really does anything useful. +- */ +-static int yaffs_check_gc(struct yaffs_dev *dev, int background) +-{ +- int aggressive = 0; +- int gc_ok = YAFFS_OK; +- int max_tries = 0; +- int min_erased; +- int erased_chunks; +- int checkpt_block_adjust; +- +- if (dev->param.gc_control_fn && +- (dev->param.gc_control_fn(dev) & 1) == 0) +- return YAFFS_OK; +- +- if (dev->gc_disable) +- /* Bail out so we don't get recursive gc */ +- return YAFFS_OK; +- +- /* This loop should pass the first time. +- * Only loops here if the collection does not increase space. +- */ +- +- do { +- max_tries++; +- +- checkpt_block_adjust = yaffs_calc_checkpt_blocks_required(dev); +- +- min_erased = +- dev->param.n_reserved_blocks + checkpt_block_adjust + 1; +- erased_chunks = +- dev->n_erased_blocks * dev->param.chunks_per_block; +- +- /* If we need a block soon then do aggressive gc. */ +- if (dev->n_erased_blocks < min_erased) +- aggressive = 1; +- else { +- if (!background +- && erased_chunks > (dev->n_free_chunks / 4)) +- break; +- +- if (dev->gc_skip > 20) +- dev->gc_skip = 20; +- if (erased_chunks < dev->n_free_chunks / 2 || +- dev->gc_skip < 1 || background) +- aggressive = 0; +- else { +- dev->gc_skip--; +- break; +- } +- } +- +- dev->gc_skip = 5; +- +- /* If we don't already have a block being gc'd then see if we +- * should start another */ +- +- if (dev->gc_block < 1 && !aggressive) { +- dev->gc_block = yaffs2_find_refresh_block(dev); +- dev->gc_chunk = 0; +- dev->n_clean_ups = 0; +- } +- if (dev->gc_block < 1) { +- dev->gc_block = +- yaffs_find_gc_block(dev, aggressive, background); +- dev->gc_chunk = 0; +- dev->n_clean_ups = 0; +- } +- +- if (dev->gc_block > 0) { +- dev->all_gcs++; +- if (!aggressive) +- dev->passive_gc_count++; +- +- yaffs_trace(YAFFS_TRACE_GC, +- "yaffs: GC n_erased_blocks %d aggressive %d", +- dev->n_erased_blocks, aggressive); +- +- gc_ok = yaffs_gc_block(dev, dev->gc_block, aggressive); +- } +- +- if (dev->n_erased_blocks < (dev->param.n_reserved_blocks) && +- dev->gc_block > 0) { +- yaffs_trace(YAFFS_TRACE_GC, +- "yaffs: GC !!!no reclaim!!! n_erased_blocks %d after try %d block %d", +- dev->n_erased_blocks, max_tries, +- dev->gc_block); +- } +- } while ((dev->n_erased_blocks < dev->param.n_reserved_blocks) && +- (dev->gc_block > 0) && (max_tries < 2)); +- +- return aggressive ? gc_ok : YAFFS_OK; +-} +- +-/* +- * yaffs_bg_gc() +- * Garbage collects. Intended to be called from a background thread. +- * Returns non-zero if at least half the free chunks are erased. +- */ +-int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency) +-{ +- int erased_chunks = dev->n_erased_blocks * dev->param.chunks_per_block; +- +- yaffs_trace(YAFFS_TRACE_BACKGROUND, "Background gc %u", urgency); +- +- yaffs_check_gc(dev, 1); +- return erased_chunks > dev->n_free_chunks / 2; +-} +- +-/*-------------------- Data file manipulation -----------------*/ +- +-static int yaffs_rd_data_obj(struct yaffs_obj *in, int inode_chunk, u8 * buffer) +-{ +- int nand_chunk = yaffs_find_chunk_in_file(in, inode_chunk, NULL); +- +- if (nand_chunk >= 0) +- return yaffs_rd_chunk_tags_nand(in->my_dev, nand_chunk, +- buffer, NULL); +- else { +- yaffs_trace(YAFFS_TRACE_NANDACCESS, +- "Chunk %d not found zero instead", +- nand_chunk); +- /* get sane (zero) data if you read a hole */ +- memset(buffer, 0, in->my_dev->data_bytes_per_chunk); +- return 0; +- } +- +-} +- +-void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash, +- int lyn) +-{ +- int block; +- int page; +- struct yaffs_ext_tags tags; +- struct yaffs_block_info *bi; +- +- if (chunk_id <= 0) +- return; +- +- dev->n_deletions++; +- block = chunk_id / dev->param.chunks_per_block; +- page = chunk_id % dev->param.chunks_per_block; +- +- if (!yaffs_check_chunk_bit(dev, block, page)) +- yaffs_trace(YAFFS_TRACE_VERIFY, +- "Deleting invalid chunk %d", chunk_id); +- +- bi = yaffs_get_block_info(dev, block); +- +- yaffs2_update_oldest_dirty_seq(dev, block, bi); +- +- yaffs_trace(YAFFS_TRACE_DELETION, +- "line %d delete of chunk %d", +- lyn, chunk_id); +- +- if (!dev->param.is_yaffs2 && mark_flash && +- bi->block_state != YAFFS_BLOCK_STATE_COLLECTING) { +- +- memset(&tags, 0, sizeof(tags)); +- tags.is_deleted = 1; +- yaffs_wr_chunk_tags_nand(dev, chunk_id, NULL, &tags); +- yaffs_handle_chunk_update(dev, chunk_id, &tags); +- } else { +- dev->n_unmarked_deletions++; +- } +- +- /* Pull out of the management area. +- * If the whole block became dirty, this will kick off an erasure. +- */ +- if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING || +- bi->block_state == YAFFS_BLOCK_STATE_FULL || +- bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN || +- bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) { +- dev->n_free_chunks++; +- yaffs_clear_chunk_bit(dev, block, page); +- bi->pages_in_use--; +- +- if (bi->pages_in_use == 0 && +- !bi->has_shrink_hdr && +- bi->block_state != YAFFS_BLOCK_STATE_ALLOCATING && +- bi->block_state != YAFFS_BLOCK_STATE_NEEDS_SCAN) { +- yaffs_block_became_dirty(dev, block); +- } +- } +-} +- +-static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk, +- const u8 *buffer, int n_bytes, int use_reserve) +-{ +- /* Find old chunk Need to do this to get serial number +- * Write new one and patch into tree. +- * Invalidate old tags. +- */ +- +- int prev_chunk_id; +- struct yaffs_ext_tags prev_tags; +- int new_chunk_id; +- struct yaffs_ext_tags new_tags; +- struct yaffs_dev *dev = in->my_dev; +- +- yaffs_check_gc(dev, 0); +- +- /* Get the previous chunk at this location in the file if it exists. +- * If it does not exist then put a zero into the tree. This creates +- * the tnode now, rather than later when it is harder to clean up. +- */ +- prev_chunk_id = yaffs_find_chunk_in_file(in, inode_chunk, &prev_tags); +- if (prev_chunk_id < 1 && +- !yaffs_put_chunk_in_file(in, inode_chunk, 0, 0)) +- return 0; +- +- /* Set up new tags */ +- memset(&new_tags, 0, sizeof(new_tags)); +- +- new_tags.chunk_id = inode_chunk; +- new_tags.obj_id = in->obj_id; +- new_tags.serial_number = +- (prev_chunk_id > 0) ? prev_tags.serial_number + 1 : 1; +- new_tags.n_bytes = n_bytes; +- +- if (n_bytes < 1 || n_bytes > dev->param.total_bytes_per_chunk) { +- yaffs_trace(YAFFS_TRACE_ERROR, +- "Writing %d bytes to chunk!!!!!!!!!", +- n_bytes); +- BUG(); +- } +- +- new_chunk_id = +- yaffs_write_new_chunk(dev, buffer, &new_tags, use_reserve); +- +- if (new_chunk_id > 0) { +- yaffs_put_chunk_in_file(in, inode_chunk, new_chunk_id, 0); +- +- if (prev_chunk_id > 0) +- yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__); +- +- yaffs_verify_file_sane(in); +- } +- return new_chunk_id; +- +-} +- +- +- +-static int yaffs_do_xattrib_mod(struct yaffs_obj *obj, int set, +- const YCHAR *name, const void *value, int size, +- int flags) +-{ +- struct yaffs_xattr_mod xmod; +- int result; +- +- xmod.set = set; +- xmod.name = name; +- xmod.data = value; +- xmod.size = size; +- xmod.flags = flags; +- xmod.result = -ENOSPC; +- +- result = yaffs_update_oh(obj, NULL, 0, 0, 0, &xmod); +- +- if (result > 0) +- return xmod.result; +- else +- return -ENOSPC; +-} +- +-static int yaffs_apply_xattrib_mod(struct yaffs_obj *obj, char *buffer, +- struct yaffs_xattr_mod *xmod) +-{ +- int retval = 0; +- int x_offs = sizeof(struct yaffs_obj_hdr); +- struct yaffs_dev *dev = obj->my_dev; +- int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr); +- char *x_buffer = buffer + x_offs; +- +- if (xmod->set) +- retval = +- nval_set(x_buffer, x_size, xmod->name, xmod->data, +- xmod->size, xmod->flags); +- else +- retval = nval_del(x_buffer, x_size, xmod->name); +- +- obj->has_xattr = nval_hasvalues(x_buffer, x_size); +- obj->xattr_known = 1; +- xmod->result = retval; +- +- return retval; +-} +- +-static int yaffs_do_xattrib_fetch(struct yaffs_obj *obj, const YCHAR *name, +- void *value, int size) +-{ +- char *buffer = NULL; +- int result; +- struct yaffs_ext_tags tags; +- struct yaffs_dev *dev = obj->my_dev; +- int x_offs = sizeof(struct yaffs_obj_hdr); +- int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr); +- char *x_buffer; +- int retval = 0; +- +- if (obj->hdr_chunk < 1) +- return -ENODATA; +- +- /* If we know that the object has no xattribs then don't do all the +- * reading and parsing. +- */ +- if (obj->xattr_known && !obj->has_xattr) { +- if (name) +- return -ENODATA; +- else +- return 0; +- } +- +- buffer = (char *)yaffs_get_temp_buffer(dev); +- if (!buffer) +- return -ENOMEM; +- +- result = +- yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, (u8 *) buffer, &tags); +- +- if (result != YAFFS_OK) +- retval = -ENOENT; +- else { +- x_buffer = buffer + x_offs; +- +- if (!obj->xattr_known) { +- obj->has_xattr = nval_hasvalues(x_buffer, x_size); +- obj->xattr_known = 1; +- } +- +- if (name) +- retval = nval_get(x_buffer, x_size, name, value, size); +- else +- retval = nval_list(x_buffer, x_size, value, size); +- } +- yaffs_release_temp_buffer(dev, (u8 *) buffer); +- return retval; +-} +- +-int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR * name, +- const void *value, int size, int flags) +-{ +- return yaffs_do_xattrib_mod(obj, 1, name, value, size, flags); +-} +- +-int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR * name) +-{ +- return yaffs_do_xattrib_mod(obj, 0, name, NULL, 0, 0); +-} +- +-int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR * name, void *value, +- int size) +-{ +- return yaffs_do_xattrib_fetch(obj, name, value, size); +-} +- +-int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size) +-{ +- return yaffs_do_xattrib_fetch(obj, NULL, buffer, size); +-} +- +-static void yaffs_check_obj_details_loaded(struct yaffs_obj *in) +-{ +- u8 *buf; +- struct yaffs_obj_hdr *oh; +- struct yaffs_dev *dev; +- struct yaffs_ext_tags tags; +- int result; +- int alloc_failed = 0; +- +- if (!in || !in->lazy_loaded || in->hdr_chunk < 1) +- return; +- +- dev = in->my_dev; +- in->lazy_loaded = 0; +- buf = yaffs_get_temp_buffer(dev); +- +- result = yaffs_rd_chunk_tags_nand(dev, in->hdr_chunk, buf, &tags); +- oh = (struct yaffs_obj_hdr *)buf; +- +- in->yst_mode = oh->yst_mode; +- yaffs_load_attribs(in, oh); +- yaffs_set_obj_name_from_oh(in, oh); +- +- if (in->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) { +- in->variant.symlink_variant.alias = +- yaffs_clone_str(oh->alias); +- if (!in->variant.symlink_variant.alias) +- alloc_failed = 1; /* Not returned */ +- } +- yaffs_release_temp_buffer(dev, buf); +-} +- +-static void yaffs_load_name_from_oh(struct yaffs_dev *dev, YCHAR *name, +- const YCHAR *oh_name, int buff_size) +-{ +-#ifdef CONFIG_YAFFS_AUTO_UNICODE +- if (dev->param.auto_unicode) { +- if (*oh_name) { +- /* It is an ASCII name, do an ASCII to +- * unicode conversion */ +- const char *ascii_oh_name = (const char *)oh_name; +- int n = buff_size - 1; +- while (n > 0 && *ascii_oh_name) { +- *name = *ascii_oh_name; +- name++; +- ascii_oh_name++; +- n--; +- } +- } else { +- strncpy(name, oh_name + 1, buff_size - 1); +- } +- } else { +-#else +- (void) dev; +- { +-#endif +- strncpy(name, oh_name, buff_size - 1); +- } +-} +- +-static void yaffs_load_oh_from_name(struct yaffs_dev *dev, YCHAR *oh_name, +- const YCHAR *name) +-{ +-#ifdef CONFIG_YAFFS_AUTO_UNICODE +- +- int is_ascii; +- YCHAR *w; +- +- if (dev->param.auto_unicode) { +- +- is_ascii = 1; +- w = name; +- +- /* Figure out if the name will fit in ascii character set */ +- while (is_ascii && *w) { +- if ((*w) & 0xff00) +- is_ascii = 0; +- w++; +- } +- +- if (is_ascii) { +- /* It is an ASCII name, so convert unicode to ascii */ +- char *ascii_oh_name = (char *)oh_name; +- int n = YAFFS_MAX_NAME_LENGTH - 1; +- while (n > 0 && *name) { +- *ascii_oh_name = *name; +- name++; +- ascii_oh_name++; +- n--; +- } +- } else { +- /* Unicode name, so save starting at the second YCHAR */ +- *oh_name = 0; +- strncpy(oh_name + 1, name, YAFFS_MAX_NAME_LENGTH - 2); +- } +- } else { +-#else +- dev = dev; +- { +-#endif +- strncpy(oh_name, name, YAFFS_MAX_NAME_LENGTH - 1); +- } +-} +- +-/* UpdateObjectHeader updates the header on NAND for an object. +- * If name is not NULL, then that new name is used. +- */ +-int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, int force, +- int is_shrink, int shadows, struct yaffs_xattr_mod *xmod) +-{ +- +- struct yaffs_block_info *bi; +- struct yaffs_dev *dev = in->my_dev; +- int prev_chunk_id; +- int ret_val = 0; +- int result = 0; +- int new_chunk_id; +- struct yaffs_ext_tags new_tags; +- struct yaffs_ext_tags old_tags; +- const YCHAR *alias = NULL; +- u8 *buffer = NULL; +- YCHAR old_name[YAFFS_MAX_NAME_LENGTH + 1]; +- struct yaffs_obj_hdr *oh = NULL; +- loff_t file_size = 0; +- +- strcpy(old_name, _Y("silly old name")); +- +- if (in->fake && in != dev->root_dir && !force && !xmod) +- return ret_val; +- +- yaffs_check_gc(dev, 0); +- yaffs_check_obj_details_loaded(in); +- +- buffer = yaffs_get_temp_buffer(in->my_dev); +- oh = (struct yaffs_obj_hdr *)buffer; +- +- prev_chunk_id = in->hdr_chunk; +- +- if (prev_chunk_id > 0) { +- result = yaffs_rd_chunk_tags_nand(dev, prev_chunk_id, +- buffer, &old_tags); +- +- yaffs_verify_oh(in, oh, &old_tags, 0); +- memcpy(old_name, oh->name, sizeof(oh->name)); +- memset(buffer, 0xff, sizeof(struct yaffs_obj_hdr)); +- } else { +- memset(buffer, 0xff, dev->data_bytes_per_chunk); +- } +- +- oh->type = in->variant_type; +- oh->yst_mode = in->yst_mode; +- oh->shadows_obj = oh->inband_shadowed_obj_id = shadows; +- +- yaffs_load_attribs_oh(oh, in); +- +- if (in->parent) +- oh->parent_obj_id = in->parent->obj_id; +- else +- oh->parent_obj_id = 0; +- +- if (name && *name) { +- memset(oh->name, 0, sizeof(oh->name)); +- yaffs_load_oh_from_name(dev, oh->name, name); +- } else if (prev_chunk_id > 0) { +- memcpy(oh->name, old_name, sizeof(oh->name)); +- } else { +- memset(oh->name, 0, sizeof(oh->name)); +- } +- +- oh->is_shrink = is_shrink; +- +- switch (in->variant_type) { +- case YAFFS_OBJECT_TYPE_UNKNOWN: +- /* Should not happen */ +- break; +- case YAFFS_OBJECT_TYPE_FILE: +- if (oh->parent_obj_id != YAFFS_OBJECTID_DELETED && +- oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED) +- file_size = in->variant.file_variant.file_size; +- yaffs_oh_size_load(oh, file_size); +- break; +- case YAFFS_OBJECT_TYPE_HARDLINK: +- oh->equiv_id = in->variant.hardlink_variant.equiv_id; +- break; +- case YAFFS_OBJECT_TYPE_SPECIAL: +- /* Do nothing */ +- break; +- case YAFFS_OBJECT_TYPE_DIRECTORY: +- /* Do nothing */ +- break; +- case YAFFS_OBJECT_TYPE_SYMLINK: +- alias = in->variant.symlink_variant.alias; +- if (!alias) +- alias = _Y("no alias"); +- strncpy(oh->alias, alias, YAFFS_MAX_ALIAS_LENGTH); +- oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0; +- break; +- } +- +- /* process any xattrib modifications */ +- if (xmod) +- yaffs_apply_xattrib_mod(in, (char *)buffer, xmod); +- +- /* Tags */ +- memset(&new_tags, 0, sizeof(new_tags)); +- in->serial++; +- new_tags.chunk_id = 0; +- new_tags.obj_id = in->obj_id; +- new_tags.serial_number = in->serial; +- +- /* Add extra info for file header */ +- new_tags.extra_available = 1; +- new_tags.extra_parent_id = oh->parent_obj_id; +- new_tags.extra_file_size = file_size; +- new_tags.extra_is_shrink = oh->is_shrink; +- new_tags.extra_equiv_id = oh->equiv_id; +- new_tags.extra_shadows = (oh->shadows_obj > 0) ? 1 : 0; +- new_tags.extra_obj_type = in->variant_type; +- yaffs_verify_oh(in, oh, &new_tags, 1); +- +- /* Create new chunk in NAND */ +- new_chunk_id = +- yaffs_write_new_chunk(dev, buffer, &new_tags, +- (prev_chunk_id > 0) ? 1 : 0); +- +- if (buffer) +- yaffs_release_temp_buffer(dev, buffer); +- +- if (new_chunk_id < 0) +- return new_chunk_id; +- +- in->hdr_chunk = new_chunk_id; +- +- if (prev_chunk_id > 0) +- yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__); +- +- if (!yaffs_obj_cache_dirty(in)) +- in->dirty = 0; +- +- /* If this was a shrink, then mark the block +- * that the chunk lives on */ +- if (is_shrink) { +- bi = yaffs_get_block_info(in->my_dev, +- new_chunk_id / +- in->my_dev->param.chunks_per_block); +- bi->has_shrink_hdr = 1; +- } +- +- +- return new_chunk_id; +-} +- +-/*--------------------- File read/write ------------------------ +- * Read and write have very similar structures. +- * In general the read/write has three parts to it +- * An incomplete chunk to start with (if the read/write is not chunk-aligned) +- * Some complete chunks +- * An incomplete chunk to end off with +- * +- * Curve-balls: the first chunk might also be the last chunk. +- */ +- +-int yaffs_file_rd(struct yaffs_obj *in, u8 * buffer, loff_t offset, int n_bytes) +-{ +- int chunk; +- u32 start; +- int n_copy; +- int n = n_bytes; +- int n_done = 0; +- struct yaffs_cache *cache; +- struct yaffs_dev *dev; +- +- dev = in->my_dev; +- +- while (n > 0) { +- yaffs_addr_to_chunk(dev, offset, &chunk, &start); +- chunk++; +- +- /* OK now check for the curveball where the start and end are in +- * the same chunk. +- */ +- if ((start + n) < dev->data_bytes_per_chunk) +- n_copy = n; +- else +- n_copy = dev->data_bytes_per_chunk - start; +- +- cache = yaffs_find_chunk_cache(in, chunk); +- +- /* If the chunk is already in the cache or it is less than +- * a whole chunk or we're using inband tags then use the cache +- * (if there is caching) else bypass the cache. +- */ +- if (cache || n_copy != dev->data_bytes_per_chunk || +- dev->param.inband_tags) { +- if (dev->param.n_caches > 0) { +- +- /* If we can't find the data in the cache, +- * then load it up. */ +- +- if (!cache) { +- cache = +- yaffs_grab_chunk_cache(in->my_dev); +- cache->object = in; +- cache->chunk_id = chunk; +- cache->dirty = 0; +- cache->locked = 0; +- yaffs_rd_data_obj(in, chunk, +- cache->data); +- cache->n_bytes = 0; +- } +- +- yaffs_use_cache(dev, cache, 0); +- +- cache->locked = 1; +- +- memcpy(buffer, &cache->data[start], n_copy); +- +- cache->locked = 0; +- } else { +- /* Read into the local buffer then copy.. */ +- +- u8 *local_buffer = +- yaffs_get_temp_buffer(dev); +- yaffs_rd_data_obj(in, chunk, local_buffer); +- +- memcpy(buffer, &local_buffer[start], n_copy); +- +- yaffs_release_temp_buffer(dev, local_buffer); +- } +- } else { +- /* A full chunk. Read directly into the buffer. */ +- yaffs_rd_data_obj(in, chunk, buffer); +- } +- n -= n_copy; +- offset += n_copy; +- buffer += n_copy; +- n_done += n_copy; +- } +- return n_done; +-} +- +-int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset, +- int n_bytes, int write_through) +-{ +- +- int chunk; +- u32 start; +- int n_copy; +- int n = n_bytes; +- int n_done = 0; +- int n_writeback; +- loff_t start_write = offset; +- int chunk_written = 0; +- u32 n_bytes_read; +- loff_t chunk_start; +- struct yaffs_dev *dev; +- +- dev = in->my_dev; +- +- while (n > 0 && chunk_written >= 0) { +- yaffs_addr_to_chunk(dev, offset, &chunk, &start); +- +- if (((loff_t)chunk) * +- dev->data_bytes_per_chunk + start != offset || +- start >= dev->data_bytes_per_chunk) { +- yaffs_trace(YAFFS_TRACE_ERROR, +- "AddrToChunk of offset %lld gives chunk %d start %d", +- offset, chunk, start); +- } +- chunk++; /* File pos to chunk in file offset */ +- +- /* OK now check for the curveball where the start and end are in +- * the same chunk. +- */ +- +- if ((start + n) < dev->data_bytes_per_chunk) { +- n_copy = n; +- +- /* Now calculate how many bytes to write back.... +- * If we're overwriting and not writing to then end of +- * file then we need to write back as much as was there +- * before. +- */ +- +- chunk_start = (((loff_t)(chunk - 1)) * +- dev->data_bytes_per_chunk); +- +- if (chunk_start > in->variant.file_variant.file_size) +- n_bytes_read = 0; /* Past end of file */ +- else +- n_bytes_read = +- in->variant.file_variant.file_size - +- chunk_start; +- +- if (n_bytes_read > dev->data_bytes_per_chunk) +- n_bytes_read = dev->data_bytes_per_chunk; +- +- n_writeback = +- (n_bytes_read > +- (start + n)) ? n_bytes_read : (start + n); +- +- if (n_writeback < 0 || +- n_writeback > dev->data_bytes_per_chunk) +- BUG(); +- +- } else { +- n_copy = dev->data_bytes_per_chunk - start; +- n_writeback = dev->data_bytes_per_chunk; +- } +- +- if (n_copy != dev->data_bytes_per_chunk || +- !dev->param.cache_bypass_aligned || +- dev->param.inband_tags) { +- /* An incomplete start or end chunk (or maybe both +- * start and end chunk), or we're using inband tags, +- * or we're forcing writes through the cache, +- * so we want to use the cache buffers. +- */ +- if (dev->param.n_caches > 0) { +- struct yaffs_cache *cache; +- +- /* If we can't find the data in the cache, then +- * load the cache */ +- cache = yaffs_find_chunk_cache(in, chunk); +- +- if (!cache && +- yaffs_check_alloc_available(dev, 1)) { +- cache = yaffs_grab_chunk_cache(dev); +- cache->object = in; +- cache->chunk_id = chunk; +- cache->dirty = 0; +- cache->locked = 0; +- yaffs_rd_data_obj(in, chunk, +- cache->data); +- } else if (cache && +- !cache->dirty && +- !yaffs_check_alloc_available(dev, +- 1)) { +- /* Drop the cache if it was a read cache +- * item and no space check has been made +- * for it. +- */ +- cache = NULL; +- } +- +- if (cache) { +- yaffs_use_cache(dev, cache, 1); +- cache->locked = 1; +- +- memcpy(&cache->data[start], buffer, +- n_copy); +- +- cache->locked = 0; +- cache->n_bytes = n_writeback; +- +- if (write_through) { +- chunk_written = +- yaffs_wr_data_obj +- (cache->object, +- cache->chunk_id, +- cache->data, +- cache->n_bytes, 1); +- cache->dirty = 0; +- } +- } else { +- chunk_written = -1; /* fail write */ +- } +- } else { +- /* An incomplete start or end chunk (or maybe +- * both start and end chunk). Read into the +- * local buffer then copy over and write back. +- */ +- +- u8 *local_buffer = yaffs_get_temp_buffer(dev); +- +- yaffs_rd_data_obj(in, chunk, local_buffer); +- memcpy(&local_buffer[start], buffer, n_copy); +- +- chunk_written = +- yaffs_wr_data_obj(in, chunk, +- local_buffer, +- n_writeback, 0); +- +- yaffs_release_temp_buffer(dev, local_buffer); +- } +- } else { +- /* A full chunk. Write directly from the buffer. */ +- +- chunk_written = +- yaffs_wr_data_obj(in, chunk, buffer, +- dev->data_bytes_per_chunk, 0); +- +- /* Since we've overwritten the cached data, +- * we better invalidate it. */ +- yaffs_invalidate_chunk_cache(in, chunk); +- } +- +- if (chunk_written >= 0) { +- n -= n_copy; +- offset += n_copy; +- buffer += n_copy; +- n_done += n_copy; +- } +- } +- +- /* Update file object */ +- +- if ((start_write + n_done) > in->variant.file_variant.file_size) +- in->variant.file_variant.file_size = (start_write + n_done); +- +- in->dirty = 1; +- return n_done; +-} +- +-int yaffs_wr_file(struct yaffs_obj *in, const u8 *buffer, loff_t offset, +- int n_bytes, int write_through) +-{ +- yaffs2_handle_hole(in, offset); +- return yaffs_do_file_wr(in, buffer, offset, n_bytes, write_through); +-} +- +-/* ---------------------- File resizing stuff ------------------ */ +- +-static void yaffs_prune_chunks(struct yaffs_obj *in, loff_t new_size) +-{ +- +- struct yaffs_dev *dev = in->my_dev; +- loff_t old_size = in->variant.file_variant.file_size; +- int i; +- int chunk_id; +- u32 dummy; +- int last_del; +- int start_del; +- +- if (old_size > 0) +- yaffs_addr_to_chunk(dev, old_size - 1, &last_del, &dummy); +- else +- last_del = 0; +- +- yaffs_addr_to_chunk(dev, new_size + dev->data_bytes_per_chunk - 1, +- &start_del, &dummy); +- last_del++; +- start_del++; +- +- /* Delete backwards so that we don't end up with holes if +- * power is lost part-way through the operation. +- */ +- for (i = last_del; i >= start_del; i--) { +- /* NB this could be optimised somewhat, +- * eg. could retrieve the tags and write them without +- * using yaffs_chunk_del +- */ +- +- chunk_id = yaffs_find_del_file_chunk(in, i, NULL); +- +- if (chunk_id < 1) +- continue; +- +- if (chunk_id < +- (dev->internal_start_block * dev->param.chunks_per_block) || +- chunk_id >= +- ((dev->internal_end_block + 1) * +- dev->param.chunks_per_block)) { +- yaffs_trace(YAFFS_TRACE_ALWAYS, +- "Found daft chunk_id %d for %d", +- chunk_id, i); +- } else { +- in->n_data_chunks--; +- yaffs_chunk_del(dev, chunk_id, 1, __LINE__); +- } +- } +-} +- +-void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size) +-{ +- int new_full; +- u32 new_partial; +- struct yaffs_dev *dev = obj->my_dev; +- +- yaffs_addr_to_chunk(dev, new_size, &new_full, &new_partial); +- +- yaffs_prune_chunks(obj, new_size); +- +- if (new_partial != 0) { +- int last_chunk = 1 + new_full; +- u8 *local_buffer = yaffs_get_temp_buffer(dev); +- +- /* Rewrite the last chunk with its new size and zero pad */ +- yaffs_rd_data_obj(obj, last_chunk, local_buffer); +- memset(local_buffer + new_partial, 0, +- dev->data_bytes_per_chunk - new_partial); +- +- yaffs_wr_data_obj(obj, last_chunk, local_buffer, +- new_partial, 1); +- +- yaffs_release_temp_buffer(dev, local_buffer); +- } +- +- obj->variant.file_variant.file_size = new_size; +- +- yaffs_prune_tree(dev, &obj->variant.file_variant); +-} +- +-int yaffs_resize_file(struct yaffs_obj *in, loff_t new_size) +-{ +- struct yaffs_dev *dev = in->my_dev; +- loff_t old_size = in->variant.file_variant.file_size; +- +- yaffs_flush_file_cache(in); +- yaffs_invalidate_whole_cache(in); +- +- yaffs_check_gc(dev, 0); +- +- if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) +- return YAFFS_FAIL; +- +- if (new_size == old_size) +- return YAFFS_OK; +- +- if (new_size > old_size) { +- yaffs2_handle_hole(in, new_size); +- in->variant.file_variant.file_size = new_size; +- } else { +- /* new_size < old_size */ +- yaffs_resize_file_down(in, new_size); +- } +- +- /* Write a new object header to reflect the resize. +- * show we've shrunk the file, if need be +- * Do this only if the file is not in the deleted directories +- * and is not shadowed. +- */ +- if (in->parent && +- !in->is_shadowed && +- in->parent->obj_id != YAFFS_OBJECTID_UNLINKED && +- in->parent->obj_id != YAFFS_OBJECTID_DELETED) +- yaffs_update_oh(in, NULL, 0, 0, 0, NULL); +- +- return YAFFS_OK; +-} +- +-int yaffs_flush_file(struct yaffs_obj *in, int update_time, int data_sync) +-{ +- if (!in->dirty) +- return YAFFS_OK; +- +- yaffs_flush_file_cache(in); +- +- if (data_sync) +- return YAFFS_OK; +- +- if (update_time) +- yaffs_load_current_time(in, 0, 0); +- +- return (yaffs_update_oh(in, NULL, 0, 0, 0, NULL) >= 0) ? +- YAFFS_OK : YAFFS_FAIL; +-} +- +- +-/* yaffs_del_file deletes the whole file data +- * and the inode associated with the file. +- * It does not delete the links associated with the file. +- */ +-static int yaffs_unlink_file_if_needed(struct yaffs_obj *in) +-{ +- int ret_val; +- int del_now = 0; +- struct yaffs_dev *dev = in->my_dev; +- +- if (!in->my_inode) +- del_now = 1; +- +- if (del_now) { +- ret_val = +- yaffs_change_obj_name(in, in->my_dev->del_dir, +- _Y("deleted"), 0, 0); +- yaffs_trace(YAFFS_TRACE_TRACING, +- "yaffs: immediate deletion of file %d", +- in->obj_id); +- in->deleted = 1; +- in->my_dev->n_deleted_files++; +- if (dev->param.disable_soft_del || dev->param.is_yaffs2) +- yaffs_resize_file(in, 0); +- yaffs_soft_del_file(in); +- } else { +- ret_val = +- yaffs_change_obj_name(in, in->my_dev->unlinked_dir, +- _Y("unlinked"), 0, 0); +- } +- return ret_val; +-} +- +-static int yaffs_del_file(struct yaffs_obj *in) +-{ +- int ret_val = YAFFS_OK; +- int deleted; /* Need to cache value on stack if in is freed */ +- struct yaffs_dev *dev = in->my_dev; +- +- if (dev->param.disable_soft_del || dev->param.is_yaffs2) +- yaffs_resize_file(in, 0); +- +- if (in->n_data_chunks > 0) { +- /* Use soft deletion if there is data in the file. +- * That won't be the case if it has been resized to zero. +- */ +- if (!in->unlinked) +- ret_val = yaffs_unlink_file_if_needed(in); +- +- deleted = in->deleted; +- +- if (ret_val == YAFFS_OK && in->unlinked && !in->deleted) { +- in->deleted = 1; +- deleted = 1; +- in->my_dev->n_deleted_files++; +- yaffs_soft_del_file(in); +- } +- return deleted ? YAFFS_OK : YAFFS_FAIL; +- } else { +- /* The file has no data chunks so we toss it immediately */ +- yaffs_free_tnode(in->my_dev, in->variant.file_variant.top); +- in->variant.file_variant.top = NULL; +- yaffs_generic_obj_del(in); +- +- return YAFFS_OK; +- } +-} +- +-int yaffs_is_non_empty_dir(struct yaffs_obj *obj) +-{ +- return (obj && +- obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) && +- !(list_empty(&obj->variant.dir_variant.children)); +-} +- +-static int yaffs_del_dir(struct yaffs_obj *obj) +-{ +- /* First check that the directory is empty. */ +- if (yaffs_is_non_empty_dir(obj)) +- return YAFFS_FAIL; +- +- return yaffs_generic_obj_del(obj); +-} +- +-static int yaffs_del_symlink(struct yaffs_obj *in) +-{ +- kfree(in->variant.symlink_variant.alias); +- in->variant.symlink_variant.alias = NULL; +- +- return yaffs_generic_obj_del(in); +-} +- +-static int yaffs_del_link(struct yaffs_obj *in) +-{ +- /* remove this hardlink from the list associated with the equivalent +- * object +- */ +- list_del_init(&in->hard_links); +- return yaffs_generic_obj_del(in); +-} +- +-int yaffs_del_obj(struct yaffs_obj *obj) +-{ +- int ret_val = -1; +- +- switch (obj->variant_type) { +- case YAFFS_OBJECT_TYPE_FILE: +- ret_val = yaffs_del_file(obj); +- break; +- case YAFFS_OBJECT_TYPE_DIRECTORY: +- if (!list_empty(&obj->variant.dir_variant.dirty)) { +- yaffs_trace(YAFFS_TRACE_BACKGROUND, +- "Remove object %d from dirty directories", +- obj->obj_id); +- list_del_init(&obj->variant.dir_variant.dirty); +- } +- return yaffs_del_dir(obj); +- break; +- case YAFFS_OBJECT_TYPE_SYMLINK: +- ret_val = yaffs_del_symlink(obj); +- break; +- case YAFFS_OBJECT_TYPE_HARDLINK: +- ret_val = yaffs_del_link(obj); +- break; +- case YAFFS_OBJECT_TYPE_SPECIAL: +- ret_val = yaffs_generic_obj_del(obj); +- break; +- case YAFFS_OBJECT_TYPE_UNKNOWN: +- ret_val = 0; +- break; /* should not happen. */ +- } +- return ret_val; +-} +- +-static int yaffs_unlink_worker(struct yaffs_obj *obj) +-{ +- int del_now = 0; +- +- if (!obj) +- return YAFFS_FAIL; +- +- if (!obj->my_inode) +- del_now = 1; +- +- yaffs_update_parent(obj->parent); +- +- if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) { +- return yaffs_del_link(obj); +- } else if (!list_empty(&obj->hard_links)) { +- /* Curve ball: We're unlinking an object that has a hardlink. +- * +- * This problem arises because we are not strictly following +- * The Linux link/inode model. +- * +- * We can't really delete the object. +- * Instead, we do the following: +- * - Select a hardlink. +- * - Unhook it from the hard links +- * - Move it from its parent directory so that the rename works. +- * - Rename the object to the hardlink's name. +- * - Delete the hardlink +- */ +- +- struct yaffs_obj *hl; +- struct yaffs_obj *parent; +- int ret_val; +- YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; +- +- hl = list_entry(obj->hard_links.next, struct yaffs_obj, +- hard_links); +- +- yaffs_get_obj_name(hl, name, YAFFS_MAX_NAME_LENGTH + 1); +- parent = hl->parent; +- +- list_del_init(&hl->hard_links); +- +- yaffs_add_obj_to_dir(obj->my_dev->unlinked_dir, hl); +- +- ret_val = yaffs_change_obj_name(obj, parent, name, 0, 0); +- +- if (ret_val == YAFFS_OK) +- ret_val = yaffs_generic_obj_del(hl); +- +- return ret_val; +- +- } else if (del_now) { +- switch (obj->variant_type) { +- case YAFFS_OBJECT_TYPE_FILE: +- return yaffs_del_file(obj); +- break; +- case YAFFS_OBJECT_TYPE_DIRECTORY: +- list_del_init(&obj->variant.dir_variant.dirty); +- return yaffs_del_dir(obj); +- break; +- case YAFFS_OBJECT_TYPE_SYMLINK: +- return yaffs_del_symlink(obj); +- break; +- case YAFFS_OBJECT_TYPE_SPECIAL: +- return yaffs_generic_obj_del(obj); +- break; +- case YAFFS_OBJECT_TYPE_HARDLINK: +- case YAFFS_OBJECT_TYPE_UNKNOWN: +- default: +- return YAFFS_FAIL; +- } +- } else if (yaffs_is_non_empty_dir(obj)) { +- return YAFFS_FAIL; +- } else { +- return yaffs_change_obj_name(obj, obj->my_dev->unlinked_dir, +- _Y("unlinked"), 0, 0); +- } +-} +- +-static int yaffs_unlink_obj(struct yaffs_obj *obj) +-{ +- if (obj && obj->unlink_allowed) +- return yaffs_unlink_worker(obj); +- +- return YAFFS_FAIL; +-} +- +-int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR *name) +-{ +- struct yaffs_obj *obj; +- +- obj = yaffs_find_by_name(dir, name); +- return yaffs_unlink_obj(obj); +-} +- +-/* Note: +- * If old_name is NULL then we take old_dir as the object to be renamed. +- */ +-int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR *old_name, +- struct yaffs_obj *new_dir, const YCHAR *new_name) +-{ +- struct yaffs_obj *obj = NULL; +- struct yaffs_obj *existing_target = NULL; +- int force = 0; +- int result; +- struct yaffs_dev *dev; +- +- if (!old_dir || old_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { +- BUG(); +- return YAFFS_FAIL; +- } +- if (!new_dir || new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { +- BUG(); +- return YAFFS_FAIL; +- } +- +- dev = old_dir->my_dev; +- +-#ifdef CONFIG_YAFFS_CASE_INSENSITIVE +- /* Special case for case insemsitive systems. +- * While look-up is case insensitive, the name isn't. +- * Therefore we might want to change x.txt to X.txt +- */ +- if (old_dir == new_dir && +- old_name && new_name && +- strcmp(old_name, new_name) == 0) +- force = 1; +-#endif +- +- if (strnlen(new_name, YAFFS_MAX_NAME_LENGTH + 1) > +- YAFFS_MAX_NAME_LENGTH) +- /* ENAMETOOLONG */ +- return YAFFS_FAIL; +- +- if (old_name) +- obj = yaffs_find_by_name(old_dir, old_name); +- else{ +- obj = old_dir; +- old_dir = obj->parent; +- } +- +- if (obj && obj->rename_allowed) { +- /* Now handle an existing target, if there is one */ +- existing_target = yaffs_find_by_name(new_dir, new_name); +- if (yaffs_is_non_empty_dir(existing_target)) { +- return YAFFS_FAIL; /* ENOTEMPTY */ +- } else if (existing_target && existing_target != obj) { +- /* Nuke the target first, using shadowing, +- * but only if it isn't the same object. +- * +- * Note we must disable gc here otherwise it can mess +- * up the shadowing. +- * +- */ +- dev->gc_disable = 1; +- yaffs_change_obj_name(obj, new_dir, new_name, force, +- existing_target->obj_id); +- existing_target->is_shadowed = 1; +- yaffs_unlink_obj(existing_target); +- dev->gc_disable = 0; +- } +- +- result = yaffs_change_obj_name(obj, new_dir, new_name, 1, 0); +- +- yaffs_update_parent(old_dir); +- if (new_dir != old_dir) +- yaffs_update_parent(new_dir); +- +- return result; +- } +- return YAFFS_FAIL; +-} +- +-/*----------------------- Initialisation Scanning ---------------------- */ +- +-void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id, +- int backward_scanning) +-{ +- struct yaffs_obj *obj; +- +- if (backward_scanning) { +- /* Handle YAFFS2 case (backward scanning) +- * If the shadowed object exists then ignore. +- */ +- obj = yaffs_find_by_number(dev, obj_id); +- if (obj) +- return; +- } +- +- /* Let's create it (if it does not exist) assuming it is a file so that +- * it can do shrinking etc. +- * We put it in unlinked dir to be cleaned up after the scanning +- */ +- obj = +- yaffs_find_or_create_by_number(dev, obj_id, YAFFS_OBJECT_TYPE_FILE); +- if (!obj) +- return; +- obj->is_shadowed = 1; +- yaffs_add_obj_to_dir(dev->unlinked_dir, obj); +- obj->variant.file_variant.shrink_size = 0; +- obj->valid = 1; /* So that we don't read any other info. */ +-} +- +-void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list) +-{ +- struct list_head *lh; +- struct list_head *save; +- struct yaffs_obj *hl; +- struct yaffs_obj *in; +- +- list_for_each_safe(lh, save, hard_list) { +- hl = list_entry(lh, struct yaffs_obj, hard_links); +- in = yaffs_find_by_number(dev, +- hl->variant.hardlink_variant.equiv_id); +- +- if (in) { +- /* Add the hardlink pointers */ +- hl->variant.hardlink_variant.equiv_obj = in; +- list_add(&hl->hard_links, &in->hard_links); +- } else { +- /* Todo Need to report/handle this better. +- * Got a problem... hardlink to a non-existant object +- */ +- hl->variant.hardlink_variant.equiv_obj = NULL; +- INIT_LIST_HEAD(&hl->hard_links); +- } +- } +-} +- +-static void yaffs_strip_deleted_objs(struct yaffs_dev *dev) +-{ +- /* +- * Sort out state of unlinked and deleted objects after scanning. +- */ +- struct list_head *i; +- struct list_head *n; +- struct yaffs_obj *l; +- +- if (dev->read_only) +- return; +- +- /* Soft delete all the unlinked files */ +- list_for_each_safe(i, n, +- &dev->unlinked_dir->variant.dir_variant.children) { +- l = list_entry(i, struct yaffs_obj, siblings); +- yaffs_del_obj(l); +- } +- +- list_for_each_safe(i, n, &dev->del_dir->variant.dir_variant.children) { +- l = list_entry(i, struct yaffs_obj, siblings); +- yaffs_del_obj(l); +- } +-} +- +-/* +- * This code iterates through all the objects making sure that they are rooted. +- * Any unrooted objects are re-rooted in lost+found. +- * An object needs to be in one of: +- * - Directly under deleted, unlinked +- * - Directly or indirectly under root. +- * +- * Note: +- * This code assumes that we don't ever change the current relationships +- * between directories: +- * root_dir->parent == unlinked_dir->parent == del_dir->parent == NULL +- * lost-n-found->parent == root_dir +- * +- * This fixes the problem where directories might have inadvertently been +- * deleted leaving the object "hanging" without being rooted in the +- * directory tree. +- */ +- +-static int yaffs_has_null_parent(struct yaffs_dev *dev, struct yaffs_obj *obj) +-{ +- return (obj == dev->del_dir || +- obj == dev->unlinked_dir || obj == dev->root_dir); +-} +- +-static void yaffs_fix_hanging_objs(struct yaffs_dev *dev) +-{ +- struct yaffs_obj *obj; +- struct yaffs_obj *parent; +- int i; +- struct list_head *lh; +- struct list_head *n; +- int depth_limit; +- int hanging; +- +- if (dev->read_only) +- return; +- +- /* Iterate through the objects in each hash entry, +- * looking at each object. +- * Make sure it is rooted. +- */ +- +- for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { +- list_for_each_safe(lh, n, &dev->obj_bucket[i].list) { +- obj = list_entry(lh, struct yaffs_obj, hash_link); +- parent = obj->parent; +- +- if (yaffs_has_null_parent(dev, obj)) { +- /* These directories are not hanging */ +- hanging = 0; +- } else if (!parent || +- parent->variant_type != +- YAFFS_OBJECT_TYPE_DIRECTORY) { +- hanging = 1; +- } else if (yaffs_has_null_parent(dev, parent)) { +- hanging = 0; +- } else { +- /* +- * Need to follow the parent chain to +- * see if it is hanging. +- */ +- hanging = 0; +- depth_limit = 100; +- +- while (parent != dev->root_dir && +- parent->parent && +- parent->parent->variant_type == +- YAFFS_OBJECT_TYPE_DIRECTORY && +- depth_limit > 0) { +- parent = parent->parent; +- depth_limit--; +- } +- if (parent != dev->root_dir) +- hanging = 1; +- } +- if (hanging) { +- yaffs_trace(YAFFS_TRACE_SCAN, +- "Hanging object %d moved to lost and found", +- obj->obj_id); +- yaffs_add_obj_to_dir(dev->lost_n_found, obj); +- } +- } +- } +-} +- +-/* +- * Delete directory contents for cleaning up lost and found. +- */ +-static void yaffs_del_dir_contents(struct yaffs_obj *dir) +-{ +- struct yaffs_obj *obj; +- struct list_head *lh; +- struct list_head *n; +- +- if (dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) +- BUG(); +- +- list_for_each_safe(lh, n, &dir->variant.dir_variant.children) { +- obj = list_entry(lh, struct yaffs_obj, siblings); +- if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) +- yaffs_del_dir_contents(obj); +- yaffs_trace(YAFFS_TRACE_SCAN, +- "Deleting lost_found object %d", +- obj->obj_id); +- yaffs_unlink_obj(obj); +- } +-} +- +-static void yaffs_empty_l_n_f(struct yaffs_dev *dev) +-{ +- yaffs_del_dir_contents(dev->lost_n_found); +-} +- +- +-struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *directory, +- const YCHAR *name) +-{ +- int sum; +- struct list_head *i; +- YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1]; +- struct yaffs_obj *l; +- +- if (!name) +- return NULL; +- +- if (!directory) { +- yaffs_trace(YAFFS_TRACE_ALWAYS, +- "tragedy: yaffs_find_by_name: null pointer directory" +- ); +- BUG(); +- return NULL; +- } +- if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { +- yaffs_trace(YAFFS_TRACE_ALWAYS, +- "tragedy: yaffs_find_by_name: non-directory" +- ); +- BUG(); +- } +- +- sum = yaffs_calc_name_sum(name); +- +- list_for_each(i, &directory->variant.dir_variant.children) { +- l = list_entry(i, struct yaffs_obj, siblings); +- +- if (l->parent != directory) +- BUG(); +- +- yaffs_check_obj_details_loaded(l); +- +- /* Special case for lost-n-found */ +- if (l->obj_id == YAFFS_OBJECTID_LOSTNFOUND) { +- if (!strcmp(name, YAFFS_LOSTNFOUND_NAME)) +- return l; +- } else if (l->sum == sum || l->hdr_chunk <= 0) { +- /* LostnFound chunk called Objxxx +- * Do a real check +- */ +- yaffs_get_obj_name(l, buffer, +- YAFFS_MAX_NAME_LENGTH + 1); +- if (!strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH)) +- return l; +- } +- } +- return NULL; +-} +- +-/* GetEquivalentObject dereferences any hard links to get to the +- * actual object. +- */ +- +-struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj) +-{ +- if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) { +- obj = obj->variant.hardlink_variant.equiv_obj; +- yaffs_check_obj_details_loaded(obj); +- } +- return obj; +-} +- +-/* +- * A note or two on object names. +- * * If the object name is missing, we then make one up in the form objnnn +- * +- * * ASCII names are stored in the object header's name field from byte zero +- * * Unicode names are historically stored starting from byte zero. +- * +- * Then there are automatic Unicode names... +- * The purpose of these is to save names in a way that can be read as +- * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII +- * system to share files. +- * +- * These automatic unicode are stored slightly differently... +- * - If the name can fit in the ASCII character space then they are saved as +- * ascii names as per above. +- * - If the name needs Unicode then the name is saved in Unicode +- * starting at oh->name[1]. +- +- */ +-static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name, +- int buffer_size) +-{ +- /* Create an object name if we could not find one. */ +- if (strnlen(name, YAFFS_MAX_NAME_LENGTH) == 0) { +- YCHAR local_name[20]; +- YCHAR num_string[20]; +- YCHAR *x = &num_string[19]; +- unsigned v = obj->obj_id; +- num_string[19] = 0; +- while (v > 0) { +- x--; +- *x = '0' + (v % 10); +- v /= 10; +- } +- /* make up a name */ +- strcpy(local_name, YAFFS_LOSTNFOUND_PREFIX); +- strcat(local_name, x); +- strncpy(name, local_name, buffer_size - 1); +- } +-} +- +-int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR *name, int buffer_size) +-{ +- memset(name, 0, buffer_size * sizeof(YCHAR)); +- yaffs_check_obj_details_loaded(obj); +- if (obj->obj_id == YAFFS_OBJECTID_LOSTNFOUND) { +- strncpy(name, YAFFS_LOSTNFOUND_NAME, buffer_size - 1); +- } else if (obj->short_name[0]) { +- strcpy(name, obj->short_name); +- } else if (obj->hdr_chunk > 0) { +- int result; +- u8 *buffer = yaffs_get_temp_buffer(obj->my_dev); +- +- struct yaffs_obj_hdr *oh = (struct yaffs_obj_hdr *)buffer; +- +- memset(buffer, 0, obj->my_dev->data_bytes_per_chunk); +- +- if (obj->hdr_chunk > 0) { +- result = yaffs_rd_chunk_tags_nand(obj->my_dev, +- obj->hdr_chunk, +- buffer, NULL); +- } +- yaffs_load_name_from_oh(obj->my_dev, name, oh->name, +- buffer_size); +- +- yaffs_release_temp_buffer(obj->my_dev, buffer); +- } +- +- yaffs_fix_null_name(obj, name, buffer_size); +- +- return strnlen(name, YAFFS_MAX_NAME_LENGTH); +-} +- +-loff_t yaffs_get_obj_length(struct yaffs_obj *obj) +-{ +- /* Dereference any hard linking */ +- obj = yaffs_get_equivalent_obj(obj); +- +- if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) +- return obj->variant.file_variant.file_size; +- if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) { +- if (!obj->variant.symlink_variant.alias) +- return 0; +- return strnlen(obj->variant.symlink_variant.alias, +- YAFFS_MAX_ALIAS_LENGTH); +- } else { +- /* Only a directory should drop through to here */ +- return obj->my_dev->data_bytes_per_chunk; +- } +-} +- +-int yaffs_get_obj_link_count(struct yaffs_obj *obj) +-{ +- int count = 0; +- struct list_head *i; +- +- if (!obj->unlinked) +- count++; /* the object itself */ +- +- list_for_each(i, &obj->hard_links) +- count++; /* add the hard links; */ +- +- return count; +-} +- +-int yaffs_get_obj_inode(struct yaffs_obj *obj) +-{ +- obj = yaffs_get_equivalent_obj(obj); +- +- return obj->obj_id; +-} +- +-unsigned yaffs_get_obj_type(struct yaffs_obj *obj) +-{ +- obj = yaffs_get_equivalent_obj(obj); +- +- switch (obj->variant_type) { +- case YAFFS_OBJECT_TYPE_FILE: +- return DT_REG; +- break; +- case YAFFS_OBJECT_TYPE_DIRECTORY: +- return DT_DIR; +- break; +- case YAFFS_OBJECT_TYPE_SYMLINK: +- return DT_LNK; +- break; +- case YAFFS_OBJECT_TYPE_HARDLINK: +- return DT_REG; +- break; +- case YAFFS_OBJECT_TYPE_SPECIAL: +- if (S_ISFIFO(obj->yst_mode)) +- return DT_FIFO; +- if (S_ISCHR(obj->yst_mode)) +- return DT_CHR; +- if (S_ISBLK(obj->yst_mode)) +- return DT_BLK; +- if (S_ISSOCK(obj->yst_mode)) +- return DT_SOCK; +- return DT_REG; +- break; +- default: +- return DT_REG; +- break; +- } +-} +- +-YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj) +-{ +- obj = yaffs_get_equivalent_obj(obj); +- if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) +- return yaffs_clone_str(obj->variant.symlink_variant.alias); +- else +- return yaffs_clone_str(_Y("")); +-} +- +-/*--------------------------- Initialisation code -------------------------- */ +- +-static int yaffs_check_dev_fns(struct yaffs_dev *dev) +-{ +- struct yaffs_driver *drv = &dev->drv; +- struct yaffs_tags_handler *tagger = &dev->tagger; +- +- /* Common functions, gotta have */ +- if (!drv->drv_read_chunk_fn || +- !drv->drv_write_chunk_fn || +- !drv->drv_erase_fn) +- return 0; +- +- if (dev->param.is_yaffs2 && +- (!drv->drv_mark_bad_fn || !drv->drv_check_bad_fn)) +- return 0; +- +- /* Install the default tags marshalling functions if needed. */ +- yaffs_tags_compat_install(dev); +- yaffs_tags_marshall_install(dev); +- +- /* Check we now have the marshalling functions required. */ +- if (!tagger->write_chunk_tags_fn || +- !tagger->read_chunk_tags_fn || +- !tagger->query_block_fn || +- !tagger->mark_bad_fn) +- return 0; +- +- return 1; +-} +- +-static int yaffs_create_initial_dir(struct yaffs_dev *dev) +-{ +- /* Initialise the unlinked, deleted, root and lost+found directories */ +- dev->lost_n_found = dev->root_dir = NULL; +- dev->unlinked_dir = dev->del_dir = NULL; +- dev->unlinked_dir = +- yaffs_create_fake_dir(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR); +- dev->del_dir = +- yaffs_create_fake_dir(dev, YAFFS_OBJECTID_DELETED, S_IFDIR); +- dev->root_dir = +- yaffs_create_fake_dir(dev, YAFFS_OBJECTID_ROOT, +- YAFFS_ROOT_MODE | S_IFDIR); +- dev->lost_n_found = +- yaffs_create_fake_dir(dev, YAFFS_OBJECTID_LOSTNFOUND, +- YAFFS_LOSTNFOUND_MODE | S_IFDIR); +- +- if (dev->lost_n_found && dev->root_dir && dev->unlinked_dir +- && dev->del_dir) { +- yaffs_add_obj_to_dir(dev->root_dir, dev->lost_n_found); +- return YAFFS_OK; +- } +- return YAFFS_FAIL; +-} +- +-int yaffs_guts_initialise(struct yaffs_dev *dev) +-{ +- int init_failed = 0; +- unsigned x; +- int bits; +- +- yaffs_trace(YAFFS_TRACE_TRACING, "yaffs: yaffs_guts_initialise()"); +- +- /* Check stuff that must be set */ +- +- if (!dev) { +- yaffs_trace(YAFFS_TRACE_ALWAYS, +- "yaffs: Need a device" +- ); +- return YAFFS_FAIL; +- } +- +- if (dev->is_mounted) { +- yaffs_trace(YAFFS_TRACE_ALWAYS, "device already mounted"); +- return YAFFS_FAIL; +- } +- +- dev->internal_start_block = dev->param.start_block; +- dev->internal_end_block = dev->param.end_block; +- dev->block_offset = 0; +- dev->chunk_offset = 0; +- dev->n_free_chunks = 0; +- +- dev->gc_block = 0; +- +- if (dev->param.start_block == 0) { +- dev->internal_start_block = dev->param.start_block + 1; +- dev->internal_end_block = dev->param.end_block + 1; +- dev->block_offset = 1; +- dev->chunk_offset = dev->param.chunks_per_block; +- } +- +- /* Check geometry parameters. */ +- +- if ((!dev->param.inband_tags && dev->param.is_yaffs2 && +- dev->param.total_bytes_per_chunk < 1024) || +- (!dev->param.is_yaffs2 && +- dev->param.total_bytes_per_chunk < 512) || +- (dev->param.inband_tags && !dev->param.is_yaffs2) || +- dev->param.chunks_per_block < 2 || +- dev->param.n_reserved_blocks < 2 || +- dev->internal_start_block <= 0 || +- dev->internal_end_block <= 0 || +- dev->internal_end_block <= +- (dev->internal_start_block + dev->param.n_reserved_blocks + 2) +- ) { +- /* otherwise it is too small */ +- yaffs_trace(YAFFS_TRACE_ALWAYS, +- "NAND geometry problems: chunk size %d, type is yaffs%s, inband_tags %d ", +- dev->param.total_bytes_per_chunk, +- dev->param.is_yaffs2 ? "2" : "", +- dev->param.inband_tags); +- return YAFFS_FAIL; +- } +- +- if (yaffs_init_nand(dev) != YAFFS_OK) { +- yaffs_trace(YAFFS_TRACE_ALWAYS, "InitialiseNAND failed"); +- return YAFFS_FAIL; +- } +- +- /* Sort out space for inband tags, if required */ +- if (dev->param.inband_tags) +- dev->data_bytes_per_chunk = +- dev->param.total_bytes_per_chunk - +- sizeof(struct yaffs_packed_tags2_tags_only); +- else +- dev->data_bytes_per_chunk = dev->param.total_bytes_per_chunk; +- +- /* Got the right mix of functions? */ +- if (!yaffs_check_dev_fns(dev)) { +- /* Function missing */ +- yaffs_trace(YAFFS_TRACE_ALWAYS, +- "device function(s) missing or wrong"); +- +- return YAFFS_FAIL; +- } +- +- /* Finished with most checks. Further checks happen later on too. */ +- +- dev->is_mounted = 1; +- +- /* OK now calculate a few things for the device */ +- +- /* +- * Calculate all the chunk size manipulation numbers: +- */ +- x = dev->data_bytes_per_chunk; +- /* We always use dev->chunk_shift and dev->chunk_div */ +- dev->chunk_shift = calc_shifts(x); +- x >>= dev->chunk_shift; +- dev->chunk_div = x; +- /* We only use chunk mask if chunk_div is 1 */ +- dev->chunk_mask = (1 << dev->chunk_shift) - 1; +- +- /* +- * Calculate chunk_grp_bits. +- * We need to find the next power of 2 > than internal_end_block +- */ +- +- x = dev->param.chunks_per_block * (dev->internal_end_block + 1); +- +- bits = calc_shifts_ceiling(x); +- +- /* Set up tnode width if wide tnodes are enabled. */ +- if (!dev->param.wide_tnodes_disabled) { +- /* bits must be even so that we end up with 32-bit words */ +- if (bits & 1) +- bits++; +- if (bits < 16) +- dev->tnode_width = 16; +- else +- dev->tnode_width = bits; +- } else { +- dev->tnode_width = 16; +- } +- +- dev->tnode_mask = (1 << dev->tnode_width) - 1; +- +- /* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled), +- * so if the bitwidth of the +- * chunk range we're using is greater than 16 we need +- * to figure out chunk shift and chunk_grp_size +- */ +- +- if (bits <= dev->tnode_width) +- dev->chunk_grp_bits = 0; +- else +- dev->chunk_grp_bits = bits - dev->tnode_width; +- +- dev->tnode_size = (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8; +- if (dev->tnode_size < sizeof(struct yaffs_tnode)) +- dev->tnode_size = sizeof(struct yaffs_tnode); +- +- dev->chunk_grp_size = 1 << dev->chunk_grp_bits; +- +- if (dev->param.chunks_per_block < dev->chunk_grp_size) { +- /* We have a problem because the soft delete won't work if +- * the chunk group size > chunks per block. +- * This can be remedied by using larger "virtual blocks". +- */ +- yaffs_trace(YAFFS_TRACE_ALWAYS, "chunk group too large"); +- +- return YAFFS_FAIL; +- } +- +- /* Finished verifying the device, continue with initialisation */ +- +- /* More device initialisation */ +- dev->all_gcs = 0; +- dev->passive_gc_count = 0; +- dev->oldest_dirty_gc_count = 0; +- dev->bg_gcs = 0; +- dev->gc_block_finder = 0; +- dev->buffered_block = -1; +- dev->doing_buffered_block_rewrite = 0; +- dev->n_deleted_files = 0; +- dev->n_bg_deletions = 0; +- dev->n_unlinked_files = 0; +- dev->n_ecc_fixed = 0; +- dev->n_ecc_unfixed = 0; +- dev->n_tags_ecc_fixed = 0; +- dev->n_tags_ecc_unfixed = 0; +- dev->n_erase_failures = 0; +- dev->n_erased_blocks = 0; +- dev->gc_disable = 0; +- dev->has_pending_prioritised_gc = 1; +- /* Assume the worst for now, will get fixed on first GC */ +- INIT_LIST_HEAD(&dev->dirty_dirs); +- dev->oldest_dirty_seq = 0; +- dev->oldest_dirty_block = 0; +- +- /* Initialise temporary buffers and caches. */ +- if (!yaffs_init_tmp_buffers(dev)) +- init_failed = 1; +- +- dev->cache = NULL; +- dev->gc_cleanup_list = NULL; +- +- if (!init_failed && dev->param.n_caches > 0) { +- int i; +- void *buf; +- int cache_bytes = +- dev->param.n_caches * sizeof(struct yaffs_cache); +- +- if (dev->param.n_caches > YAFFS_MAX_SHORT_OP_CACHES) +- dev->param.n_caches = YAFFS_MAX_SHORT_OP_CACHES; +- +- dev->cache = kmalloc(cache_bytes, GFP_NOFS); +- +- buf = (u8 *) dev->cache; +- +- if (dev->cache) +- memset(dev->cache, 0, cache_bytes); +- +- for (i = 0; i < dev->param.n_caches && buf; i++) { +- dev->cache[i].object = NULL; +- dev->cache[i].last_use = 0; +- dev->cache[i].dirty = 0; +- dev->cache[i].data = buf = +- kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS); +- } +- if (!buf) +- init_failed = 1; +- +- dev->cache_last_use = 0; +- } +- +- dev->cache_hits = 0; +- +- if (!init_failed) { +- dev->gc_cleanup_list = +- kmalloc(dev->param.chunks_per_block * sizeof(u32), +- GFP_NOFS); +- if (!dev->gc_cleanup_list) +- init_failed = 1; +- } +- +- if (dev->param.is_yaffs2) +- dev->param.use_header_file_size = 1; +- +- if (!init_failed && !yaffs_init_blocks(dev)) +- init_failed = 1; +- +- yaffs_init_tnodes_and_objs(dev); +- +- if (!init_failed && !yaffs_create_initial_dir(dev)) +- init_failed = 1; +- +- if (!init_failed && dev->param.is_yaffs2 && +- !dev->param.disable_summary && +- !yaffs_summary_init(dev)) +- init_failed = 1; +- +- if (!init_failed) { +- /* Now scan the flash. */ +- if (dev->param.is_yaffs2) { +- if (yaffs2_checkpt_restore(dev)) { +- yaffs_check_obj_details_loaded(dev->root_dir); +- yaffs_trace(YAFFS_TRACE_CHECKPOINT | +- YAFFS_TRACE_MOUNT, +- "yaffs: restored from checkpoint" +- ); +- } else { +- +- /* Clean up the mess caused by an aborted +- * checkpoint load then scan backwards. +- */ +- yaffs_deinit_blocks(dev); +- +- yaffs_deinit_tnodes_and_objs(dev); +- +- dev->n_erased_blocks = 0; +- dev->n_free_chunks = 0; +- dev->alloc_block = -1; +- dev->alloc_page = -1; +- dev->n_deleted_files = 0; +- dev->n_unlinked_files = 0; +- dev->n_bg_deletions = 0; +- +- if (!init_failed && !yaffs_init_blocks(dev)) +- init_failed = 1; +- +- yaffs_init_tnodes_and_objs(dev); +- +- if (!init_failed +- && !yaffs_create_initial_dir(dev)) +- init_failed = 1; +- +- if (!init_failed && !yaffs2_scan_backwards(dev)) +- init_failed = 1; +- } +- } else if (!yaffs1_scan(dev)) { +- init_failed = 1; +- } +- +- yaffs_strip_deleted_objs(dev); +- yaffs_fix_hanging_objs(dev); +- if (dev->param.empty_lost_n_found) +- yaffs_empty_l_n_f(dev); +- } +- +- if (init_failed) { +- /* Clean up the mess */ +- yaffs_trace(YAFFS_TRACE_TRACING, +- "yaffs: yaffs_guts_initialise() aborted."); +- +- yaffs_deinitialise(dev); +- return YAFFS_FAIL; +- } +- +- /* Zero out stats */ +- dev->n_page_reads = 0; +- dev->n_page_writes = 0; +- dev->n_erasures = 0; +- dev->n_gc_copies = 0; +- dev->n_retried_writes = 0; +- +- dev->n_retired_blocks = 0; +- +- yaffs_verify_free_chunks(dev); +- yaffs_verify_blocks(dev); +- +- /* Clean up any aborted checkpoint data */ +- if (!dev->is_checkpointed && dev->blocks_in_checkpt > 0) +- yaffs2_checkpt_invalidate(dev); +- +- yaffs_trace(YAFFS_TRACE_TRACING, +- "yaffs: yaffs_guts_initialise() done."); +- return YAFFS_OK; +-} +- +-void yaffs_deinitialise(struct yaffs_dev *dev) +-{ +- if (dev->is_mounted) { +- int i; +- +- yaffs_deinit_blocks(dev); +- yaffs_deinit_tnodes_and_objs(dev); +- yaffs_summary_deinit(dev); +- +- if (dev->param.n_caches > 0 && dev->cache) { +- +- for (i = 0; i < dev->param.n_caches; i++) { +- kfree(dev->cache[i].data); +- dev->cache[i].data = NULL; +- } +- +- kfree(dev->cache); +- dev->cache = NULL; +- } +- +- kfree(dev->gc_cleanup_list); +- +- for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) +- kfree(dev->temp_buffer[i].buffer); +- +- dev->is_mounted = 0; +- +- yaffs_deinit_nand(dev); +- } +-} +- +-int yaffs_count_free_chunks(struct yaffs_dev *dev) +-{ +- int n_free = 0; +- int b; +- struct yaffs_block_info *blk; +- +- blk = dev->block_info; +- for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) { +- switch (blk->block_state) { +- case YAFFS_BLOCK_STATE_EMPTY: +- case YAFFS_BLOCK_STATE_ALLOCATING: +- case YAFFS_BLOCK_STATE_COLLECTING: +- case YAFFS_BLOCK_STATE_FULL: +- n_free += +- (dev->param.chunks_per_block - blk->pages_in_use + +- blk->soft_del_pages); +- break; +- default: +- break; +- } +- blk++; +- } +- return n_free; +-} +- +-int yaffs_get_n_free_chunks(struct yaffs_dev *dev) +-{ +- /* This is what we report to the outside world */ +- int n_free; +- int n_dirty_caches; +- int blocks_for_checkpt; +- int i; +- +- n_free = dev->n_free_chunks; +- n_free += dev->n_deleted_files; +- +- /* Now count and subtract the number of dirty chunks in the cache. */ +- +- for (n_dirty_caches = 0, i = 0; i < dev->param.n_caches; i++) { +- if (dev->cache[i].dirty) +- n_dirty_caches++; +- } +- +- n_free -= n_dirty_caches; +- +- n_free -= +- ((dev->param.n_reserved_blocks + 1) * dev->param.chunks_per_block); +- +- /* Now figure checkpoint space and report that... */ +- blocks_for_checkpt = yaffs_calc_checkpt_blocks_required(dev); +- +- n_free -= (blocks_for_checkpt * dev->param.chunks_per_block); +- +- if (n_free < 0) +- n_free = 0; +- +- return n_free; +-} +- +- +-int yaffs_format_dev(struct yaffs_dev *dev) +-{ +- int i; +- enum yaffs_block_state state; +- u32 dummy; +- +- if(dev->is_mounted) +- return YAFFS_FAIL; +- +- /* +- * The runtime variables might not have been set up, +- * so set up what we need. +- */ +- dev->internal_start_block = dev->param.start_block; +- dev->internal_end_block = dev->param.end_block; +- dev->block_offset = 0; +- dev->chunk_offset = 0; +- +- if (dev->param.start_block == 0) { +- dev->internal_start_block = dev->param.start_block + 1; +- dev->internal_end_block = dev->param.end_block + 1; +- dev->block_offset = 1; +- dev->chunk_offset = dev->param.chunks_per_block; +- } +- +- for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { +- yaffs_query_init_block_state(dev, i, &state, &dummy); +- if (state != YAFFS_BLOCK_STATE_DEAD) +- yaffs_erase_block(dev, i); +- } +- +- return YAFFS_OK; +-} +- +- +-/* +- * Marshalling functions to get loff_t file sizes into and out of +- * object headers. +- */ +-void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize) +-{ +- oh->file_size_low = (fsize & 0xFFFFFFFF); +- oh->file_size_high = ((fsize >> 32) & 0xFFFFFFFF); +-} +- +-loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh) +-{ +- loff_t retval; +- +- if (sizeof(loff_t) >= 8 && ~(oh->file_size_high)) +- retval = (((loff_t) oh->file_size_high) << 32) | +- (((loff_t) oh->file_size_low) & 0xFFFFFFFF); +- else +- retval = (loff_t) oh->file_size_low; +- +- return retval; +-} +diff --git a/fs/yaffs2/yaffs_guts.h b/fs/yaffs2/yaffs_guts.h +deleted file mode 100644 +index 64929ed..0000000 +--- a/fs/yaffs2/yaffs_guts.h ++++ /dev/null +@@ -1,990 +0,0 @@ +-/* +- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU Lesser General Public License version 2.1 as +- * published by the Free Software Foundation. +- * +- * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +- */ +- +-#ifndef __YAFFS_GUTS_H__ +-#define __YAFFS_GUTS_H__ +- +-#include "yportenv.h" +- +-#define YAFFS_OK 1 +-#define YAFFS_FAIL 0 +- +-/* Give us a Y=0x59, +- * Give us an A=0x41, +- * Give us an FF=0xff +- * Give us an S=0x53 +- * And what have we got... +- */ +-#define YAFFS_MAGIC 0x5941ff53 +- +-/* +- * Tnodes form a tree with the tnodes in "levels" +- * Levels greater than 0 hold 8 slots which point to other tnodes. +- * Those at level 0 hold 16 slots which point to chunks in NAND. +- * +- * A maximum level of 8 thust supports files of size up to: +- * +- * 2^(3*MAX_LEVEL+4) +- * +- * Thus a max level of 8 supports files with up to 2^^28 chunks which gives +- * a maximum file size of around 512Gbytees with 2k chunks. +- */ +-#define YAFFS_NTNODES_LEVEL0 16 +-#define YAFFS_TNODES_LEVEL0_BITS 4 +-#define YAFFS_TNODES_LEVEL0_MASK 0xf +- +-#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2) +-#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1) +-#define YAFFS_TNODES_INTERNAL_MASK 0x7 +-#define YAFFS_TNODES_MAX_LEVEL 8 +-#define YAFFS_TNODES_MAX_BITS (YAFFS_TNODES_LEVEL0_BITS + \ +- YAFFS_TNODES_INTERNAL_BITS * \ +- YAFFS_TNODES_MAX_LEVEL) +-#define YAFFS_MAX_CHUNK_ID ((1 << YAFFS_TNODES_MAX_BITS) - 1) +- +-#define YAFFS_MAX_FILE_SIZE_32 0x7fffffff +- +-/* Constants for YAFFS1 mode */ +-#define YAFFS_BYTES_PER_SPARE 16 +-#define YAFFS_BYTES_PER_CHUNK 512 +-#define YAFFS_CHUNK_SIZE_SHIFT 9 +-#define YAFFS_CHUNKS_PER_BLOCK 32 +-#define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK) +- +-#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024 +-#define YAFFS_MIN_YAFFS2_SPARE_SIZE 32 +- +- +- +-#define YAFFS_ALLOCATION_NOBJECTS 100 +-#define YAFFS_ALLOCATION_NTNODES 100 +-#define YAFFS_ALLOCATION_NLINKS 100 +- +-#define YAFFS_NOBJECT_BUCKETS 256 +- +-#define YAFFS_OBJECT_SPACE 0x40000 +-#define YAFFS_MAX_OBJECT_ID (YAFFS_OBJECT_SPACE - 1) +- +-/* Binary data version stamps */ +-#define YAFFS_SUMMARY_VERSION 1 +-#define YAFFS_CHECKPOINT_VERSION 7 +- +-#ifdef CONFIG_YAFFS_UNICODE +-#define YAFFS_MAX_NAME_LENGTH 127 +-#define YAFFS_MAX_ALIAS_LENGTH 79 +-#else +-#define YAFFS_MAX_NAME_LENGTH 255 +-#define YAFFS_MAX_ALIAS_LENGTH 159 +-#endif +- +-#define YAFFS_SHORT_NAME_LENGTH 15 +- +-/* Some special object ids for pseudo objects */ +-#define YAFFS_OBJECTID_ROOT 1 +-#define YAFFS_OBJECTID_LOSTNFOUND 2 +-#define YAFFS_OBJECTID_UNLINKED 3 +-#define YAFFS_OBJECTID_DELETED 4 +- +-/* Fake object Id for summary data */ +-#define YAFFS_OBJECTID_SUMMARY 0x10 +- +-/* Pseudo object ids for checkpointing */ +-#define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20 +-#define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21 +- +-#define YAFFS_MAX_SHORT_OP_CACHES 20 +- +-#define YAFFS_N_TEMP_BUFFERS 6 +- +-/* We limit the number attempts at sucessfully saving a chunk of data. +- * Small-page devices have 32 pages per block; large-page devices have 64. +- * Default to something in the order of 5 to 10 blocks worth of chunks. +- */ +-#define YAFFS_WR_ATTEMPTS (5*64) +- +-/* Sequence numbers are used in YAFFS2 to determine block allocation order. +- * The range is limited slightly to help distinguish bad numbers from good. +- * This also allows us to perhaps in the future use special numbers for +- * special purposes. +- * EFFFFF00 allows the allocation of 8 blocks/second (~1Mbytes) for 15 years, +- * and is a larger number than the lifetime of a 2GB device. +- */ +-#define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000 +-#define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xefffff00 +- +-/* Special sequence number for bad block that failed to be marked bad */ +-#define YAFFS_SEQUENCE_BAD_BLOCK 0xffff0000 +- +-/* ChunkCache is used for short read/write operations.*/ +-struct yaffs_cache { +- struct yaffs_obj *object; +- int chunk_id; +- int last_use; +- int dirty; +- int n_bytes; /* Only valid if the cache is dirty */ +- int locked; /* Can't push out or flush while locked. */ +- u8 *data; +-}; +- +-/* yaffs1 tags structures in RAM +- * NB This uses bitfield. Bitfields should not straddle a u32 boundary +- * otherwise the structure size will get blown out. +- */ +- +-struct yaffs_tags { +- unsigned chunk_id:20; +- unsigned serial_number:2; +- unsigned n_bytes_lsb:10; +- unsigned obj_id:18; +- unsigned ecc:12; +- unsigned n_bytes_msb:2; +-}; +- +-union yaffs_tags_union { +- struct yaffs_tags as_tags; +- u8 as_bytes[8]; +-}; +- +- +-/* Stuff used for extended tags in YAFFS2 */ +- +-enum yaffs_ecc_result { +- YAFFS_ECC_RESULT_UNKNOWN, +- YAFFS_ECC_RESULT_NO_ERROR, +- YAFFS_ECC_RESULT_FIXED, +- YAFFS_ECC_RESULT_UNFIXED +-}; +- +-enum yaffs_obj_type { +- YAFFS_OBJECT_TYPE_UNKNOWN, +- YAFFS_OBJECT_TYPE_FILE, +- YAFFS_OBJECT_TYPE_SYMLINK, +- YAFFS_OBJECT_TYPE_DIRECTORY, +- YAFFS_OBJECT_TYPE_HARDLINK, +- YAFFS_OBJECT_TYPE_SPECIAL +-}; +- +-#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL +- +-struct yaffs_ext_tags { +- unsigned chunk_used; /* Status of the chunk: used or unused */ +- unsigned obj_id; /* If 0 this is not used */ +- unsigned chunk_id; /* If 0 this is a header, else a data chunk */ +- unsigned n_bytes; /* Only valid for data chunks */ +- +- /* The following stuff only has meaning when we read */ +- enum yaffs_ecc_result ecc_result; +- unsigned block_bad; +- +- /* YAFFS 1 stuff */ +- unsigned is_deleted; /* The chunk is marked deleted */ +- unsigned serial_number; /* Yaffs1 2-bit serial number */ +- +- /* YAFFS2 stuff */ +- unsigned seq_number; /* The sequence number of this block */ +- +- /* Extra info if this is an object header (YAFFS2 only) */ +- +- unsigned extra_available; /* Extra info available if not zero */ +- unsigned extra_parent_id; /* The parent object */ +- unsigned extra_is_shrink; /* Is it a shrink header? */ +- unsigned extra_shadows; /* Does this shadow another object? */ +- +- enum yaffs_obj_type extra_obj_type; /* What object type? */ +- +- loff_t extra_file_size; /* Length if it is a file */ +- unsigned extra_equiv_id; /* Equivalent object for a hard link */ +-}; +- +-/* Spare structure for YAFFS1 */ +-struct yaffs_spare { +- u8 tb0; +- u8 tb1; +- u8 tb2; +- u8 tb3; +- u8 page_status; /* set to 0 to delete the chunk */ +- u8 block_status; +- u8 tb4; +- u8 tb5; +- u8 ecc1[3]; +- u8 tb6; +- u8 tb7; +- u8 ecc2[3]; +-}; +- +-/*Special structure for passing through to mtd */ +-struct yaffs_nand_spare { +- struct yaffs_spare spare; +- int eccres1; +- int eccres2; +-}; +- +-/* Block data in RAM */ +- +-enum yaffs_block_state { +- YAFFS_BLOCK_STATE_UNKNOWN = 0, +- +- YAFFS_BLOCK_STATE_SCANNING, +- /* Being scanned */ +- +- YAFFS_BLOCK_STATE_NEEDS_SCAN, +- /* The block might have something on it (ie it is allocating or full, +- * perhaps empty) but it needs to be scanned to determine its true +- * state. +- * This state is only valid during scanning. +- * NB We tolerate empty because the pre-scanner might be incapable of +- * deciding +- * However, if this state is returned on a YAFFS2 device, +- * then we expect a sequence number +- */ +- +- YAFFS_BLOCK_STATE_EMPTY, +- /* This block is empty */ +- +- YAFFS_BLOCK_STATE_ALLOCATING, +- /* This block is partially allocated. +- * At least one page holds valid data. +- * This is the one currently being used for page +- * allocation. Should never be more than one of these. +- * If a block is only partially allocated at mount it is treated as +- * full. +- */ +- +- YAFFS_BLOCK_STATE_FULL, +- /* All the pages in this block have been allocated. +- * If a block was only partially allocated when mounted we treat +- * it as fully allocated. +- */ +- +- YAFFS_BLOCK_STATE_DIRTY, +- /* The block was full and now all chunks have been deleted. +- * Erase me, reuse me. +- */ +- +- YAFFS_BLOCK_STATE_CHECKPOINT, +- /* This block is assigned to holding checkpoint data. */ +- +- YAFFS_BLOCK_STATE_COLLECTING, +- /* This block is being garbage collected */ +- +- YAFFS_BLOCK_STATE_DEAD +- /* This block has failed and is not in use */ +-}; +- +-#define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1) +- +-struct yaffs_block_info { +- +- int soft_del_pages:10; /* number of soft deleted pages */ +- int pages_in_use:10; /* number of pages in use */ +- unsigned block_state:4; /* One of the above block states. */ +- /* NB use unsigned because enum is sometimes +- * an int */ +- u32 needs_retiring:1; /* Data has failed on this block, */ +- /*need to get valid data off and retire*/ +- u32 skip_erased_check:1;/* Skip the erased check on this block */ +- u32 gc_prioritise:1; /* An ECC check or blank check has failed. +- Block should be prioritised for GC */ +- u32 chunk_error_strikes:3; /* How many times we've had ecc etc +- failures on this block and tried to reuse it */ +- u32 has_summary:1; /* The block has a summary */ +- +- u32 has_shrink_hdr:1; /* This block has at least one shrink header */ +- u32 seq_number; /* block sequence number for yaffs2 */ +- +-}; +- +-/* -------------------------- Object structure -------------------------------*/ +-/* This is the object structure as stored on NAND */ +- +-struct yaffs_obj_hdr { +- enum yaffs_obj_type type; +- +- /* Apply to everything */ +- int parent_obj_id; +- u16 sum_no_longer_used; /* checksum of name. No longer used */ +- YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; +- +- /* The following apply to all object types except for hard links */ +- u32 yst_mode; /* protection */ +- +- u32 yst_uid; +- u32 yst_gid; +- u32 yst_atime; +- u32 yst_mtime; +- u32 yst_ctime; +- +- /* File size applies to files only */ +- u32 file_size_low; +- +- /* Equivalent object id applies to hard links only. */ +- int equiv_id; +- +- /* Alias is for symlinks only. */ +- YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1]; +- +- u32 yst_rdev; /* stuff for block and char devices (major/min) */ +- +- u32 win_ctime[2]; +- u32 win_atime[2]; +- u32 win_mtime[2]; +- +- u32 inband_shadowed_obj_id; +- u32 inband_is_shrink; +- +- u32 file_size_high; +- u32 reserved[1]; +- int shadows_obj; /* This object header shadows the +- specified object if > 0 */ +- +- /* is_shrink applies to object headers written when wemake a hole. */ +- u32 is_shrink; +- +-}; +- +-/*--------------------------- Tnode -------------------------- */ +- +-struct yaffs_tnode { +- struct yaffs_tnode *internal[YAFFS_NTNODES_INTERNAL]; +-}; +- +-/*------------------------ Object -----------------------------*/ +-/* An object can be one of: +- * - a directory (no data, has children links +- * - a regular file (data.... not prunes :->). +- * - a symlink [symbolic link] (the alias). +- * - a hard link +- */ +- +-struct yaffs_file_var { +- loff_t file_size; +- loff_t scanned_size; +- loff_t shrink_size; +- int top_level; +- struct yaffs_tnode *top; +-}; +- +-struct yaffs_dir_var { +- struct list_head children; /* list of child links */ +- struct list_head dirty; /* Entry for list of dirty directories */ +-}; +- +-struct yaffs_symlink_var { +- YCHAR *alias; +-}; +- +-struct yaffs_hardlink_var { +- struct yaffs_obj *equiv_obj; +- u32 equiv_id; +-}; +- +-union yaffs_obj_var { +- struct yaffs_file_var file_variant; +- struct yaffs_dir_var dir_variant; +- struct yaffs_symlink_var symlink_variant; +- struct yaffs_hardlink_var hardlink_variant; +-}; +- +-struct yaffs_obj { +- u8 deleted:1; /* This should only apply to unlinked files. */ +- u8 soft_del:1; /* it has also been soft deleted */ +- u8 unlinked:1; /* An unlinked file.*/ +- u8 fake:1; /* A fake object has no presence on NAND. */ +- u8 rename_allowed:1; /* Some objects cannot be renamed. */ +- u8 unlink_allowed:1; +- u8 dirty:1; /* the object needs to be written to flash */ +- u8 valid:1; /* When the file system is being loaded up, this +- * object might be created before the data +- * is available +- * ie. file data chunks encountered before +- * the header. +- */ +- u8 lazy_loaded:1; /* This object has been lazy loaded and +- * is missing some detail */ +- +- u8 defered_free:1; /* Object is removed from NAND, but is +- * still in the inode cache. +- * Free of object is defered. +- * until the inode is released. +- */ +- u8 being_created:1; /* This object is still being created +- * so skip some verification checks. */ +- u8 is_shadowed:1; /* This object is shadowed on the way +- * to being renamed. */ +- +- u8 xattr_known:1; /* We know if this has object has xattribs +- * or not. */ +- u8 has_xattr:1; /* This object has xattribs. +- * Only valid if xattr_known. */ +- +- u8 serial; /* serial number of chunk in NAND.*/ +- u16 sum; /* sum of the name to speed searching */ +- +- struct yaffs_dev *my_dev; /* The device I'm on */ +- +- struct list_head hash_link; /* list of objects in hash bucket */ +- +- struct list_head hard_links; /* hard linked object chain*/ +- +- /* directory structure stuff */ +- /* also used for linking up the free list */ +- struct yaffs_obj *parent; +- struct list_head siblings; +- +- /* Where's my object header in NAND? */ +- int hdr_chunk; +- +- int n_data_chunks; /* Number of data chunks for this file. */ +- +- u32 obj_id; /* the object id value */ +- +- u32 yst_mode; +- +- YCHAR short_name[YAFFS_SHORT_NAME_LENGTH + 1]; +- +-#ifdef CONFIG_YAFFS_WINCE +- u32 win_ctime[2]; +- u32 win_mtime[2]; +- u32 win_atime[2]; +-#else +- u32 yst_uid; +- u32 yst_gid; +- u32 yst_atime; +- u32 yst_mtime; +- u32 yst_ctime; +-#endif +- +- u32 yst_rdev; +- +- void *my_inode; +- +- enum yaffs_obj_type variant_type; +- +- union yaffs_obj_var variant; +- +-}; +- +-struct yaffs_obj_bucket { +- struct list_head list; +- int count; +-}; +- +-/* yaffs_checkpt_obj holds the definition of an object as dumped +- * by checkpointing. +- */ +- +-struct yaffs_checkpt_obj { +- int struct_type; +- u32 obj_id; +- u32 parent_id; +- int hdr_chunk; +- enum yaffs_obj_type variant_type:3; +- u8 deleted:1; +- u8 soft_del:1; +- u8 unlinked:1; +- u8 fake:1; +- u8 rename_allowed:1; +- u8 unlink_allowed:1; +- u8 serial; +- int n_data_chunks; +- loff_t size_or_equiv_obj; +-}; +- +-/*--------------------- Temporary buffers ---------------- +- * +- * These are chunk-sized working buffers. Each device has a few. +- */ +- +-struct yaffs_buffer { +- u8 *buffer; +- int in_use; +-}; +- +-/*----------------- Device ---------------------------------*/ +- +-struct yaffs_param { +- const YCHAR *name; +- +- /* +- * Entry parameters set up way early. Yaffs sets up the rest. +- * The structure should be zeroed out before use so that unused +- * and default values are zero. +- */ +- +- int inband_tags; /* Use unband tags */ +- u32 total_bytes_per_chunk; /* Should be >= 512, does not need to +- be a power of 2 */ +- int chunks_per_block; /* does not need to be a power of 2 */ +- int spare_bytes_per_chunk; /* spare area size */ +- int start_block; /* Start block we're allowed to use */ +- int end_block; /* End block we're allowed to use */ +- int n_reserved_blocks; /* Tuneable so that we can reduce +- * reserved blocks on NOR and RAM. */ +- +- int n_caches; /* If <= 0, then short op caching is disabled, +- * else the number of short op caches. +- */ +- int cache_bypass_aligned; /* If non-zero then bypass the cache for +- * aligned writes. +- */ +- +- int use_nand_ecc; /* Flag to decide whether or not to use +- * NAND driver ECC on data (yaffs1) */ +- int tags_9bytes; /* Use 9 byte tags */ +- int no_tags_ecc; /* Flag to decide whether or not to do ECC +- * on packed tags (yaffs2) */ +- +- int is_yaffs2; /* Use yaffs2 mode on this device */ +- +- int empty_lost_n_found; /* Auto-empty lost+found directory on mount */ +- +- int refresh_period; /* How often to check for a block refresh */ +- +- /* Checkpoint control. Can be set before or after initialisation */ +- u8 skip_checkpt_rd; +- u8 skip_checkpt_wr; +- +- int enable_xattr; /* Enable xattribs */ +- +- int max_objects; /* +- * Set to limit the number of objects created. +- * 0 = no limit. +- */ +- +- /* The remove_obj_fn function must be supplied by OS flavours that +- * need it. +- * yaffs direct uses it to implement the faster readdir. +- * Linux uses it to protect the directory during unlocking. +- */ +- void (*remove_obj_fn) (struct yaffs_obj *obj); +- +- /* Callback to mark the superblock dirty */ +- void (*sb_dirty_fn) (struct yaffs_dev *dev); +- +- /* Callback to control garbage collection. */ +- unsigned (*gc_control_fn) (struct yaffs_dev *dev); +- +- /* Debug control flags. Don't use unless you know what you're doing */ +- int use_header_file_size; /* Flag to determine if we should use +- * file sizes from the header */ +- int disable_lazy_load; /* Disable lazy loading on this device */ +- int wide_tnodes_disabled; /* Set to disable wide tnodes */ +- int disable_soft_del; /* yaffs 1 only: Set to disable the use of +- * softdeletion. */ +- +- int defered_dir_update; /* Set to defer directory updates */ +- +-#ifdef CONFIG_YAFFS_AUTO_UNICODE +- int auto_unicode; +-#endif +- int always_check_erased; /* Force chunk erased check always on */ +- +- int disable_summary; +- +-}; +- +-struct yaffs_driver { +- int (*drv_write_chunk_fn) (struct yaffs_dev *dev, int nand_chunk, +- const u8 *data, int data_len, +- const u8 *oob, int oob_len); +- int (*drv_read_chunk_fn) (struct yaffs_dev *dev, int nand_chunk, +- u8 *data, int data_len, +- u8 *oob, int oob_len, +- enum yaffs_ecc_result *ecc_result); +- int (*drv_erase_fn) (struct yaffs_dev *dev, int block_no); +- int (*drv_mark_bad_fn) (struct yaffs_dev *dev, int block_no); +- int (*drv_check_bad_fn) (struct yaffs_dev *dev, int block_no); +- int (*drv_initialise_fn) (struct yaffs_dev *dev); +- int (*drv_deinitialise_fn) (struct yaffs_dev *dev); +-}; +- +-struct yaffs_tags_handler { +- int (*write_chunk_tags_fn) (struct yaffs_dev *dev, +- int nand_chunk, const u8 *data, +- const struct yaffs_ext_tags *tags); +- int (*read_chunk_tags_fn) (struct yaffs_dev *dev, +- int nand_chunk, u8 *data, +- struct yaffs_ext_tags *tags); +- +- int (*query_block_fn) (struct yaffs_dev *dev, int block_no, +- enum yaffs_block_state *state, +- u32 *seq_number); +- int (*mark_bad_fn) (struct yaffs_dev *dev, int block_no); +-}; +- +-struct yaffs_dev { +- struct yaffs_param param; +- struct yaffs_driver drv; +- struct yaffs_tags_handler tagger; +- +- /* Context storage. Holds extra OS specific data for this device */ +- +- void *os_context; +- void *driver_context; +- +- struct list_head dev_list; +- +- /* Runtime parameters. Set up by YAFFS. */ +- int data_bytes_per_chunk; +- +- /* Non-wide tnode stuff */ +- u16 chunk_grp_bits; /* Number of bits that need to be resolved if +- * the tnodes are not wide enough. +- */ +- u16 chunk_grp_size; /* == 2^^chunk_grp_bits */ +- +- /* Stuff to support wide tnodes */ +- u32 tnode_width; +- u32 tnode_mask; +- u32 tnode_size; +- +- /* Stuff for figuring out file offset to chunk conversions */ +- u32 chunk_shift; /* Shift value */ +- u32 chunk_div; /* Divisor after shifting: 1 for 2^n sizes */ +- u32 chunk_mask; /* Mask to use for power-of-2 case */ +- +- int is_mounted; +- int read_only; +- int is_checkpointed; +- +- /* Stuff to support block offsetting to support start block zero */ +- int internal_start_block; +- int internal_end_block; +- int block_offset; +- int chunk_offset; +- +- /* Runtime checkpointing stuff */ +- int checkpt_page_seq; /* running sequence number of checkpt pages */ +- int checkpt_byte_count; +- int checkpt_byte_offs; +- u8 *checkpt_buffer; +- int checkpt_open_write; +- int blocks_in_checkpt; +- int checkpt_cur_chunk; +- int checkpt_cur_block; +- int checkpt_next_block; +- int *checkpt_block_list; +- int checkpt_max_blocks; +- u32 checkpt_sum; +- u32 checkpt_xor; +- +- int checkpoint_blocks_required; /* Number of blocks needed to store +- * current checkpoint set */ +- +- /* Block Info */ +- struct yaffs_block_info *block_info; +- u8 *chunk_bits; /* bitmap of chunks in use */ +- unsigned block_info_alt:1; /* allocated using alternative alloc */ +- unsigned chunk_bits_alt:1; /* allocated using alternative alloc */ +- int chunk_bit_stride; /* Number of bytes of chunk_bits per block. +- * Must be consistent with chunks_per_block. +- */ +- +- int n_erased_blocks; +- int alloc_block; /* Current block being allocated off */ +- u32 alloc_page; +- int alloc_block_finder; /* Used to search for next allocation block */ +- +- /* Object and Tnode memory management */ +- void *allocator; +- int n_obj; +- int n_tnodes; +- +- int n_hardlinks; +- +- struct yaffs_obj_bucket obj_bucket[YAFFS_NOBJECT_BUCKETS]; +- u32 bucket_finder; +- +- int n_free_chunks; +- +- /* Garbage collection control */ +- u32 *gc_cleanup_list; /* objects to delete at the end of a GC. */ +- u32 n_clean_ups; +- +- unsigned has_pending_prioritised_gc; /* We think this device might +- have pending prioritised gcs */ +- unsigned gc_disable; +- unsigned gc_block_finder; +- unsigned gc_dirtiest; +- unsigned gc_pages_in_use; +- unsigned gc_not_done; +- unsigned gc_block; +- unsigned gc_chunk; +- unsigned gc_skip; +- struct yaffs_summary_tags *gc_sum_tags; +- +- /* Special directories */ +- struct yaffs_obj *root_dir; +- struct yaffs_obj *lost_n_found; +- +- int buffered_block; /* Which block is buffered here? */ +- int doing_buffered_block_rewrite; +- +- struct yaffs_cache *cache; +- int cache_last_use; +- +- /* Stuff for background deletion and unlinked files. */ +- struct yaffs_obj *unlinked_dir; /* Directory where unlinked and deleted +- files live. */ +- struct yaffs_obj *del_dir; /* Directory where deleted objects are +- sent to disappear. */ +- struct yaffs_obj *unlinked_deletion; /* Current file being +- background deleted. */ +- int n_deleted_files; /* Count of files awaiting deletion; */ +- int n_unlinked_files; /* Count of unlinked files. */ +- int n_bg_deletions; /* Count of background deletions. */ +- +- /* Temporary buffer management */ +- struct yaffs_buffer temp_buffer[YAFFS_N_TEMP_BUFFERS]; +- int max_temp; +- int temp_in_use; +- int unmanaged_buffer_allocs; +- int unmanaged_buffer_deallocs; +- +- /* yaffs2 runtime stuff */ +- unsigned seq_number; /* Sequence number of currently +- allocating block */ +- unsigned oldest_dirty_seq; +- unsigned oldest_dirty_block; +- +- /* Block refreshing */ +- int refresh_skip; /* A skip down counter. +- * Refresh happens when this gets to zero. */ +- +- /* Dirty directory handling */ +- struct list_head dirty_dirs; /* List of dirty directories */ +- +- /* Summary */ +- int chunks_per_summary; +- struct yaffs_summary_tags *sum_tags; +- +- /* Statistics */ +- u32 n_page_writes; +- u32 n_page_reads; +- u32 n_erasures; +- u32 n_bad_markings; +- u32 n_erase_failures; +- u32 n_gc_copies; +- u32 all_gcs; +- u32 passive_gc_count; +- u32 oldest_dirty_gc_count; +- u32 n_gc_blocks; +- u32 bg_gcs; +- u32 n_retried_writes; +- u32 n_retired_blocks; +- u32 n_ecc_fixed; +- u32 n_ecc_unfixed; +- u32 n_tags_ecc_fixed; +- u32 n_tags_ecc_unfixed; +- u32 n_deletions; +- u32 n_unmarked_deletions; +- u32 refresh_count; +- u32 cache_hits; +- u32 tags_used; +- u32 summary_used; +- +-}; +- +-/* The CheckpointDevice structure holds the device information that changes +- *at runtime and must be preserved over unmount/mount cycles. +- */ +-struct yaffs_checkpt_dev { +- int struct_type; +- int n_erased_blocks; +- int alloc_block; /* Current block being allocated off */ +- u32 alloc_page; +- int n_free_chunks; +- +- int n_deleted_files; /* Count of files awaiting deletion; */ +- int n_unlinked_files; /* Count of unlinked files. */ +- int n_bg_deletions; /* Count of background deletions. */ +- +- /* yaffs2 runtime stuff */ +- unsigned seq_number; /* Sequence number of currently +- * allocating block */ +- +-}; +- +-struct yaffs_checkpt_validity { +- int struct_type; +- u32 magic; +- u32 version; +- u32 head; +-}; +- +-struct yaffs_shadow_fixer { +- int obj_id; +- int shadowed_id; +- struct yaffs_shadow_fixer *next; +-}; +- +-/* Structure for doing xattr modifications */ +-struct yaffs_xattr_mod { +- int set; /* If 0 then this is a deletion */ +- const YCHAR *name; +- const void *data; +- int size; +- int flags; +- int result; +-}; +- +-/*----------------------- YAFFS Functions -----------------------*/ +- +-int yaffs_guts_initialise(struct yaffs_dev *dev); +-void yaffs_deinitialise(struct yaffs_dev *dev); +- +-int yaffs_get_n_free_chunks(struct yaffs_dev *dev); +- +-int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name, +- struct yaffs_obj *new_dir, const YCHAR * new_name); +- +-int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR * name); +-int yaffs_del_obj(struct yaffs_obj *obj); +- +-int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR * name, int buffer_size); +-loff_t yaffs_get_obj_length(struct yaffs_obj *obj); +-int yaffs_get_obj_inode(struct yaffs_obj *obj); +-unsigned yaffs_get_obj_type(struct yaffs_obj *obj); +-int yaffs_get_obj_link_count(struct yaffs_obj *obj); +- +-/* File operations */ +-int yaffs_file_rd(struct yaffs_obj *obj, u8 * buffer, loff_t offset, +- int n_bytes); +-int yaffs_wr_file(struct yaffs_obj *obj, const u8 * buffer, loff_t offset, +- int n_bytes, int write_trhrough); +-int yaffs_resize_file(struct yaffs_obj *obj, loff_t new_size); +- +-struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent, +- const YCHAR *name, u32 mode, u32 uid, +- u32 gid); +- +-int yaffs_flush_file(struct yaffs_obj *obj, int update_time, int data_sync); +- +-/* Flushing and checkpointing */ +-void yaffs_flush_whole_cache(struct yaffs_dev *dev); +- +-int yaffs_checkpoint_save(struct yaffs_dev *dev); +-int yaffs_checkpoint_restore(struct yaffs_dev *dev); +- +-/* Directory operations */ +-struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name, +- u32 mode, u32 uid, u32 gid); +-struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *the_dir, +- const YCHAR *name); +-struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number); +- +-/* Link operations */ +-struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR *name, +- struct yaffs_obj *equiv_obj); +- +-struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj); +- +-/* Symlink operations */ +-struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent, +- const YCHAR *name, u32 mode, u32 uid, +- u32 gid, const YCHAR *alias); +-YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj); +- +-/* Special inodes (fifos, sockets and devices) */ +-struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent, +- const YCHAR *name, u32 mode, u32 uid, +- u32 gid, u32 rdev); +- +-int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR *name, +- const void *value, int size, int flags); +-int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR *name, void *value, +- int size); +-int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size); +-int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR *name); +- +-/* Special directories */ +-struct yaffs_obj *yaffs_root(struct yaffs_dev *dev); +-struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev); +- +-void yaffs_handle_defered_free(struct yaffs_obj *obj); +- +-void yaffs_update_dirty_dirs(struct yaffs_dev *dev); +- +-int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency); +- +-/* Debug dump */ +-int yaffs_dump_obj(struct yaffs_obj *obj); +- +-void yaffs_guts_test(struct yaffs_dev *dev); +- +-/* A few useful functions to be used within the core files*/ +-void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash, +- int lyn); +-int yaffs_check_ff(u8 *buffer, int n_bytes); +-void yaffs_handle_chunk_error(struct yaffs_dev *dev, +- struct yaffs_block_info *bi); +- +-u8 *yaffs_get_temp_buffer(struct yaffs_dev *dev); +-void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer); +- +-struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev, +- int number, +- enum yaffs_obj_type type); +-int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk, +- int nand_chunk, int in_scan); +-void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR *name); +-void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj, +- const struct yaffs_obj_hdr *oh); +-void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj); +-YCHAR *yaffs_clone_str(const YCHAR *str); +-void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list); +-void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no); +-int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, +- int force, int is_shrink, int shadows, +- struct yaffs_xattr_mod *xop); +-void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id, +- int backward_scanning); +-int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks); +-struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev); +-struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev, +- struct yaffs_file_var *file_struct, +- u32 chunk_id, +- struct yaffs_tnode *passed_tn); +- +-int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset, +- int n_bytes, int write_trhrough); +-void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size); +-void yaffs_skip_rest_of_block(struct yaffs_dev *dev); +- +-int yaffs_count_free_chunks(struct yaffs_dev *dev); +- +-struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev, +- struct yaffs_file_var *file_struct, +- u32 chunk_id); +- +-u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn, +- unsigned pos); +- +-int yaffs_is_non_empty_dir(struct yaffs_obj *obj); +- +-int yaffs_format_dev(struct yaffs_dev *dev); +- +-void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr, +- int *chunk_out, u32 *offset_out); +-/* +- * Marshalling functions to get loff_t file sizes into aand out of +- * object headers. +- */ +-void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize); +-loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh); +-loff_t yaffs_max_file_size(struct yaffs_dev *dev); +- +- +-#endif +diff --git a/fs/yaffs2/yaffs_linux.h b/fs/yaffs2/yaffs_linux.h +deleted file mode 100644 +index c20ab14..0000000 +--- a/fs/yaffs2/yaffs_linux.h ++++ /dev/null +@@ -1,48 +0,0 @@ +-/* +- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU Lesser General Public License version 2.1 as +- * published by the Free Software Foundation. +- * +- * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +- */ +- +-#ifndef __YAFFS_LINUX_H__ +-#define __YAFFS_LINUX_H__ +- +-#include "yportenv.h" +- +-struct yaffs_linux_context { +- struct list_head context_list; /* List of these we have mounted */ +- struct yaffs_dev *dev; +- struct super_block *super; +- struct task_struct *bg_thread; /* Background thread for this device */ +- int bg_running; +- struct mutex gross_lock; /* Gross locking mutex*/ +- u8 *spare_buffer; /* For mtdif2 use. Don't know the buffer size +- * at compile time so we have to allocate it. +- */ +- struct list_head search_contexts; +- struct task_struct *readdir_process; +- unsigned mount_id; +- int dirty; +-}; +- +-#define yaffs_dev_to_lc(dev) ((struct yaffs_linux_context *)((dev)->os_context)) +-#define yaffs_dev_to_mtd(dev) ((struct mtd_info *)((dev)->driver_context)) +- +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) +-#define WRITE_SIZE_STR "writesize" +-#define WRITE_SIZE(mtd) ((mtd)->writesize) +-#else +-#define WRITE_SIZE_STR "oobblock" +-#define WRITE_SIZE(mtd) ((mtd)->oobblock) +-#endif +- +-#endif +diff --git a/fs/yaffs2/yaffs_mtdif.c b/fs/yaffs2/yaffs_mtdif.c +deleted file mode 100644 +index 265dd78..0000000 +--- a/fs/yaffs2/yaffs_mtdif.c ++++ /dev/null +@@ -1,294 +0,0 @@ +-/* +- * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * 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 "yportenv.h" +- +-#include "yaffs_mtdif.h" +- +-#include "linux/mtd/mtd.h" +-#include "linux/types.h" +-#include "linux/time.h" +-#include "linux/mtd/nand.h" +-#include "linux/kernel.h" +-#include "linux/version.h" +-#include "linux/types.h" +- +-#include "yaffs_trace.h" +-#include "yaffs_guts.h" +-#include "yaffs_linux.h" +- +- +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) +-#define MTD_OPS_AUTO_OOB MTD_OOB_AUTO +-#endif +- +- +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) +-#define mtd_erase(m, ei) (m)->erase(m, ei) +-#define mtd_write_oob(m, addr, pops) (m)->write_oob(m, addr, pops) +-#define mtd_read_oob(m, addr, pops) (m)->read_oob(m, addr, pops) +-#define mtd_block_isbad(m, offs) (m)->block_isbad(m, offs) +-#define mtd_block_markbad(m, offs) (m)->block_markbad(m, offs) +-#endif +- +- +- +-int nandmtd_erase_block(struct yaffs_dev *dev, int block_no) +-{ +- struct mtd_info *mtd = yaffs_dev_to_mtd(dev); +- u32 addr = +- ((loff_t) block_no) * dev->param.total_bytes_per_chunk * +- dev->param.chunks_per_block; +- struct erase_info ei; +- int retval = 0; +- +- ei.mtd = mtd; +- ei.addr = addr; +- ei.len = dev->param.total_bytes_per_chunk * dev->param.chunks_per_block; +- ei.time = 1000; +- ei.retries = 2; +- ei.callback = NULL; +- ei.priv = (u_long) dev; +- +- retval = mtd_erase(mtd, &ei); +- +- if (retval == 0) +- return YAFFS_OK; +- +- return YAFFS_FAIL; +-} +- +- +-static int yaffs_mtd_write(struct yaffs_dev *dev, int nand_chunk, +- const u8 *data, int data_len, +- const u8 *oob, int oob_len) +-{ +- struct mtd_info *mtd = yaffs_dev_to_mtd(dev); +- loff_t addr; +- struct mtd_oob_ops ops; +- int retval; +- +- addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk; +- memset(&ops, 0, sizeof(ops)); +- ops.mode = MTD_OPS_AUTO_OOB; +- ops.len = (data) ? data_len : 0; +- ops.ooblen = oob_len; +- ops.datbuf = (u8 *)data; +- ops.oobbuf = (u8 *)oob; +- +- retval = mtd_write_oob(mtd, addr, &ops); +- if (retval) { +- yaffs_trace(YAFFS_TRACE_MTD, +- "write_oob failed, chunk %d, mtd error %d", +- nand_chunk, retval); +- } +- return retval ? YAFFS_FAIL : YAFFS_OK; +-} +- +-static int yaffs_mtd_read(struct yaffs_dev *dev, int nand_chunk, +- u8 *data, int data_len, +- u8 *oob, int oob_len, +- enum yaffs_ecc_result *ecc_result) +-{ +- struct mtd_info *mtd = yaffs_dev_to_mtd(dev); +- loff_t addr; +- struct mtd_oob_ops ops; +- int retval; +- +- addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk; +- memset(&ops, 0, sizeof(ops)); +- ops.mode = MTD_OPS_AUTO_OOB; +- ops.len = (data) ? data_len : 0; +- ops.ooblen = oob_len; +- ops.datbuf = data; +- ops.oobbuf = oob; +- +-#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 20)) +- /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug; +- * help it out with ops.len = ops.ooblen when ops.datbuf == NULL. +- */ +- ops.len = (ops.datbuf) ? ops.len : ops.ooblen; +-#endif +- /* Read page and oob using MTD. +- * Check status and determine ECC result. +- */ +- retval = mtd_read_oob(mtd, addr, &ops); +- if (retval) +- yaffs_trace(YAFFS_TRACE_MTD, +- "read_oob failed, chunk %d, mtd error %d", +- nand_chunk, retval); +- +- switch (retval) { +- case 0: +- /* no error */ +- if(ecc_result) +- *ecc_result = YAFFS_ECC_RESULT_NO_ERROR; +- break; +- +- case -EUCLEAN: +- /* MTD's ECC fixed the data */ +- if(ecc_result) +- *ecc_result = YAFFS_ECC_RESULT_FIXED; +- dev->n_ecc_fixed++; +- break; +- +- case -EBADMSG: +- default: +- /* MTD's ECC could not fix the data */ +- dev->n_ecc_unfixed++; +- if(ecc_result) +- *ecc_result = YAFFS_ECC_RESULT_UNFIXED; +- return YAFFS_FAIL; +- } +- +- return YAFFS_OK; +-} +- +-static int yaffs_mtd_erase(struct yaffs_dev *dev, int block_no) +-{ +- struct mtd_info *mtd = yaffs_dev_to_mtd(dev); +- +- loff_t addr; +- struct erase_info ei; +- int retval = 0; +- u32 block_size; +- +- block_size = dev->param.total_bytes_per_chunk * +- dev->param.chunks_per_block; +- addr = ((loff_t) block_no) * block_size; +- +- ei.mtd = mtd; +- ei.addr = addr; +- ei.len = block_size; +- ei.time = 1000; +- ei.retries = 2; +- ei.callback = NULL; +- ei.priv = (u_long) dev; +- +- retval = mtd_erase(mtd, &ei); +- +- if (retval == 0) +- return YAFFS_OK; +- +- return YAFFS_FAIL; +-} +- +-static int yaffs_mtd_mark_bad(struct yaffs_dev *dev, int block_no) +-{ +- struct mtd_info *mtd = yaffs_dev_to_mtd(dev); +- int blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk; +- int retval; +- +- yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", block_no); +- +- retval = mtd_block_markbad(mtd, (loff_t) blocksize * block_no); +- return (retval) ? YAFFS_FAIL : YAFFS_OK; +-} +- +-static int yaffs_mtd_check_bad(struct yaffs_dev *dev, int block_no) +-{ +- struct mtd_info *mtd = yaffs_dev_to_mtd(dev); +- int blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk; +- int retval; +- +- yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "checking block %d bad", block_no); +- +- retval = mtd_block_isbad(mtd, (loff_t) blocksize * block_no); +- return (retval) ? YAFFS_FAIL : YAFFS_OK; +-} +- +-static int yaffs_mtd_initialise(struct yaffs_dev *dev) +-{ +- return YAFFS_OK; +-} +- +-static int yaffs_mtd_deinitialise(struct yaffs_dev *dev) +-{ +- return YAFFS_OK; +-} +- +- +-void yaffs_mtd_drv_install(struct yaffs_dev *dev) +-{ +- struct yaffs_driver *drv = &dev->drv; +- +- drv->drv_write_chunk_fn = yaffs_mtd_write; +- drv->drv_read_chunk_fn = yaffs_mtd_read; +- drv->drv_erase_fn = yaffs_mtd_erase; +- drv->drv_mark_bad_fn = yaffs_mtd_mark_bad; +- drv->drv_check_bad_fn = yaffs_mtd_check_bad; +- drv->drv_initialise_fn = yaffs_mtd_initialise; +- drv->drv_deinitialise_fn = yaffs_mtd_deinitialise; +-} +- +- +-struct mtd_info * yaffs_get_mtd_device(dev_t sdev) +-{ +- struct mtd_info *mtd; +- +- mtd = yaffs_get_mtd_device(sdev); +- +- /* Check it's an mtd device..... */ +- if (MAJOR(sdev) != MTD_BLOCK_MAJOR) +- return NULL; /* This isn't an mtd device */ +- +- /* Check it's NAND */ +- if (mtd->type != MTD_NANDFLASH) { +- yaffs_trace(YAFFS_TRACE_ALWAYS, +- "yaffs: MTD device is not NAND it's type %d", +- mtd->type); +- return NULL; +- } +- +- yaffs_trace(YAFFS_TRACE_OS, " %s %d", WRITE_SIZE_STR, WRITE_SIZE(mtd)); +- yaffs_trace(YAFFS_TRACE_OS, " oobsize %d", mtd->oobsize); +- yaffs_trace(YAFFS_TRACE_OS, " erasesize %d", mtd->erasesize); +-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) +- yaffs_trace(YAFFS_TRACE_OS, " size %u", mtd->size); +-#else +- yaffs_trace(YAFFS_TRACE_OS, " size %lld", mtd->size); +-#endif +- +- return mtd; +-} +- +-int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags) +-{ +- if (yaffs_version == 2) { +- if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE || +- mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) && +- !inband_tags) { +- yaffs_trace(YAFFS_TRACE_ALWAYS, +- "MTD device does not have the right page sizes" +- ); +- return -1; +- } +- } else { +- if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK || +- mtd->oobsize != YAFFS_BYTES_PER_SPARE) { +- yaffs_trace(YAFFS_TRACE_ALWAYS, +- "MTD device does not support have the right page sizes" +- ); +- return -1; +- } +- } +- +- return 0; +-} +- +- +-void yaffs_put_mtd_device(struct mtd_info *mtd) +-{ +- if(mtd) +- put_mtd_device(mtd); +-} +diff --git a/fs/yaffs2/yaffs_mtdif.h b/fs/yaffs2/yaffs_mtdif.h +deleted file mode 100644 +index 9cff224..0000000 +--- a/fs/yaffs2/yaffs_mtdif.h ++++ /dev/null +@@ -1,25 +0,0 @@ +-/* +- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU Lesser General Public License version 2.1 as +- * published by the Free Software Foundation. +- * +- * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +- */ +- +-#ifndef __YAFFS_MTDIF_H__ +-#define __YAFFS_MTDIF_H__ +- +-#include "yaffs_guts.h" +- +-void yaffs_mtd_drv_install(struct yaffs_dev *dev); +-struct mtd_info * yaffs_get_mtd_device(dev_t sdev); +-void yaffs_put_mtd_device(struct mtd_info *mtd); +-int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags); +-#endif +diff --git a/fs/yaffs2/yaffs_nameval.c b/fs/yaffs2/yaffs_nameval.c +deleted file mode 100644 +index 4bdf4ed..0000000 +--- a/fs/yaffs2/yaffs_nameval.c ++++ /dev/null +@@ -1,208 +0,0 @@ +-/* +- * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * 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. +- */ +- +-/* +- * This simple implementation of a name-value store assumes a small number of +-* values and fits into a small finite buffer. +- * +- * Each attribute is stored as a record: +- * sizeof(int) bytes record size. +- * strnlen+1 bytes name null terminated. +- * nbytes value. +- * ---------- +- * total size stored in record size +- * +- * This code has not been tested with unicode yet. +- */ +- +-#include "yaffs_nameval.h" +- +-#include "yportenv.h" +- +-static int nval_find(const char *xb, int xb_size, const YCHAR *name, +- int *exist_size) +-{ +- int pos = 0; +- int size; +- +- memcpy(&size, xb, sizeof(int)); +- while (size > 0 && (size < xb_size) && (pos + size < xb_size)) { +- if (!strncmp((YCHAR *) (xb + pos + sizeof(int)), +- name, size)) { +- if (exist_size) +- *exist_size = size; +- return pos; +- } +- pos += size; +- if (pos < xb_size - sizeof(int)) +- memcpy(&size, xb + pos, sizeof(int)); +- else +- size = 0; +- } +- if (exist_size) +- *exist_size = 0; +- return -ENODATA; +-} +- +-static int nval_used(const char *xb, int xb_size) +-{ +- int pos = 0; +- int size; +- +- memcpy(&size, xb + pos, sizeof(int)); +- while (size > 0 && (size < xb_size) && (pos + size < xb_size)) { +- pos += size; +- if (pos < xb_size - sizeof(int)) +- memcpy(&size, xb + pos, sizeof(int)); +- else +- size = 0; +- } +- return pos; +-} +- +-int nval_del(char *xb, int xb_size, const YCHAR *name) +-{ +- int pos = nval_find(xb, xb_size, name, NULL); +- int size; +- +- if (pos < 0 || pos >= xb_size) +- return -ENODATA; +- +- /* Find size, shift rest over this record, +- * then zero out the rest of buffer */ +- memcpy(&size, xb + pos, sizeof(int)); +- memcpy(xb + pos, xb + pos + size, xb_size - (pos + size)); +- memset(xb + (xb_size - size), 0, size); +- return 0; +-} +- +-int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, +- int bsize, int flags) +-{ +- int pos; +- int namelen = strnlen(name, xb_size); +- int reclen; +- int size_exist = 0; +- int space; +- int start; +- +- pos = nval_find(xb, xb_size, name, &size_exist); +- +- if (flags & XATTR_CREATE && pos >= 0) +- return -EEXIST; +- if (flags & XATTR_REPLACE && pos < 0) +- return -ENODATA; +- +- start = nval_used(xb, xb_size); +- space = xb_size - start + size_exist; +- +- reclen = (sizeof(int) + namelen + 1 + bsize); +- +- if (reclen > space) +- return -ENOSPC; +- +- if (pos >= 0) { +- nval_del(xb, xb_size, name); +- start = nval_used(xb, xb_size); +- } +- +- pos = start; +- +- memcpy(xb + pos, &reclen, sizeof(int)); +- pos += sizeof(int); +- strncpy((YCHAR *) (xb + pos), name, reclen); +- pos += (namelen + 1); +- memcpy(xb + pos, buf, bsize); +- return 0; +-} +- +-int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf, +- int bsize) +-{ +- int pos = nval_find(xb, xb_size, name, NULL); +- int size; +- +- if (pos >= 0 && pos < xb_size) { +- +- memcpy(&size, xb + pos, sizeof(int)); +- pos += sizeof(int); /* advance past record length */ +- size -= sizeof(int); +- +- /* Advance over name string */ +- while (xb[pos] && size > 0 && pos < xb_size) { +- pos++; +- size--; +- } +- /*Advance over NUL */ +- pos++; +- size--; +- +- /* If bsize is zero then this is a size query. +- * Return the size, but don't copy. +- */ +- if (!bsize) +- return size; +- +- if (size <= bsize) { +- memcpy(buf, xb + pos, size); +- return size; +- } +- } +- if (pos >= 0) +- return -ERANGE; +- +- return -ENODATA; +-} +- +-int nval_list(const char *xb, int xb_size, char *buf, int bsize) +-{ +- int pos = 0; +- int size; +- int name_len; +- int ncopied = 0; +- int filled = 0; +- +- memcpy(&size, xb + pos, sizeof(int)); +- while (size > sizeof(int) && +- size <= xb_size && +- (pos + size) < xb_size && +- !filled) { +- pos += sizeof(int); +- size -= sizeof(int); +- name_len = strnlen((YCHAR *) (xb + pos), size); +- if (ncopied + name_len + 1 < bsize) { +- memcpy(buf, xb + pos, name_len * sizeof(YCHAR)); +- buf += name_len; +- *buf = '\0'; +- buf++; +- if (sizeof(YCHAR) > 1) { +- *buf = '\0'; +- buf++; +- } +- ncopied += (name_len + 1); +- } else { +- filled = 1; +- } +- pos += size; +- if (pos < xb_size - sizeof(int)) +- memcpy(&size, xb + pos, sizeof(int)); +- else +- size = 0; +- } +- return ncopied; +-} +- +-int nval_hasvalues(const char *xb, int xb_size) +-{ +- return nval_used(xb, xb_size) > 0; +-} +diff --git a/fs/yaffs2/yaffs_nameval.h b/fs/yaffs2/yaffs_nameval.h +deleted file mode 100644 +index 951e64f..0000000 +--- a/fs/yaffs2/yaffs_nameval.h ++++ /dev/null +@@ -1,28 +0,0 @@ +-/* +- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU Lesser General Public License version 2.1 as +- * published by the Free Software Foundation. +- * +- * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +- */ +- +-#ifndef __NAMEVAL_H__ +-#define __NAMEVAL_H__ +- +-#include "yportenv.h" +- +-int nval_del(char *xb, int xb_size, const YCHAR * name); +-int nval_set(char *xb, int xb_size, const YCHAR * name, const char *buf, +- int bsize, int flags); +-int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf, +- int bsize); +-int nval_list(const char *xb, int xb_size, char *buf, int bsize); +-int nval_hasvalues(const char *xb, int xb_size); +-#endif +diff --git a/fs/yaffs2/yaffs_nand.c b/fs/yaffs2/yaffs_nand.c +deleted file mode 100644 +index 9afd5ec..0000000 +--- a/fs/yaffs2/yaffs_nand.c ++++ /dev/null +@@ -1,118 +0,0 @@ +-/* +- * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * 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 "yaffs_nand.h" +-#include "yaffs_tagscompat.h" +- +-#include "yaffs_getblockinfo.h" +-#include "yaffs_summary.h" +- +-static int apply_chunk_offset(struct yaffs_dev *dev, int chunk) +-{ +- return chunk - dev->chunk_offset; +-} +- +-int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk, +- u8 *buffer, struct yaffs_ext_tags *tags) +-{ +- int result; +- struct yaffs_ext_tags local_tags; +- int flash_chunk = apply_chunk_offset(dev, nand_chunk); +- +- dev->n_page_reads++; +- +- /* If there are no tags provided use local tags. */ +- if (!tags) +- tags = &local_tags; +- +- result = dev->tagger.read_chunk_tags_fn(dev, flash_chunk, buffer, tags); +- if (tags && tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) { +- +- struct yaffs_block_info *bi; +- bi = yaffs_get_block_info(dev, +- nand_chunk / +- dev->param.chunks_per_block); +- yaffs_handle_chunk_error(dev, bi); +- } +- return result; +-} +- +-int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev, +- int nand_chunk, +- const u8 *buffer, struct yaffs_ext_tags *tags) +-{ +- int result; +- int flash_chunk = apply_chunk_offset(dev, nand_chunk); +- +- dev->n_page_writes++; +- +- if (!tags) { +- yaffs_trace(YAFFS_TRACE_ERROR, "Writing with no tags"); +- BUG(); +- return YAFFS_FAIL; +- } +- +- tags->seq_number = dev->seq_number; +- tags->chunk_used = 1; +- yaffs_trace(YAFFS_TRACE_WRITE, +- "Writing chunk %d tags %d %d", +- nand_chunk, tags->obj_id, tags->chunk_id); +- +- result = dev->tagger.write_chunk_tags_fn(dev, flash_chunk, +- buffer, tags); +- +- yaffs_summary_add(dev, tags, nand_chunk); +- +- return result; +-} +- +-int yaffs_mark_bad(struct yaffs_dev *dev, int block_no) +-{ +- block_no -= dev->block_offset; +- dev->n_bad_markings++; +- return dev->tagger.mark_bad_fn(dev, block_no); +-} +- +- +-int yaffs_query_init_block_state(struct yaffs_dev *dev, +- int block_no, +- enum yaffs_block_state *state, +- u32 *seq_number) +-{ +- block_no -= dev->block_offset; +- return dev->tagger.query_block_fn(dev, block_no, state, seq_number); +-} +- +-int yaffs_erase_block(struct yaffs_dev *dev, int block_no) +-{ +- int result; +- +- block_no -= dev->block_offset; +- dev->n_erasures++; +- result = dev->drv.drv_erase_fn(dev, block_no); +- return result; +-} +- +-int yaffs_init_nand(struct yaffs_dev *dev) +-{ +- if (dev->drv.drv_initialise_fn) +- return dev->drv.drv_initialise_fn(dev); +- return YAFFS_OK; +-} +- +-int yaffs_deinit_nand(struct yaffs_dev *dev) +-{ +- if (dev->drv.drv_deinitialise_fn) +- return dev->drv.drv_deinitialise_fn(dev); +- return YAFFS_OK; +-} +diff --git a/fs/yaffs2/yaffs_nand.h b/fs/yaffs2/yaffs_nand.h +deleted file mode 100644 +index 804e97a..0000000 +--- a/fs/yaffs2/yaffs_nand.h ++++ /dev/null +@@ -1,39 +0,0 @@ +-/* +- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU Lesser General Public License version 2.1 as +- * published by the Free Software Foundation. +- * +- * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +- */ +- +-#ifndef __YAFFS_NAND_H__ +-#define __YAFFS_NAND_H__ +-#include "yaffs_guts.h" +- +-int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk, +- u8 *buffer, struct yaffs_ext_tags *tags); +- +-int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev, +- int nand_chunk, +- const u8 *buffer, struct yaffs_ext_tags *tags); +- +-int yaffs_mark_bad(struct yaffs_dev *dev, int block_no); +- +-int yaffs_query_init_block_state(struct yaffs_dev *dev, +- int block_no, +- enum yaffs_block_state *state, +- unsigned *seq_number); +- +-int yaffs_erase_block(struct yaffs_dev *dev, int flash_block); +- +-int yaffs_init_nand(struct yaffs_dev *dev); +-int yaffs_deinit_nand(struct yaffs_dev *dev); +- +-#endif +diff --git a/fs/yaffs2/yaffs_packedtags1.c b/fs/yaffs2/yaffs_packedtags1.c +deleted file mode 100644 +index dd9a331..0000000 +--- a/fs/yaffs2/yaffs_packedtags1.c ++++ /dev/null +@@ -1,56 +0,0 @@ +-/* +- * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * 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 "yaffs_packedtags1.h" +-#include "yportenv.h" +- +-static const u8 all_ff[20] = { +- 0xff, 0xff, 0xff, 0xff, +- 0xff, 0xff, 0xff, 0xff, +- 0xff, 0xff, 0xff, 0xff, +- 0xff, 0xff, 0xff, 0xff, +- 0xff, 0xff, 0xff, 0xff +-}; +- +-void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt, +- const struct yaffs_ext_tags *t) +-{ +- pt->chunk_id = t->chunk_id; +- pt->serial_number = t->serial_number; +- pt->n_bytes = t->n_bytes; +- pt->obj_id = t->obj_id; +- pt->ecc = 0; +- pt->deleted = (t->is_deleted) ? 0 : 1; +- pt->unused_stuff = 0; +- pt->should_be_ff = 0xffffffff; +-} +- +-void yaffs_unpack_tags1(struct yaffs_ext_tags *t, +- const struct yaffs_packed_tags1 *pt) +-{ +- +- if (memcmp(all_ff, pt, sizeof(struct yaffs_packed_tags1))) { +- t->block_bad = 0; +- if (pt->should_be_ff != 0xffffffff) +- t->block_bad = 1; +- t->chunk_used = 1; +- t->obj_id = pt->obj_id; +- t->chunk_id = pt->chunk_id; +- t->n_bytes = pt->n_bytes; +- t->ecc_result = YAFFS_ECC_RESULT_NO_ERROR; +- t->is_deleted = (pt->deleted) ? 0 : 1; +- t->serial_number = pt->serial_number; +- } else { +- memset(t, 0, sizeof(struct yaffs_ext_tags)); +- } +-} +diff --git a/fs/yaffs2/yaffs_packedtags1.h b/fs/yaffs2/yaffs_packedtags1.h +deleted file mode 100644 +index b80f0a5..0000000 +--- a/fs/yaffs2/yaffs_packedtags1.h ++++ /dev/null +@@ -1,39 +0,0 @@ +-/* +- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU Lesser General Public License version 2.1 as +- * published by the Free Software Foundation. +- * +- * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +- */ +- +-/* This is used to pack YAFFS1 tags, not YAFFS2 tags. */ +- +-#ifndef __YAFFS_PACKEDTAGS1_H__ +-#define __YAFFS_PACKEDTAGS1_H__ +- +-#include "yaffs_guts.h" +- +-struct yaffs_packed_tags1 { +- unsigned chunk_id:20; +- unsigned serial_number:2; +- unsigned n_bytes:10; +- unsigned obj_id:18; +- unsigned ecc:12; +- unsigned deleted:1; +- unsigned unused_stuff:1; +- unsigned should_be_ff; +- +-}; +- +-void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt, +- const struct yaffs_ext_tags *t); +-void yaffs_unpack_tags1(struct yaffs_ext_tags *t, +- const struct yaffs_packed_tags1 *pt); +-#endif +diff --git a/fs/yaffs2/yaffs_packedtags2.c b/fs/yaffs2/yaffs_packedtags2.c +deleted file mode 100644 +index e1d18cc..0000000 +--- a/fs/yaffs2/yaffs_packedtags2.c ++++ /dev/null +@@ -1,197 +0,0 @@ +-/* +- * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * 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 "yaffs_packedtags2.h" +-#include "yportenv.h" +-#include "yaffs_trace.h" +- +-/* This code packs a set of extended tags into a binary structure for +- * NAND storage +- */ +- +-/* Some of the information is "extra" struff which can be packed in to +- * speed scanning +- * This is defined by having the EXTRA_HEADER_INFO_FLAG set. +- */ +- +-/* Extra flags applied to chunk_id */ +- +-#define EXTRA_HEADER_INFO_FLAG 0x80000000 +-#define EXTRA_SHRINK_FLAG 0x40000000 +-#define EXTRA_SHADOWS_FLAG 0x20000000 +-#define EXTRA_SPARE_FLAGS 0x10000000 +- +-#define ALL_EXTRA_FLAGS 0xf0000000 +- +-/* Also, the top 4 bits of the object Id are set to the object type. */ +-#define EXTRA_OBJECT_TYPE_SHIFT (28) +-#define EXTRA_OBJECT_TYPE_MASK ((0x0f) << EXTRA_OBJECT_TYPE_SHIFT) +- +-static void yaffs_dump_packed_tags2_tags_only( +- const struct yaffs_packed_tags2_tags_only *ptt) +-{ +- yaffs_trace(YAFFS_TRACE_MTD, +- "packed tags obj %d chunk %d byte %d seq %d", +- ptt->obj_id, ptt->chunk_id, ptt->n_bytes, ptt->seq_number); +-} +- +-static void yaffs_dump_packed_tags2(const struct yaffs_packed_tags2 *pt) +-{ +- yaffs_dump_packed_tags2_tags_only(&pt->t); +-} +- +-static void yaffs_dump_tags2(const struct yaffs_ext_tags *t) +-{ +- yaffs_trace(YAFFS_TRACE_MTD, +- "ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d", +- t->ecc_result, t->block_bad, t->chunk_used, t->obj_id, +- t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number, +- t->seq_number); +- +-} +- +-static int yaffs_check_tags_extra_packable(const struct yaffs_ext_tags *t) +-{ +- if (t->chunk_id != 0 || !t->extra_available) +- return 0; +- +- /* Check if the file size is too long to store */ +- if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE && +- (t->extra_file_size >> 31) != 0) +- return 0; +- return 1; +-} +- +-void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *ptt, +- const struct yaffs_ext_tags *t) +-{ +- ptt->chunk_id = t->chunk_id; +- ptt->seq_number = t->seq_number; +- ptt->n_bytes = t->n_bytes; +- ptt->obj_id = t->obj_id; +- +- /* Only store extra tags for object headers. +- * If it is a file then only store if the file size is short\ +- * enough to fit. +- */ +- if (yaffs_check_tags_extra_packable(t)) { +- /* Store the extra header info instead */ +- /* We save the parent object in the chunk_id */ +- ptt->chunk_id = EXTRA_HEADER_INFO_FLAG | t->extra_parent_id; +- if (t->extra_is_shrink) +- ptt->chunk_id |= EXTRA_SHRINK_FLAG; +- if (t->extra_shadows) +- ptt->chunk_id |= EXTRA_SHADOWS_FLAG; +- +- ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK; +- ptt->obj_id |= (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT); +- +- if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK) +- ptt->n_bytes = t->extra_equiv_id; +- else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE) +- ptt->n_bytes = (unsigned) t->extra_file_size; +- else +- ptt->n_bytes = 0; +- } +- +- yaffs_dump_packed_tags2_tags_only(ptt); +- yaffs_dump_tags2(t); +-} +- +-void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt, +- const struct yaffs_ext_tags *t, int tags_ecc) +-{ +- yaffs_pack_tags2_tags_only(&pt->t, t); +- +- if (tags_ecc) +- yaffs_ecc_calc_other((unsigned char *)&pt->t, +- sizeof(struct yaffs_packed_tags2_tags_only), +- &pt->ecc); +-} +- +-void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t, +- struct yaffs_packed_tags2_tags_only *ptt) +-{ +- memset(t, 0, sizeof(struct yaffs_ext_tags)); +- +- if (ptt->seq_number == 0xffffffff) +- return; +- +- t->block_bad = 0; +- t->chunk_used = 1; +- t->obj_id = ptt->obj_id; +- t->chunk_id = ptt->chunk_id; +- t->n_bytes = ptt->n_bytes; +- t->is_deleted = 0; +- t->serial_number = 0; +- t->seq_number = ptt->seq_number; +- +- /* Do extra header info stuff */ +- if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) { +- t->chunk_id = 0; +- t->n_bytes = 0; +- +- t->extra_available = 1; +- t->extra_parent_id = ptt->chunk_id & (~(ALL_EXTRA_FLAGS)); +- t->extra_is_shrink = ptt->chunk_id & EXTRA_SHRINK_FLAG ? 1 : 0; +- t->extra_shadows = ptt->chunk_id & EXTRA_SHADOWS_FLAG ? 1 : 0; +- t->extra_obj_type = ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT; +- t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK; +- +- if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK) +- t->extra_equiv_id = ptt->n_bytes; +- else +- t->extra_file_size = ptt->n_bytes; +- } +- yaffs_dump_packed_tags2_tags_only(ptt); +- yaffs_dump_tags2(t); +-} +- +-void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt, +- int tags_ecc) +-{ +- enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR; +- +- if (pt->t.seq_number != 0xffffffff && tags_ecc) { +- /* Chunk is in use and we need to do ECC */ +- +- struct yaffs_ecc_other ecc; +- int result; +- yaffs_ecc_calc_other((unsigned char *)&pt->t, +- sizeof(struct yaffs_packed_tags2_tags_only), +- &ecc); +- result = +- yaffs_ecc_correct_other((unsigned char *)&pt->t, +- sizeof(struct yaffs_packed_tags2_tags_only), +- &pt->ecc, &ecc); +- switch (result) { +- case 0: +- ecc_result = YAFFS_ECC_RESULT_NO_ERROR; +- break; +- case 1: +- ecc_result = YAFFS_ECC_RESULT_FIXED; +- break; +- case -1: +- ecc_result = YAFFS_ECC_RESULT_UNFIXED; +- break; +- default: +- ecc_result = YAFFS_ECC_RESULT_UNKNOWN; +- } +- } +- yaffs_unpack_tags2_tags_only(t, &pt->t); +- +- t->ecc_result = ecc_result; +- +- yaffs_dump_packed_tags2(pt); +- yaffs_dump_tags2(t); +-} +diff --git a/fs/yaffs2/yaffs_packedtags2.h b/fs/yaffs2/yaffs_packedtags2.h +deleted file mode 100644 +index 675e719..0000000 +--- a/fs/yaffs2/yaffs_packedtags2.h ++++ /dev/null +@@ -1,47 +0,0 @@ +-/* +- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU Lesser General Public License version 2.1 as +- * published by the Free Software Foundation. +- * +- * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +- */ +- +-/* This is used to pack YAFFS2 tags, not YAFFS1tags. */ +- +-#ifndef __YAFFS_PACKEDTAGS2_H__ +-#define __YAFFS_PACKEDTAGS2_H__ +- +-#include "yaffs_guts.h" +-#include "yaffs_ecc.h" +- +-struct yaffs_packed_tags2_tags_only { +- unsigned seq_number; +- unsigned obj_id; +- unsigned chunk_id; +- unsigned n_bytes; +-}; +- +-struct yaffs_packed_tags2 { +- struct yaffs_packed_tags2_tags_only t; +- struct yaffs_ecc_other ecc; +-}; +- +-/* Full packed tags with ECC, used for oob tags */ +-void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt, +- const struct yaffs_ext_tags *t, int tags_ecc); +-void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt, +- int tags_ecc); +- +-/* Only the tags part (no ECC for use with inband tags */ +-void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *pt, +- const struct yaffs_ext_tags *t); +-void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t, +- struct yaffs_packed_tags2_tags_only *pt); +-#endif +diff --git a/fs/yaffs2/yaffs_summary.c b/fs/yaffs2/yaffs_summary.c +deleted file mode 100644 +index 6f3c783..0000000 +--- a/fs/yaffs2/yaffs_summary.c ++++ /dev/null +@@ -1,313 +0,0 @@ +-/* +- * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * 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. +- */ +- +-/* Summaries write the useful part of the tags for the chunks in a block into an +- * an array which is written to the last n chunks of the block. +- * Reading the summaries gives all the tags for the block in one read. Much +- * faster. +- * +- * Chunks holding summaries are marked with tags making it look like +- * they are part of a fake file. +- * +- * The summary could also be used during gc. +- * +- */ +- +-#include "yaffs_summary.h" +-#include "yaffs_packedtags2.h" +-#include "yaffs_nand.h" +-#include "yaffs_getblockinfo.h" +-#include "yaffs_bitmap.h" +- +-/* +- * The summary is built up in an array of summary tags. +- * This gets written to the last one or two (maybe more) chunks in a block. +- * A summary header is written as the first part of each chunk of summary data. +- * The summary header must match or the summary is rejected. +- */ +- +-/* Summary tags don't need the sequence number because that is redundant. */ +-struct yaffs_summary_tags { +- unsigned obj_id; +- unsigned chunk_id; +- unsigned n_bytes; +-}; +- +-/* Summary header */ +-struct yaffs_summary_header { +- unsigned version; /* Must match current version */ +- unsigned block; /* Must be this block */ +- unsigned seq; /* Must be this sequence number */ +- unsigned sum; /* Just add up all the bytes in the tags */ +-}; +- +- +-static void yaffs_summary_clear(struct yaffs_dev *dev) +-{ +- if (!dev->sum_tags) +- return; +- memset(dev->sum_tags, 0, dev->chunks_per_summary * +- sizeof(struct yaffs_summary_tags)); +-} +- +- +-void yaffs_summary_deinit(struct yaffs_dev *dev) +-{ +- kfree(dev->sum_tags); +- dev->sum_tags = NULL; +- kfree(dev->gc_sum_tags); +- dev->gc_sum_tags = NULL; +- dev->chunks_per_summary = 0; +-} +- +-int yaffs_summary_init(struct yaffs_dev *dev) +-{ +- int sum_bytes; +- int chunks_used; /* Number of chunks used by summary */ +- int sum_tags_bytes; +- +- sum_bytes = dev->param.chunks_per_block * +- sizeof(struct yaffs_summary_tags); +- +- chunks_used = (sum_bytes + dev->data_bytes_per_chunk - 1)/ +- (dev->data_bytes_per_chunk - +- sizeof(struct yaffs_summary_header)); +- +- dev->chunks_per_summary = dev->param.chunks_per_block - chunks_used; +- sum_tags_bytes = sizeof(struct yaffs_summary_tags) * +- dev->chunks_per_summary; +- dev->sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS); +- dev->gc_sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS); +- if (!dev->sum_tags || !dev->gc_sum_tags) { +- yaffs_summary_deinit(dev); +- return YAFFS_FAIL; +- } +- +- yaffs_summary_clear(dev); +- +- return YAFFS_OK; +-} +- +-static unsigned yaffs_summary_sum(struct yaffs_dev *dev) +-{ +- u8 *sum_buffer = (u8 *)dev->sum_tags; +- int i; +- unsigned sum = 0; +- +- i = sizeof(struct yaffs_summary_tags) * +- dev->chunks_per_summary; +- while (i > 0) { +- sum += *sum_buffer; +- sum_buffer++; +- i--; +- } +- +- return sum; +-} +- +-static int yaffs_summary_write(struct yaffs_dev *dev, int blk) +-{ +- struct yaffs_ext_tags tags; +- u8 *buffer; +- u8 *sum_buffer = (u8 *)dev->sum_tags; +- int n_bytes; +- int chunk_in_nand; +- int chunk_in_block; +- int result; +- int this_tx; +- struct yaffs_summary_header hdr; +- int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr); +- struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk); +- +- buffer = yaffs_get_temp_buffer(dev); +- n_bytes = sizeof(struct yaffs_summary_tags) * +- dev->chunks_per_summary; +- memset(&tags, 0, sizeof(struct yaffs_ext_tags)); +- tags.obj_id = YAFFS_OBJECTID_SUMMARY; +- tags.chunk_id = 1; +- chunk_in_block = dev->chunks_per_summary; +- chunk_in_nand = dev->alloc_block * dev->param.chunks_per_block + +- dev->chunks_per_summary; +- hdr.version = YAFFS_SUMMARY_VERSION; +- hdr.block = blk; +- hdr.seq = bi->seq_number; +- hdr.sum = yaffs_summary_sum(dev); +- +- do { +- this_tx = n_bytes; +- if (this_tx > sum_bytes_per_chunk) +- this_tx = sum_bytes_per_chunk; +- memcpy(buffer, &hdr, sizeof(hdr)); +- memcpy(buffer + sizeof(hdr), sum_buffer, this_tx); +- tags.n_bytes = this_tx + sizeof(hdr); +- result = yaffs_wr_chunk_tags_nand(dev, chunk_in_nand, +- buffer, &tags); +- +- if (result != YAFFS_OK) +- break; +- yaffs_set_chunk_bit(dev, blk, chunk_in_block); +- bi->pages_in_use++; +- dev->n_free_chunks--; +- +- n_bytes -= this_tx; +- sum_buffer += this_tx; +- chunk_in_nand++; +- chunk_in_block++; +- tags.chunk_id++; +- } while (result == YAFFS_OK && n_bytes > 0); +- yaffs_release_temp_buffer(dev, buffer); +- +- +- if (result == YAFFS_OK) +- bi->has_summary = 1; +- +- +- return result; +-} +- +-int yaffs_summary_read(struct yaffs_dev *dev, +- struct yaffs_summary_tags *st, +- int blk) +-{ +- struct yaffs_ext_tags tags; +- u8 *buffer; +- u8 *sum_buffer = (u8 *)st; +- int n_bytes; +- int chunk_id; +- int chunk_in_nand; +- int chunk_in_block; +- int result; +- int this_tx; +- struct yaffs_summary_header hdr; +- struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk); +- int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr); +- int sum_tags_bytes; +- +- sum_tags_bytes = sizeof(struct yaffs_summary_tags) * +- dev->chunks_per_summary; +- buffer = yaffs_get_temp_buffer(dev); +- n_bytes = sizeof(struct yaffs_summary_tags) * dev->chunks_per_summary; +- chunk_in_block = dev->chunks_per_summary; +- chunk_in_nand = blk * dev->param.chunks_per_block + +- dev->chunks_per_summary; +- chunk_id = 1; +- do { +- this_tx = n_bytes; +- if (this_tx > sum_bytes_per_chunk) +- this_tx = sum_bytes_per_chunk; +- result = yaffs_rd_chunk_tags_nand(dev, chunk_in_nand, +- buffer, &tags); +- +- if (tags.chunk_id != chunk_id || +- tags.obj_id != YAFFS_OBJECTID_SUMMARY || +- tags.chunk_used == 0 || +- tags.ecc_result > YAFFS_ECC_RESULT_FIXED || +- tags.n_bytes != (this_tx + sizeof(hdr))) +- result = YAFFS_FAIL; +- if (result != YAFFS_OK) +- break; +- +- if (st == dev->sum_tags) { +- /* If we're scanning then update the block info */ +- yaffs_set_chunk_bit(dev, blk, chunk_in_block); +- bi->pages_in_use++; +- } +- memcpy(&hdr, buffer, sizeof(hdr)); +- memcpy(sum_buffer, buffer + sizeof(hdr), this_tx); +- n_bytes -= this_tx; +- sum_buffer += this_tx; +- chunk_in_nand++; +- chunk_in_block++; +- chunk_id++; +- } while (result == YAFFS_OK && n_bytes > 0); +- yaffs_release_temp_buffer(dev, buffer); +- +- if (result == YAFFS_OK) { +- /* Verify header */ +- if (hdr.version != YAFFS_SUMMARY_VERSION || +- hdr.block != blk || +- hdr.seq != bi->seq_number || +- hdr.sum != yaffs_summary_sum(dev)) +- result = YAFFS_FAIL; +- } +- +- if (st == dev->sum_tags && result == YAFFS_OK) +- bi->has_summary = 1; +- +- return result; +-} +- +-int yaffs_summary_add(struct yaffs_dev *dev, +- struct yaffs_ext_tags *tags, +- int chunk_in_nand) +-{ +- struct yaffs_packed_tags2_tags_only tags_only; +- struct yaffs_summary_tags *sum_tags; +- int block_in_nand = chunk_in_nand / dev->param.chunks_per_block; +- int chunk_in_block = chunk_in_nand % dev->param.chunks_per_block; +- +- if (!dev->sum_tags) +- return YAFFS_OK; +- +- if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) { +- yaffs_pack_tags2_tags_only(&tags_only, tags); +- sum_tags = &dev->sum_tags[chunk_in_block]; +- sum_tags->chunk_id = tags_only.chunk_id; +- sum_tags->n_bytes = tags_only.n_bytes; +- sum_tags->obj_id = tags_only.obj_id; +- +- if (chunk_in_block == dev->chunks_per_summary - 1) { +- /* Time to write out the summary */ +- yaffs_summary_write(dev, block_in_nand); +- yaffs_summary_clear(dev); +- yaffs_skip_rest_of_block(dev); +- } +- } +- return YAFFS_OK; +-} +- +-int yaffs_summary_fetch(struct yaffs_dev *dev, +- struct yaffs_ext_tags *tags, +- int chunk_in_block) +-{ +- struct yaffs_packed_tags2_tags_only tags_only; +- struct yaffs_summary_tags *sum_tags; +- if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) { +- sum_tags = &dev->sum_tags[chunk_in_block]; +- tags_only.chunk_id = sum_tags->chunk_id; +- tags_only.n_bytes = sum_tags->n_bytes; +- tags_only.obj_id = sum_tags->obj_id; +- yaffs_unpack_tags2_tags_only(tags, &tags_only); +- return YAFFS_OK; +- } +- return YAFFS_FAIL; +-} +- +-void yaffs_summary_gc(struct yaffs_dev *dev, int blk) +-{ +- struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk); +- int i; +- +- if (!bi->has_summary) +- return; +- +- for (i = dev->chunks_per_summary; +- i < dev->param.chunks_per_block; +- i++) { +- if (yaffs_check_chunk_bit(dev, blk, i)) { +- yaffs_clear_chunk_bit(dev, blk, i); +- bi->pages_in_use--; +- dev->n_free_chunks++; +- } +- } +-} +diff --git a/fs/yaffs2/yaffs_summary.h b/fs/yaffs2/yaffs_summary.h +deleted file mode 100644 +index be141d0..0000000 +--- a/fs/yaffs2/yaffs_summary.h ++++ /dev/null +@@ -1,37 +0,0 @@ +-/* +- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU Lesser General Public License version 2.1 as +- * published by the Free Software Foundation. +- * +- * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +- */ +- +-#ifndef __YAFFS_SUMMARY_H__ +-#define __YAFFS_SUMMARY_H__ +- +-#include "yaffs_packedtags2.h" +- +- +-int yaffs_summary_init(struct yaffs_dev *dev); +-void yaffs_summary_deinit(struct yaffs_dev *dev); +- +-int yaffs_summary_add(struct yaffs_dev *dev, +- struct yaffs_ext_tags *tags, +- int chunk_in_block); +-int yaffs_summary_fetch(struct yaffs_dev *dev, +- struct yaffs_ext_tags *tags, +- int chunk_in_block); +-int yaffs_summary_read(struct yaffs_dev *dev, +- struct yaffs_summary_tags *st, +- int blk); +-void yaffs_summary_gc(struct yaffs_dev *dev, int blk); +- +- +-#endif +diff --git a/fs/yaffs2/yaffs_tagscompat.c b/fs/yaffs2/yaffs_tagscompat.c +deleted file mode 100644 +index 092430b..0000000 +--- a/fs/yaffs2/yaffs_tagscompat.c ++++ /dev/null +@@ -1,381 +0,0 @@ +-/* +- * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * 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 "yaffs_guts.h" +-#include "yaffs_tagscompat.h" +-#include "yaffs_ecc.h" +-#include "yaffs_getblockinfo.h" +-#include "yaffs_trace.h" +- +-static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk); +- +- +-/********** Tags ECC calculations *********/ +- +- +-void yaffs_calc_tags_ecc(struct yaffs_tags *tags) +-{ +- /* Calculate an ecc */ +- unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes; +- unsigned i, j; +- unsigned ecc = 0; +- unsigned bit = 0; +- +- tags->ecc = 0; +- +- for (i = 0; i < 8; i++) { +- for (j = 1; j & 0xff; j <<= 1) { +- bit++; +- if (b[i] & j) +- ecc ^= bit; +- } +- } +- tags->ecc = ecc; +-} +- +-int yaffs_check_tags_ecc(struct yaffs_tags *tags) +-{ +- unsigned ecc = tags->ecc; +- +- yaffs_calc_tags_ecc(tags); +- +- ecc ^= tags->ecc; +- +- if (ecc && ecc <= 64) { +- /* TODO: Handle the failure better. Retire? */ +- unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes; +- +- ecc--; +- +- b[ecc / 8] ^= (1 << (ecc & 7)); +- +- /* Now recvalc the ecc */ +- yaffs_calc_tags_ecc(tags); +- +- return 1; /* recovered error */ +- } else if (ecc) { +- /* Wierd ecc failure value */ +- /* TODO Need to do somethiong here */ +- return -1; /* unrecovered error */ +- } +- return 0; +-} +- +-/********** Tags **********/ +- +-static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr, +- struct yaffs_tags *tags_ptr) +-{ +- union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr; +- +- yaffs_calc_tags_ecc(tags_ptr); +- +- spare_ptr->tb0 = tu->as_bytes[0]; +- spare_ptr->tb1 = tu->as_bytes[1]; +- spare_ptr->tb2 = tu->as_bytes[2]; +- spare_ptr->tb3 = tu->as_bytes[3]; +- spare_ptr->tb4 = tu->as_bytes[4]; +- spare_ptr->tb5 = tu->as_bytes[5]; +- spare_ptr->tb6 = tu->as_bytes[6]; +- spare_ptr->tb7 = tu->as_bytes[7]; +-} +- +-static void yaffs_get_tags_from_spare(struct yaffs_dev *dev, +- struct yaffs_spare *spare_ptr, +- struct yaffs_tags *tags_ptr) +-{ +- union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr; +- int result; +- +- tu->as_bytes[0] = spare_ptr->tb0; +- tu->as_bytes[1] = spare_ptr->tb1; +- tu->as_bytes[2] = spare_ptr->tb2; +- tu->as_bytes[3] = spare_ptr->tb3; +- tu->as_bytes[4] = spare_ptr->tb4; +- tu->as_bytes[5] = spare_ptr->tb5; +- tu->as_bytes[6] = spare_ptr->tb6; +- tu->as_bytes[7] = spare_ptr->tb7; +- +- result = yaffs_check_tags_ecc(tags_ptr); +- if (result > 0) +- dev->n_tags_ecc_fixed++; +- else if (result < 0) +- dev->n_tags_ecc_unfixed++; +-} +- +-static void yaffs_spare_init(struct yaffs_spare *spare) +-{ +- memset(spare, 0xff, sizeof(struct yaffs_spare)); +-} +- +-static int yaffs_wr_nand(struct yaffs_dev *dev, +- int nand_chunk, const u8 *data, +- struct yaffs_spare *spare) +-{ +- int data_size = dev->data_bytes_per_chunk; +- +- return dev->drv.drv_write_chunk_fn(dev, nand_chunk, +- data, data_size, +- (u8 *) spare, sizeof(*spare)); +-} +- +-static int yaffs_rd_chunk_nand(struct yaffs_dev *dev, +- int nand_chunk, +- u8 *data, +- struct yaffs_spare *spare, +- enum yaffs_ecc_result *ecc_result, +- int correct_errors) +-{ +- int ret_val; +- struct yaffs_spare local_spare; +- int data_size; +- int spare_size; +- int ecc_result1, ecc_result2; +- u8 calc_ecc[3]; +- +- if (!spare) { +- /* If we don't have a real spare, then we use a local one. */ +- /* Need this for the calculation of the ecc */ +- spare = &local_spare; +- } +- data_size = dev->data_bytes_per_chunk; +- spare_size = sizeof(struct yaffs_spare); +- +- if (dev->param.use_nand_ecc) +- return dev->drv.drv_read_chunk_fn(dev, nand_chunk, +- data, data_size, +- (u8 *) spare, spare_size, +- ecc_result); +- +- +- /* Handle the ECC at this level. */ +- +- ret_val = dev->drv.drv_read_chunk_fn(dev, nand_chunk, +- data, data_size, +- (u8 *)spare, spare_size, +- NULL); +- if (!data || !correct_errors) +- return ret_val; +- +- /* Do ECC correction if needed. */ +- yaffs_ecc_calc(data, calc_ecc); +- ecc_result1 = yaffs_ecc_correct(data, spare->ecc1, calc_ecc); +- yaffs_ecc_calc(&data[256], calc_ecc); +- ecc_result2 = yaffs_ecc_correct(&data[256], spare->ecc2, calc_ecc); +- +- if (ecc_result1 > 0) { +- yaffs_trace(YAFFS_TRACE_ERROR, +- "**>>yaffs ecc error fix performed on chunk %d:0", +- nand_chunk); +- dev->n_ecc_fixed++; +- } else if (ecc_result1 < 0) { +- yaffs_trace(YAFFS_TRACE_ERROR, +- "**>>yaffs ecc error unfixed on chunk %d:0", +- nand_chunk); +- dev->n_ecc_unfixed++; +- } +- +- if (ecc_result2 > 0) { +- yaffs_trace(YAFFS_TRACE_ERROR, +- "**>>yaffs ecc error fix performed on chunk %d:1", +- nand_chunk); +- dev->n_ecc_fixed++; +- } else if (ecc_result2 < 0) { +- yaffs_trace(YAFFS_TRACE_ERROR, +- "**>>yaffs ecc error unfixed on chunk %d:1", +- nand_chunk); +- dev->n_ecc_unfixed++; +- } +- +- if (ecc_result1 || ecc_result2) { +- /* We had a data problem on this page */ +- yaffs_handle_rd_data_error(dev, nand_chunk); +- } +- +- if (ecc_result1 < 0 || ecc_result2 < 0) +- *ecc_result = YAFFS_ECC_RESULT_UNFIXED; +- else if (ecc_result1 > 0 || ecc_result2 > 0) +- *ecc_result = YAFFS_ECC_RESULT_FIXED; +- else +- *ecc_result = YAFFS_ECC_RESULT_NO_ERROR; +- +- return ret_val; +-} +- +-/* +- * Functions for robustisizing +- */ +- +-static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk) +-{ +- int flash_block = nand_chunk / dev->param.chunks_per_block; +- +- /* Mark the block for retirement */ +- yaffs_get_block_info(dev, flash_block + dev->block_offset)-> +- needs_retiring = 1; +- yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, +- "**>>Block %d marked for retirement", +- flash_block); +- +- /* TODO: +- * Just do a garbage collection on the affected block +- * then retire the block +- * NB recursion +- */ +-} +- +-static int yaffs_tags_compat_wr(struct yaffs_dev *dev, +- int nand_chunk, +- const u8 *data, const struct yaffs_ext_tags *ext_tags) +-{ +- struct yaffs_spare spare; +- struct yaffs_tags tags; +- +- yaffs_spare_init(&spare); +- +- if (ext_tags->is_deleted) +- spare.page_status = 0; +- else { +- tags.obj_id = ext_tags->obj_id; +- tags.chunk_id = ext_tags->chunk_id; +- +- tags.n_bytes_lsb = ext_tags->n_bytes & (1024 - 1); +- +- if (dev->data_bytes_per_chunk >= 1024) +- tags.n_bytes_msb = (ext_tags->n_bytes >> 10) & 3; +- else +- tags.n_bytes_msb = 3; +- +- tags.serial_number = ext_tags->serial_number; +- +- if (!dev->param.use_nand_ecc && data) { +- yaffs_ecc_calc(data, spare.ecc1); +- yaffs_ecc_calc(&data[256], spare.ecc2); +- } +- +- yaffs_load_tags_to_spare(&spare, &tags); +- } +- return yaffs_wr_nand(dev, nand_chunk, data, &spare); +-} +- +-static int yaffs_tags_compat_rd(struct yaffs_dev *dev, +- int nand_chunk, +- u8 *data, struct yaffs_ext_tags *ext_tags) +-{ +- struct yaffs_spare spare; +- struct yaffs_tags tags; +- enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN; +- static struct yaffs_spare spare_ff; +- static int init; +- int deleted; +- +- if (!init) { +- memset(&spare_ff, 0xff, sizeof(spare_ff)); +- init = 1; +- } +- +- if (!yaffs_rd_chunk_nand(dev, nand_chunk, +- data, &spare, &ecc_result, 1)) +- return YAFFS_FAIL; +- +- /* ext_tags may be NULL */ +- if (!ext_tags) +- return YAFFS_OK; +- +- deleted = (hweight8(spare.page_status) < 7) ? 1 : 0; +- +- ext_tags->is_deleted = deleted; +- ext_tags->ecc_result = ecc_result; +- ext_tags->block_bad = 0; /* We're reading it */ +- /* therefore it is not a bad block */ +- ext_tags->chunk_used = +- memcmp(&spare_ff, &spare, sizeof(spare_ff)) ? 1 : 0; +- +- if (ext_tags->chunk_used) { +- yaffs_get_tags_from_spare(dev, &spare, &tags); +- ext_tags->obj_id = tags.obj_id; +- ext_tags->chunk_id = tags.chunk_id; +- ext_tags->n_bytes = tags.n_bytes_lsb; +- +- if (dev->data_bytes_per_chunk >= 1024) +- ext_tags->n_bytes |= +- (((unsigned)tags.n_bytes_msb) << 10); +- +- ext_tags->serial_number = tags.serial_number; +- } +- +- return YAFFS_OK; +-} +- +-static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block) +-{ +- struct yaffs_spare spare; +- +- memset(&spare, 0xff, sizeof(struct yaffs_spare)); +- +- spare.block_status = 'Y'; +- +- yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block, NULL, +- &spare); +- yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block + 1, +- NULL, &spare); +- +- return YAFFS_OK; +-} +- +-static int yaffs_tags_compat_query_block(struct yaffs_dev *dev, +- int block_no, +- enum yaffs_block_state *state, +- u32 *seq_number) +-{ +- struct yaffs_spare spare0, spare1; +- static struct yaffs_spare spare_ff; +- static int init; +- enum yaffs_ecc_result dummy; +- +- if (!init) { +- memset(&spare_ff, 0xff, sizeof(spare_ff)); +- init = 1; +- } +- +- *seq_number = 0; +- +- /* Look for bad block markers in the first two chunks */ +- yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block, +- NULL, &spare0, &dummy, 0); +- yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1, +- NULL, &spare1, &dummy, 0); +- +- if (hweight8(spare0.block_status & spare1.block_status) < 7) +- *state = YAFFS_BLOCK_STATE_DEAD; +- else if (memcmp(&spare_ff, &spare0, sizeof(spare_ff)) == 0) +- *state = YAFFS_BLOCK_STATE_EMPTY; +- else +- *state = YAFFS_BLOCK_STATE_NEEDS_SCAN; +- +- return YAFFS_OK; +-} +- +-void yaffs_tags_compat_install(struct yaffs_dev *dev) +-{ +- if(dev->param.is_yaffs2) +- return; +- if(!dev->tagger.write_chunk_tags_fn) +- dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_wr; +- if(!dev->tagger.read_chunk_tags_fn) +- dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_rd; +- if(!dev->tagger.query_block_fn) +- dev->tagger.query_block_fn = yaffs_tags_compat_query_block; +- if(!dev->tagger.mark_bad_fn) +- dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad; +-} +diff --git a/fs/yaffs2/yaffs_tagscompat.h b/fs/yaffs2/yaffs_tagscompat.h +deleted file mode 100644 +index 92d298a..0000000 +--- a/fs/yaffs2/yaffs_tagscompat.h ++++ /dev/null +@@ -1,44 +0,0 @@ +-/* +- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU Lesser General Public License version 2.1 as +- * published by the Free Software Foundation. +- * +- * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +- */ +- +-#ifndef __YAFFS_TAGSCOMPAT_H__ +-#define __YAFFS_TAGSCOMPAT_H__ +- +- +-#include "yaffs_guts.h" +- +-#if 0 +- +- +-int yaffs_tags_compat_wr(struct yaffs_dev *dev, +- int nand_chunk, +- const u8 *data, const struct yaffs_ext_tags *tags); +-int yaffs_tags_compat_rd(struct yaffs_dev *dev, +- int nand_chunk, +- u8 *data, struct yaffs_ext_tags *tags); +-int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no); +-int yaffs_tags_compat_query_block(struct yaffs_dev *dev, +- int block_no, +- enum yaffs_block_state *state, +- u32 *seq_number); +- +-#endif +- +- +-void yaffs_tags_compat_install(struct yaffs_dev *dev); +-void yaffs_calc_tags_ecc(struct yaffs_tags *tags); +-int yaffs_check_tags_ecc(struct yaffs_tags *tags); +- +-#endif +diff --git a/fs/yaffs2/yaffs_tagsmarshall.c b/fs/yaffs2/yaffs_tagsmarshall.c +deleted file mode 100644 +index 44a83b1..0000000 +--- a/fs/yaffs2/yaffs_tagsmarshall.c ++++ /dev/null +@@ -1,199 +0,0 @@ +-/* +- * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * 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 "yaffs_guts.h" +-#include "yaffs_trace.h" +-#include "yaffs_packedtags2.h" +- +-static int yaffs_tags_marshall_write(struct yaffs_dev *dev, +- int nand_chunk, const u8 *data, +- const struct yaffs_ext_tags *tags) +-{ +- struct yaffs_packed_tags2 pt; +- int retval; +- +- int packed_tags_size = +- dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt); +- void *packed_tags_ptr = +- dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt; +- +- yaffs_trace(YAFFS_TRACE_MTD, +- "yaffs_tags_marshall_write chunk %d data %p tags %p", +- nand_chunk, data, tags); +- +- /* For yaffs2 writing there must be both data and tags. +- * If we're using inband tags, then the tags are stuffed into +- * the end of the data buffer. +- */ +- if (!data || !tags) +- BUG(); +- else if (dev->param.inband_tags) { +- struct yaffs_packed_tags2_tags_only *pt2tp; +- pt2tp = +- (struct yaffs_packed_tags2_tags_only *)(data + +- dev-> +- data_bytes_per_chunk); +- yaffs_pack_tags2_tags_only(pt2tp, tags); +- } else { +- yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc); +- } +- +- retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk, +- data, dev->param.total_bytes_per_chunk, +- (dev->param.inband_tags) ? NULL : packed_tags_ptr, +- (dev->param.inband_tags) ? 0 : packed_tags_size); +- +- return retval; +-} +- +-static int yaffs_tags_marshall_read(struct yaffs_dev *dev, +- int nand_chunk, u8 *data, +- struct yaffs_ext_tags *tags) +-{ +- int retval = 0; +- int local_data = 0; +- u8 spare_buffer[100]; +- enum yaffs_ecc_result ecc_result; +- +- struct yaffs_packed_tags2 pt; +- +- int packed_tags_size = +- dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt); +- void *packed_tags_ptr = +- dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt; +- +- yaffs_trace(YAFFS_TRACE_MTD, +- "yaffs_tags_marshall_read chunk %d data %p tags %p", +- nand_chunk, data, tags); +- +- if (dev->param.inband_tags) { +- if (!data) { +- local_data = 1; +- data = yaffs_get_temp_buffer(dev); +- } +- } +- +- if (dev->param.inband_tags || (data && !tags)) +- retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk, +- data, dev->param.total_bytes_per_chunk, +- NULL, 0, +- &ecc_result); +- else if (tags) +- retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk, +- data, dev->param.total_bytes_per_chunk, +- spare_buffer, packed_tags_size, +- &ecc_result); +- else +- BUG(); +- +- +- if (dev->param.inband_tags) { +- if (tags) { +- struct yaffs_packed_tags2_tags_only *pt2tp; +- pt2tp = +- (struct yaffs_packed_tags2_tags_only *) +- &data[dev->data_bytes_per_chunk]; +- yaffs_unpack_tags2_tags_only(tags, pt2tp); +- } +- } else if (tags) { +- memcpy(packed_tags_ptr, spare_buffer, packed_tags_size); +- yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc); +- } +- +- if (local_data) +- yaffs_release_temp_buffer(dev, data); +- +- if (tags && ecc_result == YAFFS_ECC_RESULT_UNFIXED) { +- tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED; +- dev->n_ecc_unfixed++; +- } +- +- if (tags && ecc_result == -YAFFS_ECC_RESULT_FIXED) { +- if (tags->ecc_result <= YAFFS_ECC_RESULT_NO_ERROR) +- tags->ecc_result = YAFFS_ECC_RESULT_FIXED; +- dev->n_ecc_fixed++; +- } +- +- if (ecc_result < YAFFS_ECC_RESULT_UNFIXED) +- return YAFFS_OK; +- else +- return YAFFS_FAIL; +-} +- +-static int yaffs_tags_marshall_query_block(struct yaffs_dev *dev, int block_no, +- enum yaffs_block_state *state, +- u32 *seq_number) +-{ +- int retval; +- +- yaffs_trace(YAFFS_TRACE_MTD, "yaffs_tags_marshall_query_block %d", +- block_no); +- +- retval = dev->drv.drv_check_bad_fn(dev, block_no); +- +- if (retval== YAFFS_FAIL) { +- yaffs_trace(YAFFS_TRACE_MTD, "block is bad"); +- +- *state = YAFFS_BLOCK_STATE_DEAD; +- *seq_number = 0; +- } else { +- struct yaffs_ext_tags t; +- +- yaffs_tags_marshall_read(dev, +- block_no * dev->param.chunks_per_block, +- NULL, &t); +- +- if (t.chunk_used) { +- *seq_number = t.seq_number; +- *state = YAFFS_BLOCK_STATE_NEEDS_SCAN; +- } else { +- *seq_number = 0; +- *state = YAFFS_BLOCK_STATE_EMPTY; +- } +- } +- +- yaffs_trace(YAFFS_TRACE_MTD, +- "block query returns seq %d state %d", +- *seq_number, *state); +- +- if (retval == 0) +- return YAFFS_OK; +- else +- return YAFFS_FAIL; +-} +- +-static int yaffs_tags_marshall_mark_bad(struct yaffs_dev *dev, int block_no) +-{ +- return dev->drv.drv_mark_bad_fn(dev, block_no); +- +-} +- +- +-void yaffs_tags_marshall_install(struct yaffs_dev *dev) +-{ +- if (!dev->param.is_yaffs2) +- return; +- +- if (!dev->tagger.write_chunk_tags_fn) +- dev->tagger.write_chunk_tags_fn = yaffs_tags_marshall_write; +- +- if (!dev->tagger.read_chunk_tags_fn) +- dev->tagger.read_chunk_tags_fn = yaffs_tags_marshall_read; +- +- if (!dev->tagger.query_block_fn) +- dev->tagger.query_block_fn = yaffs_tags_marshall_query_block; +- +- if (!dev->tagger.mark_bad_fn) +- dev->tagger.mark_bad_fn = yaffs_tags_marshall_mark_bad; +- +-} +diff --git a/fs/yaffs2/yaffs_tagsmarshall.h b/fs/yaffs2/yaffs_tagsmarshall.h +deleted file mode 100644 +index bf3e68a..0000000 +--- a/fs/yaffs2/yaffs_tagsmarshall.h ++++ /dev/null +@@ -1,22 +0,0 @@ +-/* +- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU Lesser General Public License version 2.1 as +- * published by the Free Software Foundation. +- * +- * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +- */ +- +-#ifndef __YAFFS_TAGSMARSHALL_H__ +-#define __YAFFS_TAGSMARSHALL_H__ +- +-#include "yaffs_guts.h" +-void yaffs_tags_marshall_install(struct yaffs_dev *dev); +- +-#endif +diff --git a/fs/yaffs2/yaffs_trace.h b/fs/yaffs2/yaffs_trace.h +deleted file mode 100644 +index fd26054..0000000 +--- a/fs/yaffs2/yaffs_trace.h ++++ /dev/null +@@ -1,57 +0,0 @@ +-/* +- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU Lesser General Public License version 2.1 as +- * published by the Free Software Foundation. +- * +- * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +- */ +- +-#ifndef __YTRACE_H__ +-#define __YTRACE_H__ +- +-extern unsigned int yaffs_trace_mask; +-extern unsigned int yaffs_wr_attempts; +- +-/* +- * Tracing flags. +- * The flags masked in YAFFS_TRACE_ALWAYS are always traced. +- */ +- +-#define YAFFS_TRACE_OS 0x00000002 +-#define YAFFS_TRACE_ALLOCATE 0x00000004 +-#define YAFFS_TRACE_SCAN 0x00000008 +-#define YAFFS_TRACE_BAD_BLOCKS 0x00000010 +-#define YAFFS_TRACE_ERASE 0x00000020 +-#define YAFFS_TRACE_GC 0x00000040 +-#define YAFFS_TRACE_WRITE 0x00000080 +-#define YAFFS_TRACE_TRACING 0x00000100 +-#define YAFFS_TRACE_DELETION 0x00000200 +-#define YAFFS_TRACE_BUFFERS 0x00000400 +-#define YAFFS_TRACE_NANDACCESS 0x00000800 +-#define YAFFS_TRACE_GC_DETAIL 0x00001000 +-#define YAFFS_TRACE_SCAN_DEBUG 0x00002000 +-#define YAFFS_TRACE_MTD 0x00004000 +-#define YAFFS_TRACE_CHECKPOINT 0x00008000 +- +-#define YAFFS_TRACE_VERIFY 0x00010000 +-#define YAFFS_TRACE_VERIFY_NAND 0x00020000 +-#define YAFFS_TRACE_VERIFY_FULL 0x00040000 +-#define YAFFS_TRACE_VERIFY_ALL 0x000f0000 +- +-#define YAFFS_TRACE_SYNC 0x00100000 +-#define YAFFS_TRACE_BACKGROUND 0x00200000 +-#define YAFFS_TRACE_LOCK 0x00400000 +-#define YAFFS_TRACE_MOUNT 0x00800000 +- +-#define YAFFS_TRACE_ERROR 0x40000000 +-#define YAFFS_TRACE_BUG 0x80000000 +-#define YAFFS_TRACE_ALWAYS 0xf0000000 +- +-#endif +diff --git a/fs/yaffs2/yaffs_verify.c b/fs/yaffs2/yaffs_verify.c +deleted file mode 100644 +index e8f2f0a..0000000 +--- a/fs/yaffs2/yaffs_verify.c ++++ /dev/null +@@ -1,529 +0,0 @@ +-/* +- * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * 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 "yaffs_verify.h" +-#include "yaffs_trace.h" +-#include "yaffs_bitmap.h" +-#include "yaffs_getblockinfo.h" +-#include "yaffs_nand.h" +- +-int yaffs_skip_verification(struct yaffs_dev *dev) +-{ +- (void) dev; +- return !(yaffs_trace_mask & +- (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL)); +-} +- +-static int yaffs_skip_full_verification(struct yaffs_dev *dev) +-{ +- (void) dev; +- return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_FULL)); +-} +- +-static int yaffs_skip_nand_verification(struct yaffs_dev *dev) +-{ +- (void) dev; +- return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_NAND)); +-} +- +-static const char * const block_state_name[] = { +- "Unknown", +- "Needs scan", +- "Scanning", +- "Empty", +- "Allocating", +- "Full", +- "Dirty", +- "Checkpoint", +- "Collecting", +- "Dead" +-}; +- +-void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi, int n) +-{ +- int actually_used; +- int in_use; +- +- if (yaffs_skip_verification(dev)) +- return; +- +- /* Report illegal runtime states */ +- if (bi->block_state >= YAFFS_NUMBER_OF_BLOCK_STATES) +- yaffs_trace(YAFFS_TRACE_VERIFY, +- "Block %d has undefined state %d", +- n, bi->block_state); +- +- switch (bi->block_state) { +- case YAFFS_BLOCK_STATE_UNKNOWN: +- case YAFFS_BLOCK_STATE_SCANNING: +- case YAFFS_BLOCK_STATE_NEEDS_SCAN: +- yaffs_trace(YAFFS_TRACE_VERIFY, +- "Block %d has bad run-state %s", +- n, block_state_name[bi->block_state]); +- } +- +- /* Check pages in use and soft deletions are legal */ +- +- actually_used = bi->pages_in_use - bi->soft_del_pages; +- +- if (bi->pages_in_use < 0 || +- bi->pages_in_use > dev->param.chunks_per_block || +- bi->soft_del_pages < 0 || +- bi->soft_del_pages > dev->param.chunks_per_block || +- actually_used < 0 || actually_used > dev->param.chunks_per_block) +- yaffs_trace(YAFFS_TRACE_VERIFY, +- "Block %d has illegal values pages_in_used %d soft_del_pages %d", +- n, bi->pages_in_use, bi->soft_del_pages); +- +- /* Check chunk bitmap legal */ +- in_use = yaffs_count_chunk_bits(dev, n); +- if (in_use != bi->pages_in_use) +- yaffs_trace(YAFFS_TRACE_VERIFY, +- "Block %d has inconsistent values pages_in_use %d counted chunk bits %d", +- n, bi->pages_in_use, in_use); +-} +- +-void yaffs_verify_collected_blk(struct yaffs_dev *dev, +- struct yaffs_block_info *bi, int n) +-{ +- yaffs_verify_blk(dev, bi, n); +- +- /* After collection the block should be in the erased state */ +- +- if (bi->block_state != YAFFS_BLOCK_STATE_COLLECTING && +- bi->block_state != YAFFS_BLOCK_STATE_EMPTY) { +- yaffs_trace(YAFFS_TRACE_ERROR, +- "Block %d is in state %d after gc, should be erased", +- n, bi->block_state); +- } +-} +- +-void yaffs_verify_blocks(struct yaffs_dev *dev) +-{ +- int i; +- int state_count[YAFFS_NUMBER_OF_BLOCK_STATES]; +- int illegal_states = 0; +- +- if (yaffs_skip_verification(dev)) +- return; +- +- memset(state_count, 0, sizeof(state_count)); +- +- for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { +- struct yaffs_block_info *bi = yaffs_get_block_info(dev, i); +- yaffs_verify_blk(dev, bi, i); +- +- if (bi->block_state < YAFFS_NUMBER_OF_BLOCK_STATES) +- state_count[bi->block_state]++; +- else +- illegal_states++; +- } +- +- yaffs_trace(YAFFS_TRACE_VERIFY, "Block summary"); +- +- yaffs_trace(YAFFS_TRACE_VERIFY, +- "%d blocks have illegal states", +- illegal_states); +- if (state_count[YAFFS_BLOCK_STATE_ALLOCATING] > 1) +- yaffs_trace(YAFFS_TRACE_VERIFY, +- "Too many allocating blocks"); +- +- for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++) +- yaffs_trace(YAFFS_TRACE_VERIFY, +- "%s %d blocks", +- block_state_name[i], state_count[i]); +- +- if (dev->blocks_in_checkpt != state_count[YAFFS_BLOCK_STATE_CHECKPOINT]) +- yaffs_trace(YAFFS_TRACE_VERIFY, +- "Checkpoint block count wrong dev %d count %d", +- dev->blocks_in_checkpt, +- state_count[YAFFS_BLOCK_STATE_CHECKPOINT]); +- +- if (dev->n_erased_blocks != state_count[YAFFS_BLOCK_STATE_EMPTY]) +- yaffs_trace(YAFFS_TRACE_VERIFY, +- "Erased block count wrong dev %d count %d", +- dev->n_erased_blocks, +- state_count[YAFFS_BLOCK_STATE_EMPTY]); +- +- if (state_count[YAFFS_BLOCK_STATE_COLLECTING] > 1) +- yaffs_trace(YAFFS_TRACE_VERIFY, +- "Too many collecting blocks %d (max is 1)", +- state_count[YAFFS_BLOCK_STATE_COLLECTING]); +-} +- +-/* +- * Verify the object header. oh must be valid, but obj and tags may be NULL in +- * which case those tests will not be performed. +- */ +-void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh, +- struct yaffs_ext_tags *tags, int parent_check) +-{ +- if (obj && yaffs_skip_verification(obj->my_dev)) +- return; +- +- if (!(tags && obj && oh)) { +- yaffs_trace(YAFFS_TRACE_VERIFY, +- "Verifying object header tags %p obj %p oh %p", +- tags, obj, oh); +- return; +- } +- +- if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN || +- oh->type > YAFFS_OBJECT_TYPE_MAX) +- yaffs_trace(YAFFS_TRACE_VERIFY, +- "Obj %d header type is illegal value 0x%x", +- tags->obj_id, oh->type); +- +- if (tags->obj_id != obj->obj_id) +- yaffs_trace(YAFFS_TRACE_VERIFY, +- "Obj %d header mismatch obj_id %d", +- tags->obj_id, obj->obj_id); +- +- /* +- * Check that the object's parent ids match if parent_check requested. +- * +- * Tests do not apply to the root object. +- */ +- +- if (parent_check && tags->obj_id > 1 && !obj->parent) +- yaffs_trace(YAFFS_TRACE_VERIFY, +- "Obj %d header mismatch parent_id %d obj->parent is NULL", +- tags->obj_id, oh->parent_obj_id); +- +- if (parent_check && obj->parent && +- oh->parent_obj_id != obj->parent->obj_id && +- (oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED || +- obj->parent->obj_id != YAFFS_OBJECTID_DELETED)) +- yaffs_trace(YAFFS_TRACE_VERIFY, +- "Obj %d header mismatch parent_id %d parent_obj_id %d", +- tags->obj_id, oh->parent_obj_id, +- obj->parent->obj_id); +- +- if (tags->obj_id > 1 && oh->name[0] == 0) /* Null name */ +- yaffs_trace(YAFFS_TRACE_VERIFY, +- "Obj %d header name is NULL", +- obj->obj_id); +- +- if (tags->obj_id > 1 && ((u8) (oh->name[0])) == 0xff) /* Junk name */ +- yaffs_trace(YAFFS_TRACE_VERIFY, +- "Obj %d header name is 0xff", +- obj->obj_id); +-} +- +-void yaffs_verify_file(struct yaffs_obj *obj) +-{ +- u32 x; +- int required_depth; +- int actual_depth; +- int last_chunk; +- u32 offset_in_chunk; +- u32 the_chunk; +- +- u32 i; +- struct yaffs_dev *dev; +- struct yaffs_ext_tags tags; +- struct yaffs_tnode *tn; +- u32 obj_id; +- +- if (!obj) +- return; +- +- if (yaffs_skip_verification(obj->my_dev)) +- return; +- +- dev = obj->my_dev; +- obj_id = obj->obj_id; +- +- +- /* Check file size is consistent with tnode depth */ +- yaffs_addr_to_chunk(dev, obj->variant.file_variant.file_size, +- &last_chunk, &offset_in_chunk); +- last_chunk++; +- x = last_chunk >> YAFFS_TNODES_LEVEL0_BITS; +- required_depth = 0; +- while (x > 0) { +- x >>= YAFFS_TNODES_INTERNAL_BITS; +- required_depth++; +- } +- +- actual_depth = obj->variant.file_variant.top_level; +- +- /* Check that the chunks in the tnode tree are all correct. +- * We do this by scanning through the tnode tree and +- * checking the tags for every chunk match. +- */ +- +- if (yaffs_skip_nand_verification(dev)) +- return; +- +- for (i = 1; i <= last_chunk; i++) { +- tn = yaffs_find_tnode_0(dev, &obj->variant.file_variant, i); +- +- if (!tn) +- continue; +- +- the_chunk = yaffs_get_group_base(dev, tn, i); +- if (the_chunk > 0) { +- yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL, +- &tags); +- if (tags.obj_id != obj_id || tags.chunk_id != i) +- yaffs_trace(YAFFS_TRACE_VERIFY, +- "Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)", +- obj_id, i, the_chunk, +- tags.obj_id, tags.chunk_id); +- } +- } +-} +- +-void yaffs_verify_link(struct yaffs_obj *obj) +-{ +- if (obj && yaffs_skip_verification(obj->my_dev)) +- return; +- +- /* Verify sane equivalent object */ +-} +- +-void yaffs_verify_symlink(struct yaffs_obj *obj) +-{ +- if (obj && yaffs_skip_verification(obj->my_dev)) +- return; +- +- /* Verify symlink string */ +-} +- +-void yaffs_verify_special(struct yaffs_obj *obj) +-{ +- if (obj && yaffs_skip_verification(obj->my_dev)) +- return; +-} +- +-void yaffs_verify_obj(struct yaffs_obj *obj) +-{ +- struct yaffs_dev *dev; +- u32 chunk_min; +- u32 chunk_max; +- u32 chunk_id_ok; +- u32 chunk_in_range; +- u32 chunk_wrongly_deleted; +- u32 chunk_valid; +- +- if (!obj) +- return; +- +- if (obj->being_created) +- return; +- +- dev = obj->my_dev; +- +- if (yaffs_skip_verification(dev)) +- return; +- +- /* Check sane object header chunk */ +- +- chunk_min = dev->internal_start_block * dev->param.chunks_per_block; +- chunk_max = +- (dev->internal_end_block + 1) * dev->param.chunks_per_block - 1; +- +- chunk_in_range = (((unsigned)(obj->hdr_chunk)) >= chunk_min && +- ((unsigned)(obj->hdr_chunk)) <= chunk_max); +- chunk_id_ok = chunk_in_range || (obj->hdr_chunk == 0); +- chunk_valid = chunk_in_range && +- yaffs_check_chunk_bit(dev, +- obj->hdr_chunk / dev->param.chunks_per_block, +- obj->hdr_chunk % dev->param.chunks_per_block); +- chunk_wrongly_deleted = chunk_in_range && !chunk_valid; +- +- if (!obj->fake && (!chunk_id_ok || chunk_wrongly_deleted)) +- yaffs_trace(YAFFS_TRACE_VERIFY, +- "Obj %d has chunk_id %d %s %s", +- obj->obj_id, obj->hdr_chunk, +- chunk_id_ok ? "" : ",out of range", +- chunk_wrongly_deleted ? ",marked as deleted" : ""); +- +- if (chunk_valid && !yaffs_skip_nand_verification(dev)) { +- struct yaffs_ext_tags tags; +- struct yaffs_obj_hdr *oh; +- u8 *buffer = yaffs_get_temp_buffer(dev); +- +- oh = (struct yaffs_obj_hdr *)buffer; +- +- yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, buffer, &tags); +- +- yaffs_verify_oh(obj, oh, &tags, 1); +- +- yaffs_release_temp_buffer(dev, buffer); +- } +- +- /* Verify it has a parent */ +- if (obj && !obj->fake && (!obj->parent || obj->parent->my_dev != dev)) { +- yaffs_trace(YAFFS_TRACE_VERIFY, +- "Obj %d has parent pointer %p which does not look like an object", +- obj->obj_id, obj->parent); +- } +- +- /* Verify parent is a directory */ +- if (obj->parent && +- obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { +- yaffs_trace(YAFFS_TRACE_VERIFY, +- "Obj %d's parent is not a directory (type %d)", +- obj->obj_id, obj->parent->variant_type); +- } +- +- switch (obj->variant_type) { +- case YAFFS_OBJECT_TYPE_FILE: +- yaffs_verify_file(obj); +- break; +- case YAFFS_OBJECT_TYPE_SYMLINK: +- yaffs_verify_symlink(obj); +- break; +- case YAFFS_OBJECT_TYPE_DIRECTORY: +- yaffs_verify_dir(obj); +- break; +- case YAFFS_OBJECT_TYPE_HARDLINK: +- yaffs_verify_link(obj); +- break; +- case YAFFS_OBJECT_TYPE_SPECIAL: +- yaffs_verify_special(obj); +- break; +- case YAFFS_OBJECT_TYPE_UNKNOWN: +- default: +- yaffs_trace(YAFFS_TRACE_VERIFY, +- "Obj %d has illegaltype %d", +- obj->obj_id, obj->variant_type); +- break; +- } +-} +- +-void yaffs_verify_objects(struct yaffs_dev *dev) +-{ +- struct yaffs_obj *obj; +- int i; +- struct list_head *lh; +- +- if (yaffs_skip_verification(dev)) +- return; +- +- /* Iterate through the objects in each hash entry */ +- +- for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { +- list_for_each(lh, &dev->obj_bucket[i].list) { +- obj = list_entry(lh, struct yaffs_obj, hash_link); +- yaffs_verify_obj(obj); +- } +- } +-} +- +-void yaffs_verify_obj_in_dir(struct yaffs_obj *obj) +-{ +- struct list_head *lh; +- struct yaffs_obj *list_obj; +- int count = 0; +- +- if (!obj) { +- yaffs_trace(YAFFS_TRACE_ALWAYS, "No object to verify"); +- BUG(); +- return; +- } +- +- if (yaffs_skip_verification(obj->my_dev)) +- return; +- +- if (!obj->parent) { +- yaffs_trace(YAFFS_TRACE_ALWAYS, "Object does not have parent"); +- BUG(); +- return; +- } +- +- if (obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { +- yaffs_trace(YAFFS_TRACE_ALWAYS, "Parent is not directory"); +- BUG(); +- } +- +- /* Iterate through the objects in each hash entry */ +- +- list_for_each(lh, &obj->parent->variant.dir_variant.children) { +- list_obj = list_entry(lh, struct yaffs_obj, siblings); +- yaffs_verify_obj(list_obj); +- if (obj == list_obj) +- count++; +- } +- +- if (count != 1) { +- yaffs_trace(YAFFS_TRACE_ALWAYS, +- "Object in directory %d times", +- count); +- BUG(); +- } +-} +- +-void yaffs_verify_dir(struct yaffs_obj *directory) +-{ +- struct list_head *lh; +- struct yaffs_obj *list_obj; +- +- if (!directory) { +- BUG(); +- return; +- } +- +- if (yaffs_skip_full_verification(directory->my_dev)) +- return; +- +- if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { +- yaffs_trace(YAFFS_TRACE_ALWAYS, +- "Directory has wrong type: %d", +- directory->variant_type); +- BUG(); +- } +- +- /* Iterate through the objects in each hash entry */ +- +- list_for_each(lh, &directory->variant.dir_variant.children) { +- list_obj = list_entry(lh, struct yaffs_obj, siblings); +- if (list_obj->parent != directory) { +- yaffs_trace(YAFFS_TRACE_ALWAYS, +- "Object in directory list has wrong parent %p", +- list_obj->parent); +- BUG(); +- } +- yaffs_verify_obj_in_dir(list_obj); +- } +-} +- +-static int yaffs_free_verification_failures; +- +-void yaffs_verify_free_chunks(struct yaffs_dev *dev) +-{ +- int counted; +- int difference; +- +- if (yaffs_skip_verification(dev)) +- return; +- +- counted = yaffs_count_free_chunks(dev); +- +- difference = dev->n_free_chunks - counted; +- +- if (difference) { +- yaffs_trace(YAFFS_TRACE_ALWAYS, +- "Freechunks verification failure %d %d %d", +- dev->n_free_chunks, counted, difference); +- yaffs_free_verification_failures++; +- } +-} +- +-int yaffs_verify_file_sane(struct yaffs_obj *in) +-{ +- (void) in; +- return YAFFS_OK; +-} +diff --git a/fs/yaffs2/yaffs_verify.h b/fs/yaffs2/yaffs_verify.h +deleted file mode 100644 +index 4f4af8d..0000000 +--- a/fs/yaffs2/yaffs_verify.h ++++ /dev/null +@@ -1,43 +0,0 @@ +-/* +- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU Lesser General Public License version 2.1 as +- * published by the Free Software Foundation. +- * +- * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +- */ +- +-#ifndef __YAFFS_VERIFY_H__ +-#define __YAFFS_VERIFY_H__ +- +-#include "yaffs_guts.h" +- +-void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi, +- int n); +-void yaffs_verify_collected_blk(struct yaffs_dev *dev, +- struct yaffs_block_info *bi, int n); +-void yaffs_verify_blocks(struct yaffs_dev *dev); +- +-void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh, +- struct yaffs_ext_tags *tags, int parent_check); +-void yaffs_verify_file(struct yaffs_obj *obj); +-void yaffs_verify_link(struct yaffs_obj *obj); +-void yaffs_verify_symlink(struct yaffs_obj *obj); +-void yaffs_verify_special(struct yaffs_obj *obj); +-void yaffs_verify_obj(struct yaffs_obj *obj); +-void yaffs_verify_objects(struct yaffs_dev *dev); +-void yaffs_verify_obj_in_dir(struct yaffs_obj *obj); +-void yaffs_verify_dir(struct yaffs_obj *directory); +-void yaffs_verify_free_chunks(struct yaffs_dev *dev); +- +-int yaffs_verify_file_sane(struct yaffs_obj *obj); +- +-int yaffs_skip_verification(struct yaffs_dev *dev); +- +-#endif +diff --git a/fs/yaffs2/yaffs_vfs.c b/fs/yaffs2/yaffs_vfs.c +deleted file mode 100644 +index 92d2f5f..0000000 +--- a/fs/yaffs2/yaffs_vfs.c ++++ /dev/null +@@ -1,3354 +0,0 @@ +-/* +- * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * Acknowledgements: +- * Luc van OostenRyck for numerous patches. +- * Nick Bane for numerous patches. +- * Nick Bane for 2.5/2.6 integration. +- * Andras Toth for mknod rdev issue. +- * Michael Fischer for finding the problem with inode inconsistency. +- * Some code bodily lifted from JFFS +- * +- * 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. +- */ +- +-/* +- * +- * This is the file system front-end to YAFFS that hooks it up to +- * the VFS. +- * +- * Special notes: +- * >> 2.4: sb->u.generic_sbp points to the struct yaffs_dev associated with +- * this superblock +- * >> 2.6: sb->s_fs_info points to the struct yaffs_dev associated with this +- * superblock +- * >> inode->u.generic_ip points to the associated struct yaffs_obj. +- */ +- +-/* +- * There are two variants of the VFS glue code. This variant should compile +- * for any version of Linux. +- */ +-#include +- +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)) +-#define YAFFS_COMPILE_BACKGROUND +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)) +-#define YAFFS_COMPILE_FREEZER +-#endif +-#endif +- +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)) +-#define YAFFS_COMPILE_EXPORTFS +-#endif +- +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35)) +-#define YAFFS_USE_SETATTR_COPY +-#define YAFFS_USE_TRUNCATE_SETSIZE +-#endif +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35)) +-#define YAFFS_HAS_EVICT_INODE +-#endif +- +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) +-#define YAFFS_NEW_FOLLOW_LINK 1 +-#else +-#define YAFFS_NEW_FOLLOW_LINK 0 +-#endif +- +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) +-#define YAFFS_HAS_WRITE_SUPER +-#endif +- +- +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) +-#include +-#endif +- +-#include +-#include +-#include +-#include +-#include +-#include +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)) +-#include +-#endif +-#include +-#include +-#include +-#include +-#include +- +-#if (YAFFS_NEW_FOLLOW_LINK == 1) +-#include +-#endif +- +-#ifdef YAFFS_COMPILE_EXPORTFS +-#include +-#endif +- +-#ifdef YAFFS_COMPILE_BACKGROUND +-#include +-#include +-#endif +-#ifdef YAFFS_COMPILE_FREEZER +-#include +-#endif +- +-#include +- +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) +- +-#include +- +-#define UnlockPage(p) unlock_page(p) +-#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags) +- +-/* FIXME: use sb->s_id instead ? */ +-#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf) +- +-#else +- +-#include +-#define BDEVNAME_SIZE 0 +-#define yaffs_devname(sb, buf) kdevname(sb->s_dev) +- +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)) +-/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */ +-#define __user +-#endif +- +-#endif +- +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)) +-#define YPROC_ROOT (&proc_root) +-#else +-#define YPROC_ROOT NULL +-#endif +- +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)) +-#define Y_INIT_TIMER(a) init_timer(a) +-#else +-#define Y_INIT_TIMER(a) init_timer_on_stack(a) +-#endif +- +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27)) +-#define YAFFS_USE_WRITE_BEGIN_END 1 +-#else +-#define YAFFS_USE_WRITE_BEGIN_END 0 +-#endif +- +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) +-#define YAFFS_SUPER_HAS_DIRTY +-#endif +- +- +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) +-#define set_nlink(inode, count) do { (inode)->i_nlink = (count); } while(0) +-#endif +- +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28)) +-static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size) +-{ +- uint64_t result = partition_size; +- do_div(result, block_size); +- return (uint32_t) result; +-} +-#else +-#define YCALCBLOCKS(s, b) ((s)/(b)) +-#endif +- +-#include +-#include +- +-#include "yportenv.h" +-#include "yaffs_trace.h" +-#include "yaffs_guts.h" +-#include "yaffs_attribs.h" +- +-#include "yaffs_linux.h" +- +-#include "yaffs_mtdif.h" +- +-unsigned int yaffs_trace_mask = YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_ALWAYS; +-unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS; +-unsigned int yaffs_auto_checkpoint = 1; +-unsigned int yaffs_gc_control = 1; +-unsigned int yaffs_bg_enable = 1; +-unsigned int yaffs_auto_select = 1; +-/* Module Parameters */ +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) +-module_param(yaffs_trace_mask, uint, 0644); +-module_param(yaffs_wr_attempts, uint, 0644); +-module_param(yaffs_auto_checkpoint, uint, 0644); +-module_param(yaffs_gc_control, uint, 0644); +-module_param(yaffs_bg_enable, uint, 0644); +-#else +-MODULE_PARM(yaffs_trace_mask, "i"); +-MODULE_PARM(yaffs_wr_attempts, "i"); +-MODULE_PARM(yaffs_auto_checkpoint, "i"); +-MODULE_PARM(yaffs_gc_control, "i"); +-#endif +- +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)) +-/* use iget and read_inode */ +-#define Y_IGET(sb, inum) iget((sb), (inum)) +- +-#else +-/* Call local equivalent */ +-#define YAFFS_USE_OWN_IGET +-#define Y_IGET(sb, inum) yaffs_iget((sb), (inum)) +- +-#endif +- +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)) +-#define yaffs_inode_to_obj_lv(iptr) ((iptr)->i_private) +-#else +-#define yaffs_inode_to_obj_lv(iptr) ((iptr)->u.generic_ip) +-#endif +- +-#define yaffs_inode_to_obj(iptr) \ +- ((struct yaffs_obj *)(yaffs_inode_to_obj_lv(iptr))) +-#define yaffs_dentry_to_obj(dptr) yaffs_inode_to_obj((dptr)->d_inode) +- +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) +-#define yaffs_super_to_dev(sb) ((struct yaffs_dev *)sb->s_fs_info) +-#else +-#define yaffs_super_to_dev(sb) ((struct yaffs_dev *)sb->u.generic_sbp) +-#endif +- +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) +-#define Y_CLEAR_INODE(i) clear_inode(i) +-#else +-#define Y_CLEAR_INODE(i) end_writeback(i) +-#endif +- +- +-#define update_dir_time(dir) do {\ +- (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \ +- } while (0) +- +-static void yaffs_fill_inode_from_obj(struct inode *inode, +- struct yaffs_obj *obj); +- +- +-static void yaffs_gross_lock(struct yaffs_dev *dev) +-{ +- yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locking %p", current); +- mutex_lock(&(yaffs_dev_to_lc(dev)->gross_lock)); +- yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locked %p", current); +-} +- +-static void yaffs_gross_unlock(struct yaffs_dev *dev) +-{ +- yaffs_trace(YAFFS_TRACE_LOCK, "yaffs unlocking %p", current); +- mutex_unlock(&(yaffs_dev_to_lc(dev)->gross_lock)); +-} +- +- +-static int yaffs_readpage_nolock(struct file *f, struct page *pg) +-{ +- /* Lifted from jffs2 */ +- +- struct yaffs_obj *obj; +- unsigned char *pg_buf; +- int ret; +- loff_t pos = ((loff_t) pg->index) << PAGE_CACHE_SHIFT; +- struct yaffs_dev *dev; +- +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_readpage_nolock at %lld, size %08x", +- (long long)pos, +- (unsigned)PAGE_CACHE_SIZE); +- +- obj = yaffs_dentry_to_obj(f->f_dentry); +- +- dev = obj->my_dev; +- +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) +- BUG_ON(!PageLocked(pg)); +-#else +- if (!PageLocked(pg)) +- PAGE_BUG(pg); +-#endif +- +- pg_buf = kmap(pg); +- /* FIXME: Can kmap fail? */ +- +- yaffs_gross_lock(dev); +- +- ret = yaffs_file_rd(obj, pg_buf, pos, PAGE_CACHE_SIZE); +- +- yaffs_gross_unlock(dev); +- +- if (ret >= 0) +- ret = 0; +- +- if (ret) { +- ClearPageUptodate(pg); +- SetPageError(pg); +- } else { +- SetPageUptodate(pg); +- ClearPageError(pg); +- } +- +- flush_dcache_page(pg); +- kunmap(pg); +- +- yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage_nolock done"); +- return ret; +-} +- +-static int yaffs_readpage_unlock(struct file *f, struct page *pg) +-{ +- int ret = yaffs_readpage_nolock(f, pg); +- UnlockPage(pg); +- return ret; +-} +- +-static int yaffs_readpage(struct file *f, struct page *pg) +-{ +- int ret; +- +- yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage"); +- ret = yaffs_readpage_unlock(f, pg); +- yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage done"); +- return ret; +-} +- +- +-static void yaffs_set_super_dirty_val(struct yaffs_dev *dev, int val) +-{ +- struct yaffs_linux_context *lc = yaffs_dev_to_lc(dev); +- +- if (lc) +- lc->dirty = val; +- +-# ifdef YAFFS_SUPER_HAS_DIRTY +- { +- struct super_block *sb = lc->super; +- +- if (sb) +- sb->s_dirt = val; +- } +-#endif +- +-} +- +-static void yaffs_set_super_dirty(struct yaffs_dev *dev) +-{ +- yaffs_set_super_dirty_val(dev, 1); +-} +- +-static void yaffs_clear_super_dirty(struct yaffs_dev *dev) +-{ +- yaffs_set_super_dirty_val(dev, 0); +-} +- +-static int yaffs_check_super_dirty(struct yaffs_dev *dev) +-{ +- struct yaffs_linux_context *lc = yaffs_dev_to_lc(dev); +- +- if (lc && lc->dirty) +- return 1; +- +-# ifdef YAFFS_SUPER_HAS_DIRTY +- { +- struct super_block *sb = lc->super; +- +- if (sb && sb->s_dirt) +- return 1; +- } +-#endif +- return 0; +- +-} +- +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) +-static int yaffs_writepage(struct page *page, struct writeback_control *wbc) +-#else +-static int yaffs_writepage(struct page *page) +-#endif +-{ +- struct yaffs_dev *dev; +- struct address_space *mapping = page->mapping; +- struct inode *inode; +- unsigned long end_index; +- char *buffer; +- struct yaffs_obj *obj; +- int n_written = 0; +- unsigned n_bytes; +- loff_t i_size; +- +- if (!mapping) +- BUG(); +- inode = mapping->host; +- if (!inode) +- BUG(); +- i_size = i_size_read(inode); +- +- end_index = i_size >> PAGE_CACHE_SHIFT; +- +- if (page->index < end_index) +- n_bytes = PAGE_CACHE_SIZE; +- else { +- n_bytes = i_size & (PAGE_CACHE_SIZE - 1); +- +- if (page->index > end_index || !n_bytes) { +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_writepage at %lld, inode size = %lld!!", +- ((loff_t)page->index) << PAGE_CACHE_SHIFT, +- inode->i_size); +- yaffs_trace(YAFFS_TRACE_OS, +- " -> don't care!!"); +- +- zero_user_segment(page, 0, PAGE_CACHE_SIZE); +- set_page_writeback(page); +- unlock_page(page); +- end_page_writeback(page); +- return 0; +- } +- } +- +- if (n_bytes != PAGE_CACHE_SIZE) +- zero_user_segment(page, n_bytes, PAGE_CACHE_SIZE); +- +- get_page(page); +- +- buffer = kmap(page); +- +- obj = yaffs_inode_to_obj(inode); +- dev = obj->my_dev; +- yaffs_gross_lock(dev); +- +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_writepage at %lld, size %08x", +- ((loff_t)page->index) << PAGE_CACHE_SHIFT, n_bytes); +- yaffs_trace(YAFFS_TRACE_OS, +- "writepag0: obj = %lld, ino = %lld", +- obj->variant.file_variant.file_size, inode->i_size); +- +- n_written = yaffs_wr_file(obj, buffer, +- ((loff_t)page->index) << PAGE_CACHE_SHIFT, n_bytes, 0); +- +- yaffs_set_super_dirty(dev); +- +- yaffs_trace(YAFFS_TRACE_OS, +- "writepag1: obj = %lld, ino = %lld", +- obj->variant.file_variant.file_size, inode->i_size); +- +- yaffs_gross_unlock(dev); +- +- kunmap(page); +- set_page_writeback(page); +- unlock_page(page); +- end_page_writeback(page); +- put_page(page); +- +- return (n_written == n_bytes) ? 0 : -ENOSPC; +-} +- +-/* Space holding and freeing is done to ensure we have space available for write_begin/end */ +-/* For now we just assume few parallel writes and check against a small number. */ +-/* Todo: need to do this with a counter to handle parallel reads better */ +- +-static ssize_t yaffs_hold_space(struct file *f) +-{ +- struct yaffs_obj *obj; +- struct yaffs_dev *dev; +- +- int n_free_chunks; +- +- obj = yaffs_dentry_to_obj(f->f_dentry); +- +- dev = obj->my_dev; +- +- yaffs_gross_lock(dev); +- +- n_free_chunks = yaffs_get_n_free_chunks(dev); +- +- yaffs_gross_unlock(dev); +- +- return (n_free_chunks > 20) ? 1 : 0; +-} +- +-static void yaffs_release_space(struct file *f) +-{ +- struct yaffs_obj *obj; +- struct yaffs_dev *dev; +- +- obj = yaffs_dentry_to_obj(f->f_dentry); +- +- dev = obj->my_dev; +- +- yaffs_gross_lock(dev); +- +- yaffs_gross_unlock(dev); +-} +- +-#if (YAFFS_USE_WRITE_BEGIN_END > 0) +-static int yaffs_write_begin(struct file *filp, struct address_space *mapping, +- loff_t pos, unsigned len, unsigned flags, +- struct page **pagep, void **fsdata) +-{ +- struct page *pg = NULL; +- pgoff_t index = pos >> PAGE_CACHE_SHIFT; +- +- int ret = 0; +- int space_held = 0; +- +- /* Get a page */ +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) +- pg = grab_cache_page_write_begin(mapping, index, flags); +-#else +- pg = __grab_cache_page(mapping, index); +-#endif +- +- *pagep = pg; +- if (!pg) { +- ret = -ENOMEM; +- goto out; +- } +- yaffs_trace(YAFFS_TRACE_OS, +- "start yaffs_write_begin index %d(%x) uptodate %d", +- (int)index, (int)index, Page_Uptodate(pg) ? 1 : 0); +- +- /* Get fs space */ +- space_held = yaffs_hold_space(filp); +- +- if (!space_held) { +- ret = -ENOSPC; +- goto out; +- } +- +- /* Update page if required */ +- +- if (!Page_Uptodate(pg)) +- ret = yaffs_readpage_nolock(filp, pg); +- +- if (ret) +- goto out; +- +- /* Happy path return */ +- yaffs_trace(YAFFS_TRACE_OS, "end yaffs_write_begin - ok"); +- +- return 0; +- +-out: +- yaffs_trace(YAFFS_TRACE_OS, +- "end yaffs_write_begin fail returning %d", ret); +- if (space_held) +- yaffs_release_space(filp); +- if (pg) { +- unlock_page(pg); +- page_cache_release(pg); +- } +- return ret; +-} +- +-#else +- +-static int yaffs_prepare_write(struct file *f, struct page *pg, +- unsigned offset, unsigned to) +-{ +- yaffs_trace(YAFFS_TRACE_OS, "yaffs_prepair_write"); +- +- if (!Page_Uptodate(pg)) +- return yaffs_readpage_nolock(f, pg); +- return 0; +-} +-#endif +- +- +-static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, +- loff_t * pos) +-{ +- struct yaffs_obj *obj; +- int n_written; +- loff_t ipos; +- struct inode *inode; +- struct yaffs_dev *dev; +- +- obj = yaffs_dentry_to_obj(f->f_dentry); +- +- if (!obj) { +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_file_write: hey obj is null!"); +- return -EINVAL; +- } +- +- dev = obj->my_dev; +- +- yaffs_gross_lock(dev); +- +- inode = f->f_dentry->d_inode; +- +- if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND) +- ipos = inode->i_size; +- else +- ipos = *pos; +- +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_file_write about to write writing %u(%x) bytes to object %d at %lld", +- (unsigned)n, (unsigned)n, obj->obj_id, ipos); +- +- n_written = yaffs_wr_file(obj, buf, ipos, n, 0); +- +- yaffs_set_super_dirty(dev); +- +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_file_write: %d(%x) bytes written", +- (unsigned)n, (unsigned)n); +- +- if (n_written > 0) { +- ipos += n_written; +- *pos = ipos; +- if (ipos > inode->i_size) { +- inode->i_size = ipos; +- inode->i_blocks = (ipos + 511) >> 9; +- +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_file_write size updated to %lld bytes, %d blocks", +- ipos, (int)(inode->i_blocks)); +- } +- +- } +- yaffs_gross_unlock(dev); +- return (n_written == 0) && (n > 0) ? -ENOSPC : n_written; +-} +- +- +-#if (YAFFS_USE_WRITE_BEGIN_END > 0) +-static int yaffs_write_end(struct file *filp, struct address_space *mapping, +- loff_t pos, unsigned len, unsigned copied, +- struct page *pg, void *fsdadata) +-{ +- int ret = 0; +- void *addr, *kva; +- uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1); +- +- kva = kmap(pg); +- addr = kva + offset_into_page; +- +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_write_end addr %p pos %lld n_bytes %d", +- addr, pos, copied); +- +- ret = yaffs_file_write(filp, addr, copied, &pos); +- +- if (ret != copied) { +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_write_end not same size ret %d copied %d", +- ret, copied); +- SetPageError(pg); +- } +- +- kunmap(pg); +- +- yaffs_release_space(filp); +- unlock_page(pg); +- page_cache_release(pg); +- return ret; +-} +-#else +- +-static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset, +- unsigned to) +-{ +- void *addr, *kva; +- +- loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset; +- int n_bytes = to - offset; +- int n_written; +- +- kva = kmap(pg); +- addr = kva + offset; +- +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_commit_write addr %p pos %lld n_bytes %d", +- addr, pos, n_bytes); +- +- n_written = yaffs_file_write(f, addr, n_bytes, &pos); +- +- if (n_written != n_bytes) { +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_commit_write not same size n_written %d n_bytes %d", +- n_written, n_bytes); +- SetPageError(pg); +- } +- kunmap(pg); +- +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_commit_write returning %d", +- n_written == n_bytes ? 0 : n_written); +- +- return n_written == n_bytes ? 0 : n_written; +-} +-#endif +- +-static struct address_space_operations yaffs_file_address_operations = { +- .readpage = yaffs_readpage, +- .writepage = yaffs_writepage, +-#if (YAFFS_USE_WRITE_BEGIN_END > 0) +- .write_begin = yaffs_write_begin, +- .write_end = yaffs_write_end, +-#else +- .prepare_write = yaffs_prepare_write, +- .commit_write = yaffs_commit_write, +-#endif +-}; +- +- +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) +-static int yaffs_file_flush(struct file *file, fl_owner_t id) +-#else +-static int yaffs_file_flush(struct file *file) +-#endif +-{ +- struct yaffs_obj *obj = yaffs_dentry_to_obj(file->f_dentry); +- +- struct yaffs_dev *dev = obj->my_dev; +- +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_file_flush object %d (%s)", +- obj->obj_id, +- obj->dirty ? "dirty" : "clean"); +- +- yaffs_gross_lock(dev); +- +- yaffs_flush_file(obj, 1, 0); +- +- yaffs_gross_unlock(dev); +- +- return 0; +-} +- +- +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) +-static int yaffs_sync_object(struct file *file, loff_t start, loff_t end, int datasync) +-#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34)) +-static int yaffs_sync_object(struct file *file, int datasync) +-#else +-static int yaffs_sync_object(struct file *file, struct dentry *dentry, +- int datasync) +-#endif +-{ +- struct yaffs_obj *obj; +- struct yaffs_dev *dev; +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34)) +- struct dentry *dentry = file->f_path.dentry; +-#endif +- +- obj = yaffs_dentry_to_obj(dentry); +- +- dev = obj->my_dev; +- +- yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, +- "yaffs_sync_object"); +- yaffs_gross_lock(dev); +- yaffs_flush_file(obj, 1, datasync); +- yaffs_gross_unlock(dev); +- return 0; +-} +- +- +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)) +-static const struct file_operations yaffs_file_operations = { +- .read = do_sync_read, +- .write = do_sync_write, +- .aio_read = generic_file_aio_read, +- .aio_write = generic_file_aio_write, +- .mmap = generic_file_mmap, +- .flush = yaffs_file_flush, +- .fsync = yaffs_sync_object, +- .splice_read = generic_file_splice_read, +- .splice_write = generic_file_splice_write, +- .llseek = generic_file_llseek, +-}; +- +-#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)) +- +-static const struct file_operations yaffs_file_operations = { +- .read = do_sync_read, +- .write = do_sync_write, +- .aio_read = generic_file_aio_read, +- .aio_write = generic_file_aio_write, +- .mmap = generic_file_mmap, +- .flush = yaffs_file_flush, +- .fsync = yaffs_sync_object, +- .sendfile = generic_file_sendfile, +-}; +- +-#else +- +-static const struct file_operations yaffs_file_operations = { +- .read = generic_file_read, +- .write = generic_file_write, +- .mmap = generic_file_mmap, +- .flush = yaffs_file_flush, +- .fsync = yaffs_sync_object, +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) +- .sendfile = generic_file_sendfile, +-#endif +-}; +-#endif +- +- +- +- +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)) +-static void zero_user_segment(struct page *page, unsigned start, unsigned end) +-{ +- void *kaddr = kmap_atomic(page, KM_USER0); +- memset(kaddr + start, 0, end - start); +- kunmap_atomic(kaddr, KM_USER0); +- flush_dcache_page(page); +-} +-#endif +- +- +-static int yaffs_vfs_setsize(struct inode *inode, loff_t newsize) +-{ +-#ifdef YAFFS_USE_TRUNCATE_SETSIZE +- truncate_setsize(inode, newsize); +- return 0; +-#else +- truncate_inode_pages(&inode->i_data, newsize); +- return 0; +-#endif +- +-} +- +- +-static int yaffs_vfs_setattr(struct inode *inode, struct iattr *attr) +-{ +-#ifdef YAFFS_USE_SETATTR_COPY +- setattr_copy(inode, attr); +- return 0; +-#else +- return inode_setattr(inode, attr); +-#endif +- +-} +- +-static int yaffs_setattr(struct dentry *dentry, struct iattr *attr) +-{ +- struct inode *inode = dentry->d_inode; +- int error = 0; +- struct yaffs_dev *dev; +- +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_setattr of object %d", +- yaffs_inode_to_obj(inode)->obj_id); +-#if 0 +- /* Fail if a requested resize >= 2GB */ +- if (attr->ia_valid & ATTR_SIZE && (attr->ia_size >> 31)) +- error = -EINVAL; +-#endif +- +- if (error == 0) +- error = inode_change_ok(inode, attr); +- if (error == 0) { +- int result; +- if (!error) { +- error = yaffs_vfs_setattr(inode, attr); +- yaffs_trace(YAFFS_TRACE_OS, "inode_setattr called"); +- if (attr->ia_valid & ATTR_SIZE) { +- yaffs_vfs_setsize(inode, attr->ia_size); +- inode->i_blocks = (inode->i_size + 511) >> 9; +- } +- } +- dev = yaffs_inode_to_obj(inode)->my_dev; +- if (attr->ia_valid & ATTR_SIZE) { +- yaffs_trace(YAFFS_TRACE_OS, +- "resize to %d(%x)", +- (int)(attr->ia_size), +- (int)(attr->ia_size)); +- } +- yaffs_gross_lock(dev); +- result = yaffs_set_attribs(yaffs_inode_to_obj(inode), attr); +- if (result == YAFFS_OK) { +- error = 0; +- } else { +- error = -EPERM; +- } +- yaffs_gross_unlock(dev); +- +- } +- +- yaffs_trace(YAFFS_TRACE_OS, "yaffs_setattr done returning %d", error); +- +- return error; +-} +- +-static int yaffs_setxattr(struct dentry *dentry, const char *name, +- const void *value, size_t size, int flags) +-{ +- struct inode *inode = dentry->d_inode; +- int error = 0; +- struct yaffs_dev *dev; +- struct yaffs_obj *obj = yaffs_inode_to_obj(inode); +- +- yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr of object %d", obj->obj_id); +- +- if (error == 0) { +- int result; +- dev = obj->my_dev; +- yaffs_gross_lock(dev); +- result = yaffs_set_xattrib(obj, name, value, size, flags); +- if (result == YAFFS_OK) +- error = 0; +- else if (result < 0) +- error = result; +- yaffs_gross_unlock(dev); +- +- } +- yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr done returning %d", error); +- +- return error; +-} +- +-static ssize_t yaffs_getxattr(struct dentry * dentry, const char *name, +- void *buff, size_t size) +-{ +- struct inode *inode = dentry->d_inode; +- int error = 0; +- struct yaffs_dev *dev; +- struct yaffs_obj *obj = yaffs_inode_to_obj(inode); +- +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_getxattr \"%s\" from object %d", +- name, obj->obj_id); +- +- if (error == 0) { +- dev = obj->my_dev; +- yaffs_gross_lock(dev); +- error = yaffs_get_xattrib(obj, name, buff, size); +- yaffs_gross_unlock(dev); +- +- } +- yaffs_trace(YAFFS_TRACE_OS, "yaffs_getxattr done returning %d", error); +- +- return error; +-} +- +-static int yaffs_removexattr(struct dentry *dentry, const char *name) +-{ +- struct inode *inode = dentry->d_inode; +- int error = 0; +- struct yaffs_dev *dev; +- struct yaffs_obj *obj = yaffs_inode_to_obj(inode); +- +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_removexattr of object %d", obj->obj_id); +- +- if (error == 0) { +- int result; +- dev = obj->my_dev; +- yaffs_gross_lock(dev); +- result = yaffs_remove_xattrib(obj, name); +- if (result == YAFFS_OK) +- error = 0; +- else if (result < 0) +- error = result; +- yaffs_gross_unlock(dev); +- +- } +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_removexattr done returning %d", error); +- +- return error; +-} +- +-static ssize_t yaffs_listxattr(struct dentry * dentry, char *buff, size_t size) +-{ +- struct inode *inode = dentry->d_inode; +- int error = 0; +- struct yaffs_dev *dev; +- struct yaffs_obj *obj = yaffs_inode_to_obj(inode); +- +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_listxattr of object %d", obj->obj_id); +- +- if (error == 0) { +- dev = obj->my_dev; +- yaffs_gross_lock(dev); +- error = yaffs_list_xattrib(obj, buff, size); +- yaffs_gross_unlock(dev); +- +- } +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_listxattr done returning %d", error); +- +- return error; +-} +- +- +-static const struct inode_operations yaffs_file_inode_operations = { +- .setattr = yaffs_setattr, +- .setxattr = yaffs_setxattr, +- .getxattr = yaffs_getxattr, +- .listxattr = yaffs_listxattr, +- .removexattr = yaffs_removexattr, +-}; +- +- +-static int yaffs_readlink(struct dentry *dentry, char __user * buffer, +- int buflen) +-{ +- unsigned char *alias; +- int ret; +- +- struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev; +- +- yaffs_gross_lock(dev); +- +- alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry)); +- +- yaffs_gross_unlock(dev); +- +- if (!alias) +- return -ENOMEM; +- +- ret = vfs_readlink(dentry, buffer, buflen, alias); +- kfree(alias); +- return ret; +-} +- +-#if (YAFFS_NEW_FOLLOW_LINK == 1) +-static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd) +-{ +- void *ret; +-#else +-static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd) +-{ +- int ret +-#endif +- unsigned char *alias; +- int ret_int = 0; +- struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev; +- +- yaffs_gross_lock(dev); +- +- alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry)); +- yaffs_gross_unlock(dev); +- +- if (!alias) { +- ret_int = -ENOMEM; +- goto out; +- } +-#if (YAFFS_NEW_FOLLOW_LINK == 1) +- nd_set_link(nd, alias); +- ret = alias; +-out: +- if (ret_int) +- ret = ERR_PTR(ret_int); +- return ret; +-#else +- ret = vfs_follow_link(nd, alias); +- kfree(alias); +-out: +- if (ret_int) +- ret = ret_int; +- return ret; +-#endif +-} +- +- +-#ifdef YAFFS_HAS_PUT_INODE +- +-/* For now put inode is just for debugging +- * Put inode is called when the inode **structure** is put. +- */ +-static void yaffs_put_inode(struct inode *inode) +-{ +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_put_inode: ino %d, count %d"), +- (int)inode->i_ino, atomic_read(&inode->i_count); +- +-} +-#endif +- +-#if (YAFFS_NEW_FOLLOW_LINK == 1) +-void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias) +-{ +- kfree(alias); +-} +-#endif +- +-static const struct inode_operations yaffs_symlink_inode_operations = { +- .readlink = yaffs_readlink, +- .follow_link = yaffs_follow_link, +-#if (YAFFS_NEW_FOLLOW_LINK == 1) +- .put_link = yaffs_put_link, +-#endif +- .setattr = yaffs_setattr, +- .setxattr = yaffs_setxattr, +- .getxattr = yaffs_getxattr, +- .listxattr = yaffs_listxattr, +- .removexattr = yaffs_removexattr, +-}; +- +-#ifdef YAFFS_USE_OWN_IGET +- +-static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino) +-{ +- struct inode *inode; +- struct yaffs_obj *obj; +- struct yaffs_dev *dev = yaffs_super_to_dev(sb); +- +- yaffs_trace(YAFFS_TRACE_OS, "yaffs_iget for %lu", ino); +- +- inode = iget_locked(sb, ino); +- if (!inode) +- return ERR_PTR(-ENOMEM); +- if (!(inode->i_state & I_NEW)) +- return inode; +- +- /* NB This is called as a side effect of other functions, but +- * we had to release the lock to prevent deadlocks, so +- * need to lock again. +- */ +- +- yaffs_gross_lock(dev); +- +- obj = yaffs_find_by_number(dev, inode->i_ino); +- +- yaffs_fill_inode_from_obj(inode, obj); +- +- yaffs_gross_unlock(dev); +- +- unlock_new_inode(inode); +- return inode; +-} +- +-#else +- +-static void yaffs_read_inode(struct inode *inode) +-{ +- /* NB This is called as a side effect of other functions, but +- * we had to release the lock to prevent deadlocks, so +- * need to lock again. +- */ +- +- struct yaffs_obj *obj; +- struct yaffs_dev *dev = yaffs_super_to_dev(inode->i_sb); +- +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_read_inode for %d", (int)inode->i_ino); +- +- if (current != yaffs_dev_to_lc(dev)->readdir_process) +- yaffs_gross_lock(dev); +- +- obj = yaffs_find_by_number(dev, inode->i_ino); +- +- yaffs_fill_inode_from_obj(inode, obj); +- +- if (current != yaffs_dev_to_lc(dev)->readdir_process) +- yaffs_gross_unlock(dev); +-} +- +-#endif +- +- +- +-struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev, +- struct yaffs_obj *obj) +-{ +- struct inode *inode; +- +- if (!sb) { +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_get_inode for NULL super_block!!"); +- return NULL; +- +- } +- +- if (!obj) { +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_get_inode for NULL object!!"); +- return NULL; +- +- } +- +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_get_inode for object %d", obj->obj_id); +- +- inode = Y_IGET(sb, obj->obj_id); +- if (IS_ERR(inode)) +- return NULL; +- +- /* NB Side effect: iget calls back to yaffs_read_inode(). */ +- /* iget also increments the inode's i_count */ +- /* NB You can't be holding gross_lock or deadlock will happen! */ +- +- return inode; +-} +- +- +- +-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) +-#define YCRED(x) x +-#else +-#define YCRED(x) (x->cred) +-#endif +- +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) +-static int yaffs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, +- dev_t rdev) +-#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) +-static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, +- dev_t rdev) +-#else +-static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, +- int rdev) +-#endif +-{ +- struct inode *inode; +- +- struct yaffs_obj *obj = NULL; +- struct yaffs_dev *dev; +- +- struct yaffs_obj *parent = yaffs_inode_to_obj(dir); +- +- int error = -ENOSPC; +- uid_t uid = YCRED(current)->fsuid; +- gid_t gid = +- (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid; +- +- if ((dir->i_mode & S_ISGID) && S_ISDIR(mode)) +- mode |= S_ISGID; +- +- if (parent) { +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_mknod: parent object %d type %d", +- parent->obj_id, parent->variant_type); +- } else { +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_mknod: could not get parent object"); +- return -EPERM; +- } +- +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_mknod: making oject for %s, mode %x dev %x", +- dentry->d_name.name, mode, rdev); +- +- dev = parent->my_dev; +- +- yaffs_gross_lock(dev); +- +- switch (mode & S_IFMT) { +- default: +- /* Special (socket, fifo, device...) */ +- yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making special"); +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) +- obj = +- yaffs_create_special(parent, dentry->d_name.name, mode, uid, +- gid, old_encode_dev(rdev)); +-#else +- obj = +- yaffs_create_special(parent, dentry->d_name.name, mode, uid, +- gid, rdev); +-#endif +- break; +- case S_IFREG: /* file */ +- yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making file"); +- obj = yaffs_create_file(parent, dentry->d_name.name, mode, uid, +- gid); +- break; +- case S_IFDIR: /* directory */ +- yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making directory"); +- obj = yaffs_create_dir(parent, dentry->d_name.name, mode, +- uid, gid); +- break; +- case S_IFLNK: /* symlink */ +- yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making symlink"); +- obj = NULL; /* Do we ever get here? */ +- break; +- } +- +- /* Can not call yaffs_get_inode() with gross lock held */ +- yaffs_gross_unlock(dev); +- +- if (obj) { +- inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj); +- d_instantiate(dentry, inode); +- update_dir_time(dir); +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_mknod created object %d count = %d", +- obj->obj_id, atomic_read(&inode->i_count)); +- error = 0; +- yaffs_fill_inode_from_obj(dir, parent); +- } else { +- yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod failed making object"); +- error = -ENOMEM; +- } +- +- return error; +-} +- +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) +-static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) +-#else +-static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +-#endif +-{ +- int ret_val; +- yaffs_trace(YAFFS_TRACE_OS, "yaffs_mkdir"); +- ret_val = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0); +- return ret_val; +-} +- +- +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) +-static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode, +- bool dummy) +-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) +-static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode, +- struct nameidata *n) +-#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) +-static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode, +- struct nameidata *n) +-#else +-static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode) +-#endif +-{ +- yaffs_trace(YAFFS_TRACE_OS, "yaffs_create"); +- return yaffs_mknod(dir, dentry, mode | S_IFREG, 0); +-} +- +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) +-static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry, +- unsigned int dummy) +-#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) +-static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry, +- struct nameidata *n) +-#else +-static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry) +-#endif +-{ +- struct yaffs_obj *obj; +- struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */ +- +- struct yaffs_dev *dev = yaffs_inode_to_obj(dir)->my_dev; +- +- if (current != yaffs_dev_to_lc(dev)->readdir_process) +- yaffs_gross_lock(dev); +- +- yaffs_trace(YAFFS_TRACE_OS, "yaffs_lookup for %d:%s", +- yaffs_inode_to_obj(dir)->obj_id, dentry->d_name.name); +- +- obj = yaffs_find_by_name(yaffs_inode_to_obj(dir), dentry->d_name.name); +- +- obj = yaffs_get_equivalent_obj(obj); /* in case it was a hardlink */ +- +- /* Can't hold gross lock when calling yaffs_get_inode() */ +- if (current != yaffs_dev_to_lc(dev)->readdir_process) +- yaffs_gross_unlock(dev); +- +- if (obj) { +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_lookup found %d", obj->obj_id); +- +- inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj); +- } else { +- yaffs_trace(YAFFS_TRACE_OS, "yaffs_lookup not found"); +- +- } +- +-/* added NCB for 2.5/6 compatability - forces add even if inode is +- * NULL which creates dentry hash */ +- d_add(dentry, inode); +- +- return NULL; +-} +- +-/* +- * Create a link... +- */ +-static int yaffs_link(struct dentry *old_dentry, struct inode *dir, +- struct dentry *dentry) +-{ +- struct inode *inode = old_dentry->d_inode; +- struct yaffs_obj *obj = NULL; +- struct yaffs_obj *link = NULL; +- struct yaffs_dev *dev; +- +- yaffs_trace(YAFFS_TRACE_OS, "yaffs_link"); +- +- obj = yaffs_inode_to_obj(inode); +- dev = obj->my_dev; +- +- yaffs_gross_lock(dev); +- +- if (!S_ISDIR(inode->i_mode)) /* Don't link directories */ +- link = +- yaffs_link_obj(yaffs_inode_to_obj(dir), dentry->d_name.name, +- obj); +- +- if (link) { +- set_nlink(old_dentry->d_inode, yaffs_get_obj_link_count(obj)); +- d_instantiate(dentry, old_dentry->d_inode); +- atomic_inc(&old_dentry->d_inode->i_count); +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_link link count %d i_count %d", +- old_dentry->d_inode->i_nlink, +- atomic_read(&old_dentry->d_inode->i_count)); +- } +- +- yaffs_gross_unlock(dev); +- +- if (link) { +- update_dir_time(dir); +- return 0; +- } +- +- return -EPERM; +-} +- +-static int yaffs_symlink(struct inode *dir, struct dentry *dentry, +- const char *symname) +-{ +- struct yaffs_obj *obj; +- struct yaffs_dev *dev; +- uid_t uid = YCRED(current)->fsuid; +- gid_t gid = +- (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid; +- +- yaffs_trace(YAFFS_TRACE_OS, "yaffs_symlink"); +- +- if (strnlen(dentry->d_name.name, YAFFS_MAX_NAME_LENGTH + 1) > +- YAFFS_MAX_NAME_LENGTH) +- return -ENAMETOOLONG; +- +- if (strnlen(symname, YAFFS_MAX_ALIAS_LENGTH + 1) > +- YAFFS_MAX_ALIAS_LENGTH) +- return -ENAMETOOLONG; +- +- dev = yaffs_inode_to_obj(dir)->my_dev; +- yaffs_gross_lock(dev); +- obj = yaffs_create_symlink(yaffs_inode_to_obj(dir), dentry->d_name.name, +- S_IFLNK | S_IRWXUGO, uid, gid, symname); +- yaffs_gross_unlock(dev); +- +- if (obj) { +- struct inode *inode; +- +- inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj); +- d_instantiate(dentry, inode); +- update_dir_time(dir); +- yaffs_trace(YAFFS_TRACE_OS, "symlink created OK"); +- return 0; +- } else { +- yaffs_trace(YAFFS_TRACE_OS, "symlink not created"); +- } +- +- return -ENOMEM; +-} +- +-/* +- * The VFS layer already does all the dentry stuff for rename. +- * +- * NB: POSIX says you can rename an object over an old object of the same name +- */ +-static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry, +- struct inode *new_dir, struct dentry *new_dentry) +-{ +- struct yaffs_dev *dev; +- int ret_val = YAFFS_FAIL; +- struct yaffs_obj *target; +- +- yaffs_trace(YAFFS_TRACE_OS, "yaffs_rename"); +- dev = yaffs_inode_to_obj(old_dir)->my_dev; +- +- yaffs_gross_lock(dev); +- +- /* Check if the target is an existing directory that is not empty. */ +- target = yaffs_find_by_name(yaffs_inode_to_obj(new_dir), +- new_dentry->d_name.name); +- +- if (target && target->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY && +- !list_empty(&target->variant.dir_variant.children)) { +- +- yaffs_trace(YAFFS_TRACE_OS, "target is non-empty dir"); +- +- ret_val = YAFFS_FAIL; +- } else { +- /* Now does unlinking internally using shadowing mechanism */ +- yaffs_trace(YAFFS_TRACE_OS, "calling yaffs_rename_obj"); +- +- ret_val = yaffs_rename_obj(yaffs_inode_to_obj(old_dir), +- old_dentry->d_name.name, +- yaffs_inode_to_obj(new_dir), +- new_dentry->d_name.name); +- } +- yaffs_gross_unlock(dev); +- +- if (ret_val == YAFFS_OK) { +- if (target) +- inode_dec_link_count(new_dentry->d_inode); +- +- update_dir_time(old_dir); +- if (old_dir != new_dir) +- update_dir_time(new_dir); +- return 0; +- } else { +- return -ENOTEMPTY; +- } +-} +- +- +- +- +-static int yaffs_unlink(struct inode *dir, struct dentry *dentry) +-{ +- int ret_val; +- +- struct yaffs_dev *dev; +- struct yaffs_obj *obj; +- +- yaffs_trace(YAFFS_TRACE_OS, "yaffs_unlink %d:%s", +- (int)(dir->i_ino), dentry->d_name.name); +- obj = yaffs_inode_to_obj(dir); +- dev = obj->my_dev; +- +- yaffs_gross_lock(dev); +- +- ret_val = yaffs_unlinker(obj, dentry->d_name.name); +- +- if (ret_val == YAFFS_OK) { +- inode_dec_link_count(dentry->d_inode); +- dir->i_version++; +- yaffs_gross_unlock(dev); +- update_dir_time(dir); +- return 0; +- } +- yaffs_gross_unlock(dev); +- return -ENOTEMPTY; +-} +- +- +- +-static const struct inode_operations yaffs_dir_inode_operations = { +- .create = yaffs_create, +- .lookup = yaffs_lookup, +- .link = yaffs_link, +- .unlink = yaffs_unlink, +- .symlink = yaffs_symlink, +- .mkdir = yaffs_mkdir, +- .rmdir = yaffs_unlink, +- .mknod = yaffs_mknod, +- .rename = yaffs_rename, +- .setattr = yaffs_setattr, +- .setxattr = yaffs_setxattr, +- .getxattr = yaffs_getxattr, +- .listxattr = yaffs_listxattr, +- .removexattr = yaffs_removexattr, +-}; +- +-/*-----------------------------------------------------------------*/ +-/* Directory search context allows us to unlock access to yaffs during +- * filldir without causing problems with the directory being modified. +- * This is similar to the tried and tested mechanism used in yaffs direct. +- * +- * A search context iterates along a doubly linked list of siblings in the +- * directory. If the iterating object is deleted then this would corrupt +- * the list iteration, likely causing a crash. The search context avoids +- * this by using the remove_obj_fn to move the search context to the +- * next object before the object is deleted. +- * +- * Many readdirs (and thus seach conexts) may be alive simulateously so +- * each struct yaffs_dev has a list of these. +- * +- * A seach context lives for the duration of a readdir. +- * +- * All these functions must be called while yaffs is locked. +- */ +- +-struct yaffs_search_context { +- struct yaffs_dev *dev; +- struct yaffs_obj *dir_obj; +- struct yaffs_obj *next_return; +- struct list_head others; +-}; +- +-/* +- * yaffs_new_search() creates a new search context, initialises it and +- * adds it to the device's search context list. +- * +- * Called at start of readdir. +- */ +-static struct yaffs_search_context *yaffs_new_search(struct yaffs_obj *dir) +-{ +- struct yaffs_dev *dev = dir->my_dev; +- struct yaffs_search_context *sc = +- kmalloc(sizeof(struct yaffs_search_context), GFP_NOFS); +- if (sc) { +- sc->dir_obj = dir; +- sc->dev = dev; +- if (list_empty(&sc->dir_obj->variant.dir_variant.children)) +- sc->next_return = NULL; +- else +- sc->next_return = +- list_entry(dir->variant.dir_variant.children.next, +- struct yaffs_obj, siblings); +- INIT_LIST_HEAD(&sc->others); +- list_add(&sc->others, &(yaffs_dev_to_lc(dev)->search_contexts)); +- } +- return sc; +-} +- +-/* +- * yaffs_search_end() disposes of a search context and cleans up. +- */ +-static void yaffs_search_end(struct yaffs_search_context *sc) +-{ +- if (sc) { +- list_del(&sc->others); +- kfree(sc); +- } +-} +- +-/* +- * yaffs_search_advance() moves a search context to the next object. +- * Called when the search iterates or when an object removal causes +- * the search context to be moved to the next object. +- */ +-static void yaffs_search_advance(struct yaffs_search_context *sc) +-{ +- if (!sc) +- return; +- +- if (sc->next_return == NULL || +- list_empty(&sc->dir_obj->variant.dir_variant.children)) +- sc->next_return = NULL; +- else { +- struct list_head *next = sc->next_return->siblings.next; +- +- if (next == &sc->dir_obj->variant.dir_variant.children) +- sc->next_return = NULL; /* end of list */ +- else +- sc->next_return = +- list_entry(next, struct yaffs_obj, siblings); +- } +-} +- +-/* +- * yaffs_remove_obj_callback() is called when an object is unlinked. +- * We check open search contexts and advance any which are currently +- * on the object being iterated. +- */ +-static void yaffs_remove_obj_callback(struct yaffs_obj *obj) +-{ +- +- struct list_head *i; +- struct yaffs_search_context *sc; +- struct list_head *search_contexts = +- &(yaffs_dev_to_lc(obj->my_dev)->search_contexts); +- +- /* Iterate through the directory search contexts. +- * If any are currently on the object being removed, then advance +- * the search context to the next object to prevent a hanging pointer. +- */ +- list_for_each(i, search_contexts) { +- sc = list_entry(i, struct yaffs_search_context, others); +- if (sc->next_return == obj) +- yaffs_search_advance(sc); +- } +- +-} +- +- +-/*-----------------------------------------------------------------*/ +- +-static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) +-{ +- struct yaffs_obj *obj; +- struct yaffs_dev *dev; +- struct yaffs_search_context *sc; +- struct inode *inode = f->f_dentry->d_inode; +- unsigned long offset, curoffs; +- struct yaffs_obj *l; +- int ret_val = 0; +- +- char name[YAFFS_MAX_NAME_LENGTH + 1]; +- +- obj = yaffs_dentry_to_obj(f->f_dentry); +- dev = obj->my_dev; +- +- yaffs_gross_lock(dev); +- +- yaffs_dev_to_lc(dev)->readdir_process = current; +- +- offset = f->f_pos; +- +- sc = yaffs_new_search(obj); +- if (!sc) { +- ret_val = -ENOMEM; +- goto out; +- } +- +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_readdir: starting at %d", (int)offset); +- +- if (offset == 0) { +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_readdir: entry . ino %d", +- (int)inode->i_ino); +- yaffs_gross_unlock(dev); +- if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0) { +- yaffs_gross_lock(dev); +- goto out; +- } +- yaffs_gross_lock(dev); +- offset++; +- f->f_pos++; +- } +- if (offset == 1) { +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_readdir: entry .. ino %d", +- (int)f->f_dentry->d_parent->d_inode->i_ino); +- yaffs_gross_unlock(dev); +- if (filldir(dirent, "..", 2, offset, +- f->f_dentry->d_parent->d_inode->i_ino, +- DT_DIR) < 0) { +- yaffs_gross_lock(dev); +- goto out; +- } +- yaffs_gross_lock(dev); +- offset++; +- f->f_pos++; +- } +- +- curoffs = 1; +- +- /* If the directory has changed since the open or last call to +- readdir, rewind to after the 2 canned entries. */ +- if (f->f_version != inode->i_version) { +- offset = 2; +- f->f_pos = offset; +- f->f_version = inode->i_version; +- } +- +- while (sc->next_return) { +- curoffs++; +- l = sc->next_return; +- if (curoffs >= offset) { +- int this_inode = yaffs_get_obj_inode(l); +- int this_type = yaffs_get_obj_type(l); +- +- yaffs_get_obj_name(l, name, YAFFS_MAX_NAME_LENGTH + 1); +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_readdir: %s inode %d", +- name, yaffs_get_obj_inode(l)); +- +- yaffs_gross_unlock(dev); +- +- if (filldir(dirent, +- name, +- strlen(name), +- offset, this_inode, this_type) < 0) { +- yaffs_gross_lock(dev); +- goto out; +- } +- +- yaffs_gross_lock(dev); +- +- offset++; +- f->f_pos++; +- } +- yaffs_search_advance(sc); +- } +- +-out: +- yaffs_search_end(sc); +- yaffs_dev_to_lc(dev)->readdir_process = NULL; +- yaffs_gross_unlock(dev); +- +- return ret_val; +-} +- +-static const struct file_operations yaffs_dir_operations = { +- .read = generic_read_dir, +- .readdir = yaffs_readdir, +- .fsync = yaffs_sync_object, +- .llseek = generic_file_llseek, +-}; +- +-static void yaffs_fill_inode_from_obj(struct inode *inode, +- struct yaffs_obj *obj) +-{ +- if (inode && obj) { +- +- /* Check mode against the variant type and attempt to repair if broken. */ +- u32 mode = obj->yst_mode; +- switch (obj->variant_type) { +- case YAFFS_OBJECT_TYPE_FILE: +- if (!S_ISREG(mode)) { +- obj->yst_mode &= ~S_IFMT; +- obj->yst_mode |= S_IFREG; +- } +- +- break; +- case YAFFS_OBJECT_TYPE_SYMLINK: +- if (!S_ISLNK(mode)) { +- obj->yst_mode &= ~S_IFMT; +- obj->yst_mode |= S_IFLNK; +- } +- +- break; +- case YAFFS_OBJECT_TYPE_DIRECTORY: +- if (!S_ISDIR(mode)) { +- obj->yst_mode &= ~S_IFMT; +- obj->yst_mode |= S_IFDIR; +- } +- +- break; +- case YAFFS_OBJECT_TYPE_UNKNOWN: +- case YAFFS_OBJECT_TYPE_HARDLINK: +- case YAFFS_OBJECT_TYPE_SPECIAL: +- default: +- /* TODO? */ +- break; +- } +- +- inode->i_flags |= S_NOATIME; +- +- inode->i_ino = obj->obj_id; +- inode->i_mode = obj->yst_mode; +- inode->i_uid = obj->yst_uid; +- inode->i_gid = obj->yst_gid; +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) +- inode->i_blksize = inode->i_sb->s_blocksize; +-#endif +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) +- +- inode->i_rdev = old_decode_dev(obj->yst_rdev); +- inode->i_atime.tv_sec = (time_t) (obj->yst_atime); +- inode->i_atime.tv_nsec = 0; +- inode->i_mtime.tv_sec = (time_t) obj->yst_mtime; +- inode->i_mtime.tv_nsec = 0; +- inode->i_ctime.tv_sec = (time_t) obj->yst_ctime; +- inode->i_ctime.tv_nsec = 0; +-#else +- inode->i_rdev = obj->yst_rdev; +- inode->i_atime = obj->yst_atime; +- inode->i_mtime = obj->yst_mtime; +- inode->i_ctime = obj->yst_ctime; +-#endif +- inode->i_size = yaffs_get_obj_length(obj); +- inode->i_blocks = (inode->i_size + 511) >> 9; +- +- set_nlink(inode, yaffs_get_obj_link_count(obj)); +- +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_fill_inode mode %x uid %d gid %d size %lld count %d", +- inode->i_mode, inode->i_uid, inode->i_gid, +- inode->i_size, atomic_read(&inode->i_count)); +- +- switch (obj->yst_mode & S_IFMT) { +- default: /* fifo, device or socket */ +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) +- init_special_inode(inode, obj->yst_mode, +- old_decode_dev(obj->yst_rdev)); +-#else +- init_special_inode(inode, obj->yst_mode, +- (dev_t) (obj->yst_rdev)); +-#endif +- break; +- case S_IFREG: /* file */ +- inode->i_op = &yaffs_file_inode_operations; +- inode->i_fop = &yaffs_file_operations; +- inode->i_mapping->a_ops = +- &yaffs_file_address_operations; +- break; +- case S_IFDIR: /* directory */ +- inode->i_op = &yaffs_dir_inode_operations; +- inode->i_fop = &yaffs_dir_operations; +- break; +- case S_IFLNK: /* symlink */ +- inode->i_op = &yaffs_symlink_inode_operations; +- break; +- } +- +- yaffs_inode_to_obj_lv(inode) = obj; +- +- obj->my_inode = inode; +- +- } else { +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_fill_inode invalid parameters"); +- } +- +-} +- +- +- +-/* +- * yaffs background thread functions . +- * yaffs_bg_thread_fn() the thread function +- * yaffs_bg_start() launches the background thread. +- * yaffs_bg_stop() cleans up the background thread. +- * +- * NB: +- * The thread should only run after the yaffs is initialised +- * The thread should be stopped before yaffs is unmounted. +- * The thread should not do any writing while the fs is in read only. +- */ +- +-static unsigned yaffs_bg_gc_urgency(struct yaffs_dev *dev) +-{ +- unsigned erased_chunks = +- dev->n_erased_blocks * dev->param.chunks_per_block; +- struct yaffs_linux_context *context = yaffs_dev_to_lc(dev); +- unsigned scattered = 0; /* Free chunks not in an erased block */ +- +- if (erased_chunks < dev->n_free_chunks) +- scattered = (dev->n_free_chunks - erased_chunks); +- +- if (!context->bg_running) +- return 0; +- else if (scattered < (dev->param.chunks_per_block * 2)) +- return 0; +- else if (erased_chunks > dev->n_free_chunks / 2) +- return 0; +- else if (erased_chunks > dev->n_free_chunks / 4) +- return 1; +- else +- return 2; +-} +- +-#ifdef YAFFS_COMPILE_BACKGROUND +- +-void yaffs_background_waker(unsigned long data) +-{ +- wake_up_process((struct task_struct *)data); +-} +- +-static int yaffs_bg_thread_fn(void *data) +-{ +- struct yaffs_dev *dev = (struct yaffs_dev *)data; +- struct yaffs_linux_context *context = yaffs_dev_to_lc(dev); +- unsigned long now = jiffies; +- unsigned long next_dir_update = now; +- unsigned long next_gc = now; +- unsigned long expires; +- unsigned int urgency; +- +- int gc_result; +- struct timer_list timer; +- +- yaffs_trace(YAFFS_TRACE_BACKGROUND, +- "yaffs_background starting for dev %p", (void *)dev); +- +-#ifdef YAFFS_COMPILE_FREEZER +- set_freezable(); +-#endif +- while (context->bg_running) { +- yaffs_trace(YAFFS_TRACE_BACKGROUND, "yaffs_background"); +- +- if (kthread_should_stop()) +- break; +- +-#ifdef YAFFS_COMPILE_FREEZER +- if (try_to_freeze()) +- continue; +-#endif +- yaffs_gross_lock(dev); +- +- now = jiffies; +- +- if (time_after(now, next_dir_update) && yaffs_bg_enable) { +- yaffs_update_dirty_dirs(dev); +- next_dir_update = now + HZ; +- } +- +- if (time_after(now, next_gc) && yaffs_bg_enable) { +- if (!dev->is_checkpointed) { +- urgency = yaffs_bg_gc_urgency(dev); +- gc_result = yaffs_bg_gc(dev, urgency); +- if (urgency > 1) +- next_gc = now + HZ / 20 + 1; +- else if (urgency > 0) +- next_gc = now + HZ / 10 + 1; +- else +- next_gc = now + HZ * 2; +- } else { +- /* +- * gc not running so set to next_dir_update +- * to cut down on wake ups +- */ +- next_gc = next_dir_update; +- } +- } +- yaffs_gross_unlock(dev); +-#if 1 +- expires = next_dir_update; +- if (time_before(next_gc, expires)) +- expires = next_gc; +- if (time_before(expires, now)) +- expires = now + HZ; +- +- Y_INIT_TIMER(&timer); +- timer.expires = expires + 1; +- timer.data = (unsigned long)current; +- timer.function = yaffs_background_waker; +- +- set_current_state(TASK_INTERRUPTIBLE); +- add_timer(&timer); +- schedule(); +- del_timer_sync(&timer); +-#else +- msleep(10); +-#endif +- } +- +- return 0; +-} +- +-static int yaffs_bg_start(struct yaffs_dev *dev) +-{ +- int retval = 0; +- struct yaffs_linux_context *context = yaffs_dev_to_lc(dev); +- +- if (dev->read_only) +- return -1; +- +- context->bg_running = 1; +- +- context->bg_thread = kthread_run(yaffs_bg_thread_fn, +- (void *)dev, "yaffs-bg-%d", +- context->mount_id); +- +- if (IS_ERR(context->bg_thread)) { +- retval = PTR_ERR(context->bg_thread); +- context->bg_thread = NULL; +- context->bg_running = 0; +- } +- return retval; +-} +- +-static void yaffs_bg_stop(struct yaffs_dev *dev) +-{ +- struct yaffs_linux_context *ctxt = yaffs_dev_to_lc(dev); +- +- ctxt->bg_running = 0; +- +- if (ctxt->bg_thread) { +- kthread_stop(ctxt->bg_thread); +- ctxt->bg_thread = NULL; +- } +-} +-#else +-static int yaffs_bg_thread_fn(void *data) +-{ +- return 0; +-} +- +-static int yaffs_bg_start(struct yaffs_dev *dev) +-{ +- return 0; +-} +- +-static void yaffs_bg_stop(struct yaffs_dev *dev) +-{ +-} +-#endif +- +- +-static void yaffs_flush_inodes(struct super_block *sb) +-{ +- struct inode *iptr; +- struct yaffs_obj *obj; +- +- list_for_each_entry(iptr, &sb->s_inodes, i_sb_list) { +- obj = yaffs_inode_to_obj(iptr); +- if (obj) { +- yaffs_trace(YAFFS_TRACE_OS, +- "flushing obj %d", +- obj->obj_id); +- yaffs_flush_file(obj, 1, 0); +- } +- } +-} +- +-static void yaffs_flush_super(struct super_block *sb, int do_checkpoint) +-{ +- struct yaffs_dev *dev = yaffs_super_to_dev(sb); +- if (!dev) +- return; +- +- yaffs_flush_inodes(sb); +- yaffs_update_dirty_dirs(dev); +- yaffs_flush_whole_cache(dev); +- if (do_checkpoint) +- yaffs_checkpoint_save(dev); +-} +- +-static LIST_HEAD(yaffs_context_list); +-struct mutex yaffs_context_lock; +- +-static void yaffs_put_super(struct super_block *sb) +-{ +- struct yaffs_dev *dev = yaffs_super_to_dev(sb); +- struct mtd_info *mtd = yaffs_dev_to_mtd(dev); +- +- yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_ALWAYS, +- "yaffs_put_super"); +- +- yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND, +- "Shutting down yaffs background thread"); +- yaffs_bg_stop(dev); +- yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND, +- "yaffs background thread shut down"); +- +- yaffs_gross_lock(dev); +- +- yaffs_flush_super(sb, 1); +- +- yaffs_deinitialise(dev); +- +- yaffs_gross_unlock(dev); +- +- mutex_lock(&yaffs_context_lock); +- list_del_init(&(yaffs_dev_to_lc(dev)->context_list)); +- mutex_unlock(&yaffs_context_lock); +- +- if (yaffs_dev_to_lc(dev)->spare_buffer) { +- kfree(yaffs_dev_to_lc(dev)->spare_buffer); +- yaffs_dev_to_lc(dev)->spare_buffer = NULL; +- } +- +- kfree(dev); +- +- yaffs_put_mtd_device(mtd); +- +- yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_ALWAYS, +- "yaffs_put_super done"); +-} +- +- +-static unsigned yaffs_gc_control_callback(struct yaffs_dev *dev) +-{ +- return yaffs_gc_control; +-} +- +- +-#ifdef YAFFS_COMPILE_EXPORTFS +- +-static struct inode *yaffs2_nfs_get_inode(struct super_block *sb, uint64_t ino, +- uint32_t generation) +-{ +- return Y_IGET(sb, ino); +-} +- +-static struct dentry *yaffs2_fh_to_dentry(struct super_block *sb, +- struct fid *fid, int fh_len, +- int fh_type) +-{ +- return generic_fh_to_dentry(sb, fid, fh_len, fh_type, +- yaffs2_nfs_get_inode); +-} +- +-static struct dentry *yaffs2_fh_to_parent(struct super_block *sb, +- struct fid *fid, int fh_len, +- int fh_type) +-{ +- return generic_fh_to_parent(sb, fid, fh_len, fh_type, +- yaffs2_nfs_get_inode); +-} +- +-struct dentry *yaffs2_get_parent(struct dentry *dentry) +-{ +- +- struct super_block *sb = dentry->d_inode->i_sb; +- struct dentry *parent = ERR_PTR(-ENOENT); +- struct inode *inode; +- unsigned long parent_ino; +- struct yaffs_obj *d_obj; +- struct yaffs_obj *parent_obj; +- +- d_obj = yaffs_inode_to_obj(dentry->d_inode); +- +- if (d_obj) { +- parent_obj = d_obj->parent; +- if (parent_obj) { +- parent_ino = yaffs_get_obj_inode(parent_obj); +- inode = Y_IGET(sb, parent_ino); +- +- if (IS_ERR(inode)) { +- parent = ERR_CAST(inode); +- } else { +- parent = d_obtain_alias(inode); +- if (!IS_ERR(parent)) { +- parent = ERR_PTR(-ENOMEM); +- iput(inode); +- } +- } +- } +- } +- +- return parent; +-} +- +-/* Just declare a zero structure as a NULL value implies +- * using the default functions of exportfs. +- */ +- +-static struct export_operations yaffs_export_ops = { +- .fh_to_dentry = yaffs2_fh_to_dentry, +- .fh_to_parent = yaffs2_fh_to_parent, +- .get_parent = yaffs2_get_parent, +-}; +- +-#endif +- +-static void yaffs_unstitch_obj(struct inode *inode, struct yaffs_obj *obj) +-{ +- /* Clear the association between the inode and +- * the struct yaffs_obj. +- */ +- obj->my_inode = NULL; +- yaffs_inode_to_obj_lv(inode) = NULL; +- +- /* If the object freeing was deferred, then the real +- * free happens now. +- * This should fix the inode inconsistency problem. +- */ +- yaffs_handle_defered_free(obj); +-} +- +-#ifdef YAFFS_HAS_EVICT_INODE +-/* yaffs_evict_inode combines into one operation what was previously done in +- * yaffs_clear_inode() and yaffs_delete_inode() +- * +- */ +-static void yaffs_evict_inode(struct inode *inode) +-{ +- struct yaffs_obj *obj; +- struct yaffs_dev *dev; +- int deleteme = 0; +- +- obj = yaffs_inode_to_obj(inode); +- +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_evict_inode: ino %d, count %d %s", +- (int)inode->i_ino, atomic_read(&inode->i_count), +- obj ? "object exists" : "null object"); +- +- if (!inode->i_nlink && !is_bad_inode(inode)) +- deleteme = 1; +- truncate_inode_pages(&inode->i_data, 0); +- Y_CLEAR_INODE(inode); +- +- if (deleteme && obj) { +- dev = obj->my_dev; +- yaffs_gross_lock(dev); +- yaffs_del_obj(obj); +- yaffs_gross_unlock(dev); +- } +- if (obj) { +- dev = obj->my_dev; +- yaffs_gross_lock(dev); +- yaffs_unstitch_obj(inode, obj); +- yaffs_gross_unlock(dev); +- } +-} +-#else +- +-/* clear is called to tell the fs to release any per-inode data it holds. +- * The object might still exist on disk and is just being thrown out of the cache +- * or else the object has actually been deleted and we're being called via +- * the chain +- * yaffs_delete_inode() -> clear_inode()->yaffs_clear_inode() +- */ +- +-static void yaffs_clear_inode(struct inode *inode) +-{ +- struct yaffs_obj *obj; +- struct yaffs_dev *dev; +- +- obj = yaffs_inode_to_obj(inode); +- +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_clear_inode: ino %d, count %d %s", +- (int)inode->i_ino, atomic_read(&inode->i_count), +- obj ? "object exists" : "null object"); +- +- if (obj) { +- dev = obj->my_dev; +- yaffs_gross_lock(dev); +- yaffs_unstitch_obj(inode, obj); +- yaffs_gross_unlock(dev); +- } +- +-} +- +-/* delete is called when the link count is zero and the inode +- * is put (ie. nobody wants to know about it anymore, time to +- * delete the file). +- * NB Must call clear_inode() +- */ +-static void yaffs_delete_inode(struct inode *inode) +-{ +- struct yaffs_obj *obj = yaffs_inode_to_obj(inode); +- struct yaffs_dev *dev; +- +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_delete_inode: ino %d, count %d %s", +- (int)inode->i_ino, atomic_read(&inode->i_count), +- obj ? "object exists" : "null object"); +- +- if (obj) { +- dev = obj->my_dev; +- yaffs_gross_lock(dev); +- yaffs_del_obj(obj); +- yaffs_gross_unlock(dev); +- } +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) +- truncate_inode_pages(&inode->i_data, 0); +-#endif +- clear_inode(inode); +-} +-#endif +- +- +- +- +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) +-static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf) +-{ +- struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev; +- struct super_block *sb = dentry->d_sb; +-#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) +-static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf) +-{ +- struct yaffs_dev *dev = yaffs_super_to_dev(sb); +-#else +-static int yaffs_statfs(struct super_block *sb, struct statfs *buf) +-{ +- struct yaffs_dev *dev = yaffs_super_to_dev(sb); +-#endif +- +- yaffs_trace(YAFFS_TRACE_OS, "yaffs_statfs"); +- +- yaffs_gross_lock(dev); +- +- buf->f_type = YAFFS_MAGIC; +- buf->f_bsize = sb->s_blocksize; +- buf->f_namelen = 255; +- +- if (dev->data_bytes_per_chunk & (dev->data_bytes_per_chunk - 1)) { +- /* Do this if chunk size is not a power of 2 */ +- +- uint64_t bytes_in_dev; +- uint64_t bytes_free; +- +- bytes_in_dev = +- ((uint64_t) +- ((dev->param.end_block - dev->param.start_block + +- 1))) * ((uint64_t) (dev->param.chunks_per_block * +- dev->data_bytes_per_chunk)); +- +- do_div(bytes_in_dev, sb->s_blocksize); /* bytes_in_dev becomes the number of blocks */ +- buf->f_blocks = bytes_in_dev; +- +- bytes_free = ((uint64_t) (yaffs_get_n_free_chunks(dev))) * +- ((uint64_t) (dev->data_bytes_per_chunk)); +- +- do_div(bytes_free, sb->s_blocksize); +- +- buf->f_bfree = bytes_free; +- +- } else if (sb->s_blocksize > dev->data_bytes_per_chunk) { +- +- buf->f_blocks = +- (dev->param.end_block - dev->param.start_block + 1) * +- dev->param.chunks_per_block / +- (sb->s_blocksize / dev->data_bytes_per_chunk); +- buf->f_bfree = +- yaffs_get_n_free_chunks(dev) / +- (sb->s_blocksize / dev->data_bytes_per_chunk); +- } else { +- buf->f_blocks = +- (dev->param.end_block - dev->param.start_block + 1) * +- dev->param.chunks_per_block * +- (dev->data_bytes_per_chunk / sb->s_blocksize); +- +- buf->f_bfree = +- yaffs_get_n_free_chunks(dev) * +- (dev->data_bytes_per_chunk / sb->s_blocksize); +- } +- +- buf->f_files = 0; +- buf->f_ffree = 0; +- buf->f_bavail = buf->f_bfree; +- +- yaffs_gross_unlock(dev); +- return 0; +-} +- +- +- +-static int yaffs_do_sync_fs(struct super_block *sb, int request_checkpoint) +-{ +- +- struct yaffs_dev *dev = yaffs_super_to_dev(sb); +- unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4); +- unsigned gc_urgent = yaffs_bg_gc_urgency(dev); +- int do_checkpoint; +- int dirty = yaffs_check_super_dirty(dev); +- +- yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND, +- "yaffs_do_sync_fs: gc-urgency %d %s %s%s", +- gc_urgent, +- dirty ? "dirty" : "clean", +- request_checkpoint ? "checkpoint requested" : "no checkpoint", +- oneshot_checkpoint ? " one-shot" : ""); +- +- yaffs_gross_lock(dev); +- do_checkpoint = ((request_checkpoint && !gc_urgent) || +- oneshot_checkpoint) && !dev->is_checkpointed; +- +- if (dirty || do_checkpoint) { +- yaffs_flush_super(sb, !dev->is_checkpointed && do_checkpoint); +- yaffs_clear_super_dirty(dev); +- if (oneshot_checkpoint) +- yaffs_auto_checkpoint &= ~4; +- } +- yaffs_gross_unlock(dev); +- +- return 0; +-} +- +- +-#ifdef YAFFS_HAS_WRITE_SUPER +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) +-static void yaffs_write_super(struct super_block *sb) +-#else +-static int yaffs_write_super(struct super_block *sb) +-#endif +-{ +- unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2); +- +- yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND, +- "yaffs_write_super %s", +- request_checkpoint ? " checkpt" : ""); +- +- yaffs_do_sync_fs(sb, request_checkpoint); +- +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)) +- return 0; +-#endif +-} +-#endif +- +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) +-static int yaffs_sync_fs(struct super_block *sb, int wait) +-#else +-static int yaffs_sync_fs(struct super_block *sb) +-#endif +-{ +- unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1); +- +- yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, +- "yaffs_sync_fs%s", request_checkpoint ? " checkpt" : ""); +- +- yaffs_do_sync_fs(sb, request_checkpoint); +- +- return 0; +-} +- +- +- +-static const struct super_operations yaffs_super_ops = { +- .statfs = yaffs_statfs, +- +-#ifndef YAFFS_USE_OWN_IGET +- .read_inode = yaffs_read_inode, +-#endif +-#ifdef YAFFS_HAS_PUT_INODE +- .put_inode = yaffs_put_inode, +-#endif +- .put_super = yaffs_put_super, +-#ifdef YAFFS_HAS_EVICT_INODE +- .evict_inode = yaffs_evict_inode, +-#else +- .delete_inode = yaffs_delete_inode, +- .clear_inode = yaffs_clear_inode, +-#endif +- .sync_fs = yaffs_sync_fs, +-#ifdef YAFFS_HAS_WRITE_SUPER +- .write_super = yaffs_write_super, +-#endif +-}; +- +-struct yaffs_options { +- int inband_tags; +- int skip_checkpoint_read; +- int skip_checkpoint_write; +- int no_cache; +- int tags_ecc_on; +- int tags_ecc_overridden; +- int lazy_loading_enabled; +- int lazy_loading_overridden; +- int empty_lost_and_found; +- int empty_lost_and_found_overridden; +- int disable_summary; +-}; +- +-#define MAX_OPT_LEN 30 +-static int yaffs_parse_options(struct yaffs_options *options, +- const char *options_str) +-{ +- char cur_opt[MAX_OPT_LEN + 1]; +- int p; +- int error = 0; +- +- /* Parse through the options which is a comma seperated list */ +- +- while (options_str && *options_str && !error) { +- memset(cur_opt, 0, MAX_OPT_LEN + 1); +- p = 0; +- +- while (*options_str == ',') +- options_str++; +- +- while (*options_str && *options_str != ',') { +- if (p < MAX_OPT_LEN) { +- cur_opt[p] = *options_str; +- p++; +- } +- options_str++; +- } +- +- if (!strcmp(cur_opt, "inband-tags")) { +- options->inband_tags = 1; +- } else if (!strcmp(cur_opt, "tags-ecc-off")) { +- options->tags_ecc_on = 0; +- options->tags_ecc_overridden = 1; +- } else if (!strcmp(cur_opt, "tags-ecc-on")) { +- options->tags_ecc_on = 1; +- options->tags_ecc_overridden = 1; +- } else if (!strcmp(cur_opt, "lazy-loading-off")) { +- options->lazy_loading_enabled = 0; +- options->lazy_loading_overridden = 1; +- } else if (!strcmp(cur_opt, "lazy-loading-on")) { +- options->lazy_loading_enabled = 1; +- options->lazy_loading_overridden = 1; +- } else if (!strcmp(cur_opt, "disable-summary")) { +- options->disable_summary = 1; +- } else if (!strcmp(cur_opt, "empty-lost-and-found-off")) { +- options->empty_lost_and_found = 0; +- options->empty_lost_and_found_overridden = 1; +- } else if (!strcmp(cur_opt, "empty-lost-and-found-on")) { +- options->empty_lost_and_found = 1; +- options->empty_lost_and_found_overridden = 1; +- } else if (!strcmp(cur_opt, "no-cache")) { +- options->no_cache = 1; +- } else if (!strcmp(cur_opt, "no-checkpoint-read")) { +- options->skip_checkpoint_read = 1; +- } else if (!strcmp(cur_opt, "no-checkpoint-write")) { +- options->skip_checkpoint_write = 1; +- } else if (!strcmp(cur_opt, "no-checkpoint")) { +- options->skip_checkpoint_read = 1; +- options->skip_checkpoint_write = 1; +- } else { +- printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n", +- cur_opt); +- error = 1; +- } +- } +- +- return error; +-} +- +- +-static struct dentry *yaffs_make_root(struct inode *inode) +-{ +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) +- struct dentry *root = d_alloc_root(inode); +- +- if (!root) +- iput(inode); +- +- return root; +-#else +- return d_make_root(inode); +-#endif +-} +- +- +- +- +-static struct super_block *yaffs_internal_read_super(int yaffs_version, +- struct super_block *sb, +- void *data, int silent) +-{ +- int n_blocks; +- struct inode *inode = NULL; +- struct dentry *root; +- struct yaffs_dev *dev = 0; +- char devname_buf[BDEVNAME_SIZE + 1]; +- struct mtd_info *mtd; +- int err; +- char *data_str = (char *)data; +- struct yaffs_linux_context *context = NULL; +- struct yaffs_param *param; +- +- int read_only = 0; +- +- struct yaffs_options options; +- +- unsigned mount_id; +- int found; +- struct yaffs_linux_context *context_iterator; +- struct list_head *l; +- +- if (!sb) { +- printk(KERN_INFO "yaffs: sb is NULL\n"); +- return NULL; +- } +- +- sb->s_magic = YAFFS_MAGIC; +- sb->s_op = &yaffs_super_ops; +- sb->s_flags |= MS_NOATIME; +- +- read_only = ((sb->s_flags & MS_RDONLY) != 0); +- +-#ifdef YAFFS_COMPILE_EXPORTFS +- sb->s_export_op = &yaffs_export_ops; +-#endif +- +- if (!sb->s_dev) +- printk(KERN_INFO "yaffs: sb->s_dev is NULL\n"); +- else if (!yaffs_devname(sb, devname_buf)) +- printk(KERN_INFO "yaffs: devname is NULL\n"); +- else +- printk(KERN_INFO "yaffs: dev is %d name is \"%s\" %s\n", +- sb->s_dev, +- yaffs_devname(sb, devname_buf), read_only ? "ro" : "rw"); +- +- if (!data_str) +- data_str = ""; +- +- printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str); +- +- memset(&options, 0, sizeof(options)); +- +- if (yaffs_parse_options(&options, data_str)) { +- /* Option parsing failed */ +- return NULL; +- } +- +- sb->s_blocksize = PAGE_CACHE_SIZE; +- sb->s_blocksize_bits = PAGE_CACHE_SHIFT; +- +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_read_super: Using yaffs%d", yaffs_version); +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_read_super: block size %d", (int)(sb->s_blocksize)); +- +- yaffs_trace(YAFFS_TRACE_ALWAYS, +- "yaffs: Attempting MTD mount of %u.%u,\"%s\"", +- MAJOR(sb->s_dev), MINOR(sb->s_dev), +- yaffs_devname(sb, devname_buf)); +- +- /* Get the device */ +- mtd = get_mtd_device(NULL, MINOR(sb->s_dev)); +- if (!mtd) { +- yaffs_trace(YAFFS_TRACE_ALWAYS, +- "yaffs: MTD device %u either not valid or unavailable", +- MINOR(sb->s_dev)); +- return NULL; +- } +- +- if (yaffs_auto_select && yaffs_version == 1 && WRITE_SIZE(mtd) >= 2048) { +- yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs2"); +- yaffs_version = 2; +- } +- +- /* Added NCB 26/5/2006 for completeness */ +- if (yaffs_version == 2 && !options.inband_tags +- && WRITE_SIZE(mtd) == 512) { +- yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs1"); +- yaffs_version = 1; +- } +- +- if(yaffs_verify_mtd(mtd, yaffs_version, options.inband_tags) < 0) +- return NULL; +- +- /* OK, so if we got here, we have an MTD that's NAND and looks +- * like it has the right capabilities +- * Set the struct yaffs_dev up for mtd +- */ +- +- if (!read_only && !(mtd->flags & MTD_WRITEABLE)) { +- read_only = 1; +- printk(KERN_INFO +- "yaffs: mtd is read only, setting superblock read only\n" +- ); +- sb->s_flags |= MS_RDONLY; +- } +- +- dev = kmalloc(sizeof(struct yaffs_dev), GFP_KERNEL); +- context = kmalloc(sizeof(struct yaffs_linux_context), GFP_KERNEL); +- +- if (!dev || !context) { +- if (dev) +- kfree(dev); +- if (context) +- kfree(context); +- dev = NULL; +- context = NULL; +- } +- +- if (!dev) { +- /* Deep shit could not allocate device structure */ +- yaffs_trace(YAFFS_TRACE_ALWAYS, +- "yaffs_read_super: Failed trying to allocate struct yaffs_dev." +- ); +- return NULL; +- } +- memset(dev, 0, sizeof(struct yaffs_dev)); +- param = &(dev->param); +- +- memset(context, 0, sizeof(struct yaffs_linux_context)); +- dev->os_context = context; +- INIT_LIST_HEAD(&(context->context_list)); +- context->dev = dev; +- context->super = sb; +- +- dev->read_only = read_only; +- +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) +- sb->s_fs_info = dev; +-#else +- sb->u.generic_sbp = dev; +-#endif +- +- +- dev->driver_context = mtd; +- param->name = mtd->name; +- +- /* Set up the memory size parameters.... */ +- +- +- param->n_reserved_blocks = 5; +- param->n_caches = (options.no_cache) ? 0 : 10; +- param->inband_tags = options.inband_tags; +- +- param->enable_xattr = 1; +- if (options.lazy_loading_overridden) +- param->disable_lazy_load = !options.lazy_loading_enabled; +- +- param->defered_dir_update = 1; +- +- if (options.tags_ecc_overridden) +- param->no_tags_ecc = !options.tags_ecc_on; +- +- param->empty_lost_n_found = 1; +- param->refresh_period = 500; +- param->disable_summary = options.disable_summary; +- +- if (options.empty_lost_and_found_overridden) +- param->empty_lost_n_found = options.empty_lost_and_found; +- +- /* ... and the functions. */ +- if (yaffs_version == 2) { +- param->is_yaffs2 = 1; +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) +- param->total_bytes_per_chunk = mtd->writesize; +- param->chunks_per_block = mtd->erasesize / mtd->writesize; +-#else +- param->total_bytes_per_chunk = mtd->oobblock; +- param->chunks_per_block = mtd->erasesize / mtd->oobblock; +-#endif +- n_blocks = YCALCBLOCKS(mtd->size, mtd->erasesize); +- +- param->start_block = 0; +- param->end_block = n_blocks - 1; +- } else { +- param->is_yaffs2 = 0; +- n_blocks = YCALCBLOCKS(mtd->size, +- YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK); +- +- param->chunks_per_block = YAFFS_CHUNKS_PER_BLOCK; +- param->total_bytes_per_chunk = YAFFS_BYTES_PER_CHUNK; +- } +- +- param->start_block = 0; +- param->end_block = n_blocks - 1; +- +- yaffs_mtd_drv_install(dev); +- +- param->sb_dirty_fn = yaffs_set_super_dirty; +- param->gc_control_fn = yaffs_gc_control_callback; +- +- yaffs_dev_to_lc(dev)->super = sb; +- +- param->use_nand_ecc = 1; +- +- param->skip_checkpt_rd = options.skip_checkpoint_read; +- param->skip_checkpt_wr = options.skip_checkpoint_write; +- +- mutex_lock(&yaffs_context_lock); +- /* Get a mount id */ +- found = 0; +- for (mount_id = 0; !found; mount_id++) { +- found = 1; +- list_for_each(l, &yaffs_context_list) { +- context_iterator = +- list_entry(l, struct yaffs_linux_context, +- context_list); +- if (context_iterator->mount_id == mount_id) +- found = 0; +- } +- } +- context->mount_id = mount_id; +- +- list_add_tail(&(yaffs_dev_to_lc(dev)->context_list), +- &yaffs_context_list); +- mutex_unlock(&yaffs_context_lock); +- +- /* Directory search handling... */ +- INIT_LIST_HEAD(&(yaffs_dev_to_lc(dev)->search_contexts)); +- param->remove_obj_fn = yaffs_remove_obj_callback; +- +- mutex_init(&(yaffs_dev_to_lc(dev)->gross_lock)); +- +- yaffs_gross_lock(dev); +- +- err = yaffs_guts_initialise(dev); +- +- yaffs_trace(YAFFS_TRACE_OS, +- "yaffs_read_super: guts initialised %s", +- (err == YAFFS_OK) ? "OK" : "FAILED"); +- +- if (err == YAFFS_OK) +- yaffs_bg_start(dev); +- +- if (!context->bg_thread) +- param->defered_dir_update = 0; +- +- sb->s_maxbytes = yaffs_max_file_size(dev); +- +- /* Release lock before yaffs_get_inode() */ +- yaffs_gross_unlock(dev); +- +- /* Create root inode */ +- if (err == YAFFS_OK) +- inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0, yaffs_root(dev)); +- +- if (!inode) +- return NULL; +- +- inode->i_op = &yaffs_dir_inode_operations; +- inode->i_fop = &yaffs_dir_operations; +- +- yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: got root inode"); +- +- root = yaffs_make_root(inode); +- +- if (!root) +- return NULL; +- +- sb->s_root = root; +- if(!dev->is_checkpointed) +- yaffs_set_super_dirty(dev); +- +- yaffs_trace(YAFFS_TRACE_ALWAYS, +- "yaffs_read_super: is_checkpointed %d", +- dev->is_checkpointed); +- +- yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: done"); +- return sb; +-} +- +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) +-static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data, +- int silent) +-{ +- return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL; +-} +- +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) +-static struct dentry *yaffs_mount(struct file_system_type *fs_type, int flags, +- const char *dev_name, void *data) +-{ +- return mount_bdev(fs_type, flags, dev_name, data, yaffs_internal_read_super_mtd); +-} +-#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) +-static int yaffs_read_super(struct file_system_type *fs, +- int flags, const char *dev_name, +- void *data, struct vfsmount *mnt) +-{ +- +- return get_sb_bdev(fs, flags, dev_name, data, +- yaffs_internal_read_super_mtd, mnt); +-} +-#else +-static struct super_block *yaffs_read_super(struct file_system_type *fs, +- int flags, const char *dev_name, +- void *data) +-{ +- +- return get_sb_bdev(fs, flags, dev_name, data, +- yaffs_internal_read_super_mtd); +-} +-#endif +- +-static struct file_system_type yaffs_fs_type = { +- .owner = THIS_MODULE, +- .name = "yaffs", +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) +- .mount = yaffs_mount, +-#else +- .get_sb = yaffs_read_super, +-#endif +- .kill_sb = kill_block_super, +- .fs_flags = FS_REQUIRES_DEV, +-}; +-#else +-static struct super_block *yaffs_read_super(struct super_block *sb, void *data, +- int silent) +-{ +- return yaffs_internal_read_super(1, sb, data, silent); +-} +- +-static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super, +- FS_REQUIRES_DEV); +-#endif +- +- +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) +-static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data, +- int silent) +-{ +- return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL; +-} +- +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) +-static struct dentry *yaffs2_mount(struct file_system_type *fs_type, int flags, +- const char *dev_name, void *data) +-{ +- return mount_bdev(fs_type, flags, dev_name, data, yaffs2_internal_read_super_mtd); +-} +-#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) +-static int yaffs2_read_super(struct file_system_type *fs, +- int flags, const char *dev_name, void *data, +- struct vfsmount *mnt) +-{ +- return get_sb_bdev(fs, flags, dev_name, data, +- yaffs2_internal_read_super_mtd, mnt); +-} +-#else +-static struct super_block *yaffs2_read_super(struct file_system_type *fs, +- int flags, const char *dev_name, +- void *data) +-{ +- +- return get_sb_bdev(fs, flags, dev_name, data, +- yaffs2_internal_read_super_mtd); +-} +-#endif +- +-static struct file_system_type yaffs2_fs_type = { +- .owner = THIS_MODULE, +- .name = "yaffs2", +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) +- .mount = yaffs2_mount, +-#else +- .get_sb = yaffs2_read_super, +-#endif +- .kill_sb = kill_block_super, +- .fs_flags = FS_REQUIRES_DEV, +-}; +-#else +-static struct super_block *yaffs2_read_super(struct super_block *sb, +- void *data, int silent) +-{ +- return yaffs_internal_read_super(2, sb, data, silent); +-} +- +-static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super, +- FS_REQUIRES_DEV); +-#endif +- +- +-static struct proc_dir_entry *my_proc_entry; +- +-static char *yaffs_dump_dev_part0(char *buf, struct yaffs_dev *dev) +-{ +- struct yaffs_param *param = &dev->param; +- +- buf += sprintf(buf, "start_block.......... %d\n", param->start_block); +- buf += sprintf(buf, "end_block............ %d\n", param->end_block); +- buf += sprintf(buf, "total_bytes_per_chunk %d\n", +- param->total_bytes_per_chunk); +- buf += sprintf(buf, "use_nand_ecc......... %d\n", param->use_nand_ecc); +- buf += sprintf(buf, "no_tags_ecc.......... %d\n", param->no_tags_ecc); +- buf += sprintf(buf, "is_yaffs2............ %d\n", param->is_yaffs2); +- buf += sprintf(buf, "inband_tags.......... %d\n", param->inband_tags); +- buf += sprintf(buf, "empty_lost_n_found... %d\n", +- param->empty_lost_n_found); +- buf += sprintf(buf, "disable_lazy_load.... %d\n", +- param->disable_lazy_load); +- buf += sprintf(buf, "refresh_period....... %d\n", +- param->refresh_period); +- buf += sprintf(buf, "n_caches............. %d\n", param->n_caches); +- buf += sprintf(buf, "n_reserved_blocks.... %d\n", +- param->n_reserved_blocks); +- buf += sprintf(buf, "always_check_erased.. %d\n", +- param->always_check_erased); +- buf += sprintf(buf, "\n"); +- +- return buf; +-} +- +-static char *yaffs_dump_dev_part1(char *buf, struct yaffs_dev *dev) +-{ +- buf += sprintf(buf, "max file size....... %lld\n", +- (long long) yaffs_max_file_size(dev)); +- buf += sprintf(buf, "data_bytes_per_chunk. %d\n", +- dev->data_bytes_per_chunk); +- buf += sprintf(buf, "chunk_grp_bits....... %d\n", dev->chunk_grp_bits); +- buf += sprintf(buf, "chunk_grp_size....... %d\n", dev->chunk_grp_size); +- buf += sprintf(buf, "n_erased_blocks...... %d\n", dev->n_erased_blocks); +- buf += sprintf(buf, "blocks_in_checkpt.... %d\n", +- dev->blocks_in_checkpt); +- buf += sprintf(buf, "\n"); +- buf += sprintf(buf, "n_tnodes............. %d\n", dev->n_tnodes); +- buf += sprintf(buf, "n_obj................ %d\n", dev->n_obj); +- buf += sprintf(buf, "n_free_chunks........ %d\n", dev->n_free_chunks); +- buf += sprintf(buf, "\n"); +- buf += sprintf(buf, "n_page_writes........ %u\n", dev->n_page_writes); +- buf += sprintf(buf, "n_page_reads......... %u\n", dev->n_page_reads); +- buf += sprintf(buf, "n_erasures........... %u\n", dev->n_erasures); +- buf += sprintf(buf, "n_gc_copies.......... %u\n", dev->n_gc_copies); +- buf += sprintf(buf, "all_gcs.............. %u\n", dev->all_gcs); +- buf += sprintf(buf, "passive_gc_count..... %u\n", +- dev->passive_gc_count); +- buf += sprintf(buf, "oldest_dirty_gc_count %u\n", +- dev->oldest_dirty_gc_count); +- buf += sprintf(buf, "n_gc_blocks.......... %u\n", dev->n_gc_blocks); +- buf += sprintf(buf, "bg_gcs............... %u\n", dev->bg_gcs); +- buf += sprintf(buf, "n_retried_writes..... %u\n", +- dev->n_retried_writes); +- buf += sprintf(buf, "n_retired_blocks..... %u\n", +- dev->n_retired_blocks); +- buf += sprintf(buf, "n_ecc_fixed.......... %u\n", dev->n_ecc_fixed); +- buf += sprintf(buf, "n_ecc_unfixed........ %u\n", dev->n_ecc_unfixed); +- buf += sprintf(buf, "n_tags_ecc_fixed..... %u\n", +- dev->n_tags_ecc_fixed); +- buf += sprintf(buf, "n_tags_ecc_unfixed... %u\n", +- dev->n_tags_ecc_unfixed); +- buf += sprintf(buf, "cache_hits........... %u\n", dev->cache_hits); +- buf += sprintf(buf, "n_deleted_files...... %u\n", dev->n_deleted_files); +- buf += sprintf(buf, "n_unlinked_files..... %u\n", +- dev->n_unlinked_files); +- buf += sprintf(buf, "refresh_count........ %u\n", dev->refresh_count); +- buf += sprintf(buf, "n_bg_deletions....... %u\n", dev->n_bg_deletions); +- buf += sprintf(buf, "tags_used............ %u\n", dev->tags_used); +- buf += sprintf(buf, "summary_used......... %u\n", dev->summary_used); +- +- return buf; +-} +- +-static int yaffs_proc_read(char *page, +- char **start, +- off_t offset, int count, int *eof, void *data) +-{ +- struct list_head *item; +- char *buf = page; +- int step = offset; +- int n = 0; +- +- /* Get proc_file_read() to step 'offset' by one on each sucessive call. +- * We use 'offset' (*ppos) to indicate where we are in dev_list. +- * This also assumes the user has posted a read buffer large +- * enough to hold the complete output; but that's life in /proc. +- */ +- +- *(int *)start = 1; +- +- /* Print header first */ +- if (step == 0) +- buf += +- sprintf(buf, +- "Multi-version YAFFS built:" __DATE__ " " __TIME__ +- "\n"); +- else if (step == 1) +- buf += sprintf(buf, "\n"); +- else { +- step -= 2; +- +- mutex_lock(&yaffs_context_lock); +- +- /* Locate and print the Nth entry. Order N-squared but N is small. */ +- list_for_each(item, &yaffs_context_list) { +- struct yaffs_linux_context *dc = +- list_entry(item, struct yaffs_linux_context, +- context_list); +- struct yaffs_dev *dev = dc->dev; +- +- if (n < (step & ~1)) { +- n += 2; +- continue; +- } +- if ((step & 1) == 0) { +- buf += +- sprintf(buf, "\nDevice %d \"%s\"\n", n, +- dev->param.name); +- buf = yaffs_dump_dev_part0(buf, dev); +- } else { +- buf = yaffs_dump_dev_part1(buf, dev); +- } +- +- break; +- } +- mutex_unlock(&yaffs_context_lock); +- } +- +- return buf - page < count ? buf - page : count; +-} +- +-/** +- * Set the verbosity of the warnings and error messages. +- * +- * Note that the names can only be a..z or _ with the current code. +- */ +- +-static struct { +- char *mask_name; +- unsigned mask_bitfield; +-} mask_flags[] = { +- {"allocate", YAFFS_TRACE_ALLOCATE}, +- {"always", YAFFS_TRACE_ALWAYS}, +- {"background", YAFFS_TRACE_BACKGROUND}, +- {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS}, +- {"buffers", YAFFS_TRACE_BUFFERS}, +- {"bug", YAFFS_TRACE_BUG}, +- {"checkpt", YAFFS_TRACE_CHECKPOINT}, +- {"deletion", YAFFS_TRACE_DELETION}, +- {"erase", YAFFS_TRACE_ERASE}, +- {"error", YAFFS_TRACE_ERROR}, +- {"gc_detail", YAFFS_TRACE_GC_DETAIL}, +- {"gc", YAFFS_TRACE_GC}, +- {"lock", YAFFS_TRACE_LOCK}, +- {"mtd", YAFFS_TRACE_MTD}, +- {"nandaccess", YAFFS_TRACE_NANDACCESS}, +- {"os", YAFFS_TRACE_OS}, +- {"scan_debug", YAFFS_TRACE_SCAN_DEBUG}, +- {"scan", YAFFS_TRACE_SCAN}, +- {"mount", YAFFS_TRACE_MOUNT}, +- {"tracing", YAFFS_TRACE_TRACING}, +- {"sync", YAFFS_TRACE_SYNC}, +- {"write", YAFFS_TRACE_WRITE}, +- {"verify", YAFFS_TRACE_VERIFY}, +- {"verify_nand", YAFFS_TRACE_VERIFY_NAND}, +- {"verify_full", YAFFS_TRACE_VERIFY_FULL}, +- {"verify_all", YAFFS_TRACE_VERIFY_ALL}, +- {"all", 0xffffffff}, +- {"none", 0}, +- {NULL, 0}, +-}; +- +-#define MAX_MASK_NAME_LENGTH 40 +-static int yaffs_proc_write_trace_options(struct file *file, const char *buf, +- unsigned long count, void *data) +-{ +- unsigned rg = 0, mask_bitfield; +- char *end; +- char *mask_name; +- const char *x; +- char substring[MAX_MASK_NAME_LENGTH + 1]; +- int i; +- int done = 0; +- int add, len = 0; +- int pos = 0; +- +- rg = yaffs_trace_mask; +- +- while (!done && (pos < count)) { +- done = 1; +- while ((pos < count) && isspace(buf[pos])) +- pos++; +- +- switch (buf[pos]) { +- case '+': +- case '-': +- case '=': +- add = buf[pos]; +- pos++; +- break; +- +- default: +- add = ' '; +- break; +- } +- mask_name = NULL; +- +- mask_bitfield = simple_strtoul(buf + pos, &end, 0); +- +- if (end > buf + pos) { +- mask_name = "numeral"; +- len = end - (buf + pos); +- pos += len; +- done = 0; +- } else { +- for (x = buf + pos, i = 0; +- (*x == '_' || (*x >= 'a' && *x <= 'z')) && +- i < MAX_MASK_NAME_LENGTH; x++, i++, pos++) +- substring[i] = *x; +- substring[i] = '\0'; +- +- for (i = 0; mask_flags[i].mask_name != NULL; i++) { +- if (strcmp(substring, mask_flags[i].mask_name) +- == 0) { +- mask_name = mask_flags[i].mask_name; +- mask_bitfield = +- mask_flags[i].mask_bitfield; +- done = 0; +- break; +- } +- } +- } +- +- if (mask_name != NULL) { +- done = 0; +- switch (add) { +- case '-': +- rg &= ~mask_bitfield; +- break; +- case '+': +- rg |= mask_bitfield; +- break; +- case '=': +- rg = mask_bitfield; +- break; +- default: +- rg |= mask_bitfield; +- break; +- } +- } +- } +- +- yaffs_trace_mask = rg | YAFFS_TRACE_ALWAYS; +- +- printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_trace_mask); +- +- if (rg & YAFFS_TRACE_ALWAYS) { +- for (i = 0; mask_flags[i].mask_name != NULL; i++) { +- char flag; +- flag = ((rg & mask_flags[i].mask_bitfield) == +- mask_flags[i].mask_bitfield) ? '+' : '-'; +- printk(KERN_DEBUG "%c%s\n", flag, +- mask_flags[i].mask_name); +- } +- } +- +- return count; +-} +- +-static int yaffs_proc_write(struct file *file, const char *buf, +- unsigned long count, void *data) +-{ +- return yaffs_proc_write_trace_options(file, buf, count, data); +-} +- +-/* Stuff to handle installation of file systems */ +-struct file_system_to_install { +- struct file_system_type *fst; +- int installed; +-}; +- +-static struct file_system_to_install fs_to_install[] = { +- {&yaffs_fs_type, 0}, +- {&yaffs2_fs_type, 0}, +- {NULL, 0} +-}; +- +-static int __init init_yaffs_fs(void) +-{ +- int error = 0; +- struct file_system_to_install *fsinst; +- +- yaffs_trace(YAFFS_TRACE_ALWAYS, +- "yaffs built " __DATE__ " " __TIME__ " Installing."); +- +- mutex_init(&yaffs_context_lock); +- +- /* Install the proc_fs entries */ +- my_proc_entry = create_proc_entry("yaffs", +- S_IRUGO | S_IFREG, YPROC_ROOT); +- +- if (my_proc_entry) { +- my_proc_entry->write_proc = yaffs_proc_write; +- my_proc_entry->read_proc = yaffs_proc_read; +- my_proc_entry->data = NULL; +- } else { +- return -ENOMEM; +- } +- +- /* Now add the file system entries */ +- +- fsinst = fs_to_install; +- +- while (fsinst->fst && !error) { +- error = register_filesystem(fsinst->fst); +- if (!error) +- fsinst->installed = 1; +- fsinst++; +- } +- +- /* Any errors? uninstall */ +- if (error) { +- fsinst = fs_to_install; +- +- while (fsinst->fst) { +- if (fsinst->installed) { +- unregister_filesystem(fsinst->fst); +- fsinst->installed = 0; +- } +- fsinst++; +- } +- } +- +- return error; +-} +- +-static void __exit exit_yaffs_fs(void) +-{ +- +- struct file_system_to_install *fsinst; +- +- yaffs_trace(YAFFS_TRACE_ALWAYS, +- "yaffs built " __DATE__ " " __TIME__ " removing."); +- +- remove_proc_entry("yaffs", YPROC_ROOT); +- +- fsinst = fs_to_install; +- +- while (fsinst->fst) { +- if (fsinst->installed) { +- unregister_filesystem(fsinst->fst); +- fsinst->installed = 0; +- } +- fsinst++; +- } +-} +- +-module_init(init_yaffs_fs) +- module_exit(exit_yaffs_fs) +- +- MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system"); +-MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2011"); +-MODULE_LICENSE("GPL"); +diff --git a/fs/yaffs2/yaffs_yaffs1.c b/fs/yaffs2/yaffs_yaffs1.c +deleted file mode 100644 +index d277e20..0000000 +--- a/fs/yaffs2/yaffs_yaffs1.c ++++ /dev/null +@@ -1,422 +0,0 @@ +-/* +- * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * 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 "yaffs_yaffs1.h" +-#include "yportenv.h" +-#include "yaffs_trace.h" +-#include "yaffs_bitmap.h" +-#include "yaffs_getblockinfo.h" +-#include "yaffs_nand.h" +-#include "yaffs_attribs.h" +- +-int yaffs1_scan(struct yaffs_dev *dev) +-{ +- struct yaffs_ext_tags tags; +- int blk; +- int result; +- int chunk; +- int c; +- int deleted; +- enum yaffs_block_state state; +- LIST_HEAD(hard_list); +- struct yaffs_block_info *bi; +- u32 seq_number; +- struct yaffs_obj_hdr *oh; +- struct yaffs_obj *in; +- struct yaffs_obj *parent; +- int alloc_failed = 0; +- struct yaffs_shadow_fixer *shadow_fixers = NULL; +- u8 *chunk_data; +- +- yaffs_trace(YAFFS_TRACE_SCAN, +- "yaffs1_scan starts intstartblk %d intendblk %d...", +- dev->internal_start_block, dev->internal_end_block); +- +- chunk_data = yaffs_get_temp_buffer(dev); +- +- dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER; +- +- /* Scan all the blocks to determine their state */ +- bi = dev->block_info; +- for (blk = dev->internal_start_block; blk <= dev->internal_end_block; +- blk++) { +- yaffs_clear_chunk_bits(dev, blk); +- bi->pages_in_use = 0; +- bi->soft_del_pages = 0; +- +- yaffs_query_init_block_state(dev, blk, &state, &seq_number); +- +- bi->block_state = state; +- bi->seq_number = seq_number; +- +- if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK) +- bi->block_state = state = YAFFS_BLOCK_STATE_DEAD; +- +- yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, +- "Block scanning block %d state %d seq %d", +- blk, state, seq_number); +- +- if (state == YAFFS_BLOCK_STATE_DEAD) { +- yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, +- "block %d is bad", blk); +- } else if (state == YAFFS_BLOCK_STATE_EMPTY) { +- yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty "); +- dev->n_erased_blocks++; +- dev->n_free_chunks += dev->param.chunks_per_block; +- } +- bi++; +- } +- +- /* For each block.... */ +- for (blk = dev->internal_start_block; +- !alloc_failed && blk <= dev->internal_end_block; blk++) { +- +- cond_resched(); +- +- bi = yaffs_get_block_info(dev, blk); +- state = bi->block_state; +- +- deleted = 0; +- +- /* For each chunk in each block that needs scanning.... */ +- for (c = 0; +- !alloc_failed && c < dev->param.chunks_per_block && +- state == YAFFS_BLOCK_STATE_NEEDS_SCAN; c++) { +- /* Read the tags and decide what to do */ +- chunk = blk * dev->param.chunks_per_block + c; +- +- result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL, +- &tags); +- +- /* Let's have a good look at this chunk... */ +- +- if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED || +- tags.is_deleted) { +- /* YAFFS1 only... +- * A deleted chunk +- */ +- deleted++; +- dev->n_free_chunks++; +- } else if (!tags.chunk_used) { +- /* An unassigned chunk in the block +- * This means that either the block is empty or +- * this is the one being allocated from +- */ +- +- if (c == 0) { +- /* We're looking at the first chunk in +- *the block so the block is unused */ +- state = YAFFS_BLOCK_STATE_EMPTY; +- dev->n_erased_blocks++; +- } else { +- /* this is the block being allocated */ +- yaffs_trace(YAFFS_TRACE_SCAN, +- " Allocating from %d %d", +- blk, c); +- state = YAFFS_BLOCK_STATE_ALLOCATING; +- dev->alloc_block = blk; +- dev->alloc_page = c; +- dev->alloc_block_finder = blk; +- +- } +- +- dev->n_free_chunks += +- (dev->param.chunks_per_block - c); +- } else if (tags.chunk_id > 0) { +- /* chunk_id > 0 so it is a data chunk... */ +- unsigned int endpos; +- +- yaffs_set_chunk_bit(dev, blk, c); +- bi->pages_in_use++; +- +- in = yaffs_find_or_create_by_number(dev, +- tags.obj_id, +- YAFFS_OBJECT_TYPE_FILE); +- /* PutChunkIntoFile checks for a clash +- * (two data chunks with the same chunk_id). +- */ +- +- if (!in) +- alloc_failed = 1; +- +- if (in) { +- if (!yaffs_put_chunk_in_file +- (in, tags.chunk_id, chunk, 1)) +- alloc_failed = 1; +- } +- +- endpos = +- (tags.chunk_id - 1) * +- dev->data_bytes_per_chunk + +- tags.n_bytes; +- if (in && +- in->variant_type == +- YAFFS_OBJECT_TYPE_FILE && +- in->variant.file_variant.scanned_size < +- endpos) { +- in->variant.file_variant.scanned_size = +- endpos; +- if (!dev->param.use_header_file_size) { +- in->variant. +- file_variant.file_size = +- in->variant. +- file_variant.scanned_size; +- } +- +- } +- } else { +- /* chunk_id == 0, so it is an ObjectHeader. +- * Make the object +- */ +- yaffs_set_chunk_bit(dev, blk, c); +- bi->pages_in_use++; +- +- result = yaffs_rd_chunk_tags_nand(dev, chunk, +- chunk_data, +- NULL); +- +- oh = (struct yaffs_obj_hdr *)chunk_data; +- +- in = yaffs_find_by_number(dev, tags.obj_id); +- if (in && in->variant_type != oh->type) { +- /* This should not happen, but somehow +- * Wev'e ended up with an obj_id that +- * has been reused but not yet deleted, +- * and worse still it has changed type. +- * Delete the old object. +- */ +- +- yaffs_del_obj(in); +- in = NULL; +- } +- +- in = yaffs_find_or_create_by_number(dev, +- tags.obj_id, +- oh->type); +- +- if (!in) +- alloc_failed = 1; +- +- if (in && oh->shadows_obj > 0) { +- +- struct yaffs_shadow_fixer *fixer; +- fixer = +- kmalloc(sizeof +- (struct yaffs_shadow_fixer), +- GFP_NOFS); +- if (fixer) { +- fixer->next = shadow_fixers; +- shadow_fixers = fixer; +- fixer->obj_id = tags.obj_id; +- fixer->shadowed_id = +- oh->shadows_obj; +- yaffs_trace(YAFFS_TRACE_SCAN, +- " Shadow fixer: %d shadows %d", +- fixer->obj_id, +- fixer->shadowed_id); +- +- } +- +- } +- +- if (in && in->valid) { +- /* We have already filled this one. +- * We have a duplicate and need to +- * resolve it. */ +- +- unsigned existing_serial = in->serial; +- unsigned new_serial = +- tags.serial_number; +- +- if (((existing_serial + 1) & 3) == +- new_serial) { +- /* Use new one - destroy the +- * exisiting one */ +- yaffs_chunk_del(dev, +- in->hdr_chunk, +- 1, __LINE__); +- in->valid = 0; +- } else { +- /* Use existing - destroy +- * this one. */ +- yaffs_chunk_del(dev, chunk, 1, +- __LINE__); +- } +- } +- +- if (in && !in->valid && +- (tags.obj_id == YAFFS_OBJECTID_ROOT || +- tags.obj_id == +- YAFFS_OBJECTID_LOSTNFOUND)) { +- /* We only load some info, don't fiddle +- * with directory structure */ +- in->valid = 1; +- in->variant_type = oh->type; +- +- in->yst_mode = oh->yst_mode; +- yaffs_load_attribs(in, oh); +- in->hdr_chunk = chunk; +- in->serial = tags.serial_number; +- +- } else if (in && !in->valid) { +- /* we need to load this info */ +- +- in->valid = 1; +- in->variant_type = oh->type; +- +- in->yst_mode = oh->yst_mode; +- yaffs_load_attribs(in, oh); +- in->hdr_chunk = chunk; +- in->serial = tags.serial_number; +- +- yaffs_set_obj_name_from_oh(in, oh); +- in->dirty = 0; +- +- /* directory stuff... +- * hook up to parent +- */ +- +- parent = +- yaffs_find_or_create_by_number +- (dev, oh->parent_obj_id, +- YAFFS_OBJECT_TYPE_DIRECTORY); +- if (!parent) +- alloc_failed = 1; +- if (parent && parent->variant_type == +- YAFFS_OBJECT_TYPE_UNKNOWN) { +- /* Set up as a directory */ +- parent->variant_type = +- YAFFS_OBJECT_TYPE_DIRECTORY; +- INIT_LIST_HEAD(&parent-> +- variant.dir_variant. +- children); +- } else if (!parent || +- parent->variant_type != +- YAFFS_OBJECT_TYPE_DIRECTORY) { +- /* Hoosterman, a problem.... +- * We're trying to use a +- * non-directory as a directory +- */ +- +- yaffs_trace(YAFFS_TRACE_ERROR, +- "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." +- ); +- parent = dev->lost_n_found; +- } +- +- yaffs_add_obj_to_dir(parent, in); +- +- switch (in->variant_type) { +- case YAFFS_OBJECT_TYPE_UNKNOWN: +- /* Todo got a problem */ +- break; +- case YAFFS_OBJECT_TYPE_FILE: +- if (dev->param. +- use_header_file_size) +- in->variant. +- file_variant.file_size +- = yaffs_oh_to_size(oh); +- break; +- case YAFFS_OBJECT_TYPE_HARDLINK: +- in->variant. +- hardlink_variant.equiv_id = +- oh->equiv_id; +- list_add(&in->hard_links, +- &hard_list); +- break; +- case YAFFS_OBJECT_TYPE_DIRECTORY: +- /* Do nothing */ +- break; +- case YAFFS_OBJECT_TYPE_SPECIAL: +- /* Do nothing */ +- break; +- case YAFFS_OBJECT_TYPE_SYMLINK: +- in->variant.symlink_variant. +- alias = +- yaffs_clone_str(oh->alias); +- if (!in->variant. +- symlink_variant.alias) +- alloc_failed = 1; +- break; +- } +- } +- } +- } +- +- if (state == YAFFS_BLOCK_STATE_NEEDS_SCAN) { +- /* If we got this far while scanning, +- * then the block is fully allocated. */ +- state = YAFFS_BLOCK_STATE_FULL; +- } +- +- if (state == YAFFS_BLOCK_STATE_ALLOCATING) { +- /* If the block was partially allocated then +- * treat it as fully allocated. */ +- state = YAFFS_BLOCK_STATE_FULL; +- dev->alloc_block = -1; +- } +- +- bi->block_state = state; +- +- /* Now let's see if it was dirty */ +- if (bi->pages_in_use == 0 && +- !bi->has_shrink_hdr && +- bi->block_state == YAFFS_BLOCK_STATE_FULL) +- yaffs_block_became_dirty(dev, blk); +- } +- +- /* Ok, we've done all the scanning. +- * Fix up the hard link chains. +- * We should now have scanned all the objects, now it's time to add +- * these hardlinks. +- */ +- +- yaffs_link_fixup(dev, &hard_list); +- +- /* +- * Fix up any shadowed objects. +- * There should not be more than one of these. +- */ +- { +- struct yaffs_shadow_fixer *fixer; +- struct yaffs_obj *obj; +- +- while (shadow_fixers) { +- fixer = shadow_fixers; +- shadow_fixers = fixer->next; +- /* Complete the rename transaction by deleting the +- * shadowed object then setting the object header +- to unshadowed. +- */ +- obj = yaffs_find_by_number(dev, fixer->shadowed_id); +- if (obj) +- yaffs_del_obj(obj); +- +- obj = yaffs_find_by_number(dev, fixer->obj_id); +- +- if (obj) +- yaffs_update_oh(obj, NULL, 1, 0, 0, NULL); +- +- kfree(fixer); +- } +- } +- +- yaffs_release_temp_buffer(dev, chunk_data); +- +- if (alloc_failed) +- return YAFFS_FAIL; +- +- yaffs_trace(YAFFS_TRACE_SCAN, "yaffs1_scan ends"); +- +- return YAFFS_OK; +-} +diff --git a/fs/yaffs2/yaffs_yaffs1.h b/fs/yaffs2/yaffs_yaffs1.h +deleted file mode 100644 +index 97e2fdd..0000000 +--- a/fs/yaffs2/yaffs_yaffs1.h ++++ /dev/null +@@ -1,22 +0,0 @@ +-/* +- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU Lesser General Public License version 2.1 as +- * published by the Free Software Foundation. +- * +- * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +- */ +- +-#ifndef __YAFFS_YAFFS1_H__ +-#define __YAFFS_YAFFS1_H__ +- +-#include "yaffs_guts.h" +-int yaffs1_scan(struct yaffs_dev *dev); +- +-#endif +diff --git a/fs/yaffs2/yaffs_yaffs2.c b/fs/yaffs2/yaffs_yaffs2.c +deleted file mode 100644 +index f1dc972..0000000 +--- a/fs/yaffs2/yaffs_yaffs2.c ++++ /dev/null +@@ -1,1532 +0,0 @@ +-/* +- * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * 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 "yaffs_guts.h" +-#include "yaffs_trace.h" +-#include "yaffs_yaffs2.h" +-#include "yaffs_checkptrw.h" +-#include "yaffs_bitmap.h" +-#include "yaffs_nand.h" +-#include "yaffs_getblockinfo.h" +-#include "yaffs_verify.h" +-#include "yaffs_attribs.h" +-#include "yaffs_summary.h" +- +-/* +- * Checkpoints are really no benefit on very small partitions. +- * +- * To save space on small partitions don't bother with checkpoints unless +- * the partition is at least this big. +- */ +-#define YAFFS_CHECKPOINT_MIN_BLOCKS 60 +-#define YAFFS_SMALL_HOLE_THRESHOLD 4 +- +-/* +- * Oldest Dirty Sequence Number handling. +- */ +- +-/* yaffs_calc_oldest_dirty_seq() +- * yaffs2_find_oldest_dirty_seq() +- * Calculate the oldest dirty sequence number if we don't know it. +- */ +-void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev) +-{ +- int i; +- unsigned seq; +- unsigned block_no = 0; +- struct yaffs_block_info *b; +- +- if (!dev->param.is_yaffs2) +- return; +- +- /* Find the oldest dirty sequence number. */ +- seq = dev->seq_number + 1; +- b = dev->block_info; +- for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { +- if (b->block_state == YAFFS_BLOCK_STATE_FULL && +- (b->pages_in_use - b->soft_del_pages) < +- dev->param.chunks_per_block && +- b->seq_number < seq) { +- seq = b->seq_number; +- block_no = i; +- } +- b++; +- } +- +- if (block_no) { +- dev->oldest_dirty_seq = seq; +- dev->oldest_dirty_block = block_no; +- } +-} +- +-void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev) +-{ +- if (!dev->param.is_yaffs2) +- return; +- +- if (!dev->oldest_dirty_seq) +- yaffs_calc_oldest_dirty_seq(dev); +-} +- +-/* +- * yaffs_clear_oldest_dirty_seq() +- * Called when a block is erased or marked bad. (ie. when its seq_number +- * becomes invalid). If the value matches the oldest then we clear +- * dev->oldest_dirty_seq to force its recomputation. +- */ +-void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev, +- struct yaffs_block_info *bi) +-{ +- +- if (!dev->param.is_yaffs2) +- return; +- +- if (!bi || bi->seq_number == dev->oldest_dirty_seq) { +- dev->oldest_dirty_seq = 0; +- dev->oldest_dirty_block = 0; +- } +-} +- +-/* +- * yaffs2_update_oldest_dirty_seq() +- * Update the oldest dirty sequence number whenever we dirty a block. +- * Only do this if the oldest_dirty_seq is actually being tracked. +- */ +-void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no, +- struct yaffs_block_info *bi) +-{ +- if (!dev->param.is_yaffs2) +- return; +- +- if (dev->oldest_dirty_seq) { +- if (dev->oldest_dirty_seq > bi->seq_number) { +- dev->oldest_dirty_seq = bi->seq_number; +- dev->oldest_dirty_block = block_no; +- } +- } +-} +- +-int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi) +-{ +- +- if (!dev->param.is_yaffs2) +- return 1; /* disqualification only applies to yaffs2. */ +- +- if (!bi->has_shrink_hdr) +- return 1; /* can gc */ +- +- yaffs2_find_oldest_dirty_seq(dev); +- +- /* Can't do gc of this block if there are any blocks older than this +- * one that have discarded pages. +- */ +- return (bi->seq_number <= dev->oldest_dirty_seq); +-} +- +-/* +- * yaffs2_find_refresh_block() +- * periodically finds the oldest full block by sequence number for refreshing. +- * Only for yaffs2. +- */ +-u32 yaffs2_find_refresh_block(struct yaffs_dev *dev) +-{ +- u32 b; +- u32 oldest = 0; +- u32 oldest_seq = 0; +- struct yaffs_block_info *bi; +- +- if (!dev->param.is_yaffs2) +- return oldest; +- +- /* +- * If refresh period < 10 then refreshing is disabled. +- */ +- if (dev->param.refresh_period < 10) +- return oldest; +- +- /* +- * Fix broken values. +- */ +- if (dev->refresh_skip > dev->param.refresh_period) +- dev->refresh_skip = dev->param.refresh_period; +- +- if (dev->refresh_skip > 0) +- return oldest; +- +- /* +- * Refresh skip is now zero. +- * We'll do a refresh this time around.... +- * Update the refresh skip and find the oldest block. +- */ +- dev->refresh_skip = dev->param.refresh_period; +- dev->refresh_count++; +- bi = dev->block_info; +- for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) { +- +- if (bi->block_state == YAFFS_BLOCK_STATE_FULL) { +- +- if (oldest < 1 || bi->seq_number < oldest_seq) { +- oldest = b; +- oldest_seq = bi->seq_number; +- } +- } +- bi++; +- } +- +- if (oldest > 0) { +- yaffs_trace(YAFFS_TRACE_GC, +- "GC refresh count %d selected block %d with seq_number %d", +- dev->refresh_count, oldest, oldest_seq); +- } +- +- return oldest; +-} +- +-int yaffs2_checkpt_required(struct yaffs_dev *dev) +-{ +- int nblocks; +- +- if (!dev->param.is_yaffs2) +- return 0; +- +- nblocks = dev->internal_end_block - dev->internal_start_block + 1; +- +- return !dev->param.skip_checkpt_wr && +- !dev->read_only && (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS); +-} +- +-int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev) +-{ +- int retval; +- int n_bytes = 0; +- int n_blocks; +- int dev_blocks; +- +- if (!dev->param.is_yaffs2) +- return 0; +- +- if (!dev->checkpoint_blocks_required && yaffs2_checkpt_required(dev)) { +- /* Not a valid value so recalculate */ +- dev_blocks = dev->param.end_block - dev->param.start_block + 1; +- n_bytes += sizeof(struct yaffs_checkpt_validity); +- n_bytes += sizeof(struct yaffs_checkpt_dev); +- n_bytes += dev_blocks * sizeof(struct yaffs_block_info); +- n_bytes += dev_blocks * dev->chunk_bit_stride; +- n_bytes += +- (sizeof(struct yaffs_checkpt_obj) + sizeof(u32)) * +- dev->n_obj; +- n_bytes += (dev->tnode_size + sizeof(u32)) * dev->n_tnodes; +- n_bytes += sizeof(struct yaffs_checkpt_validity); +- n_bytes += sizeof(u32); /* checksum */ +- +- /* Round up and add 2 blocks to allow for some bad blocks, +- * so add 3 */ +- +- n_blocks = +- (n_bytes / +- (dev->data_bytes_per_chunk * +- dev->param.chunks_per_block)) + 3; +- +- dev->checkpoint_blocks_required = n_blocks; +- } +- +- retval = dev->checkpoint_blocks_required - dev->blocks_in_checkpt; +- if (retval < 0) +- retval = 0; +- return retval; +-} +- +-/*--------------------- Checkpointing --------------------*/ +- +-static int yaffs2_wr_checkpt_validity_marker(struct yaffs_dev *dev, int head) +-{ +- struct yaffs_checkpt_validity cp; +- +- memset(&cp, 0, sizeof(cp)); +- +- cp.struct_type = sizeof(cp); +- cp.magic = YAFFS_MAGIC; +- cp.version = YAFFS_CHECKPOINT_VERSION; +- cp.head = (head) ? 1 : 0; +- +- return (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)) ? 1 : 0; +-} +- +-static int yaffs2_rd_checkpt_validity_marker(struct yaffs_dev *dev, int head) +-{ +- struct yaffs_checkpt_validity cp; +- int ok; +- +- ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp)); +- +- if (ok) +- ok = (cp.struct_type == sizeof(cp)) && +- (cp.magic == YAFFS_MAGIC) && +- (cp.version == YAFFS_CHECKPOINT_VERSION) && +- (cp.head == ((head) ? 1 : 0)); +- return ok ? 1 : 0; +-} +- +-static void yaffs2_dev_to_checkpt_dev(struct yaffs_checkpt_dev *cp, +- struct yaffs_dev *dev) +-{ +- cp->n_erased_blocks = dev->n_erased_blocks; +- cp->alloc_block = dev->alloc_block; +- cp->alloc_page = dev->alloc_page; +- cp->n_free_chunks = dev->n_free_chunks; +- +- cp->n_deleted_files = dev->n_deleted_files; +- cp->n_unlinked_files = dev->n_unlinked_files; +- cp->n_bg_deletions = dev->n_bg_deletions; +- cp->seq_number = dev->seq_number; +- +-} +- +-static void yaffs_checkpt_dev_to_dev(struct yaffs_dev *dev, +- struct yaffs_checkpt_dev *cp) +-{ +- dev->n_erased_blocks = cp->n_erased_blocks; +- dev->alloc_block = cp->alloc_block; +- dev->alloc_page = cp->alloc_page; +- dev->n_free_chunks = cp->n_free_chunks; +- +- dev->n_deleted_files = cp->n_deleted_files; +- dev->n_unlinked_files = cp->n_unlinked_files; +- dev->n_bg_deletions = cp->n_bg_deletions; +- dev->seq_number = cp->seq_number; +-} +- +-static int yaffs2_wr_checkpt_dev(struct yaffs_dev *dev) +-{ +- struct yaffs_checkpt_dev cp; +- u32 n_bytes; +- u32 n_blocks = dev->internal_end_block - dev->internal_start_block + 1; +- int ok; +- +- /* Write device runtime values */ +- yaffs2_dev_to_checkpt_dev(&cp, dev); +- cp.struct_type = sizeof(cp); +- +- ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)); +- if (!ok) +- return 0; +- +- /* Write block info */ +- n_bytes = n_blocks * sizeof(struct yaffs_block_info); +- ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) == n_bytes); +- if (!ok) +- return 0; +- +- /* Write chunk bits */ +- n_bytes = n_blocks * dev->chunk_bit_stride; +- ok = (yaffs2_checkpt_wr(dev, dev->chunk_bits, n_bytes) == n_bytes); +- +- return ok ? 1 : 0; +-} +- +-static int yaffs2_rd_checkpt_dev(struct yaffs_dev *dev) +-{ +- struct yaffs_checkpt_dev cp; +- u32 n_bytes; +- u32 n_blocks = +- (dev->internal_end_block - dev->internal_start_block + 1); +- int ok; +- +- ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp)); +- if (!ok) +- return 0; +- +- if (cp.struct_type != sizeof(cp)) +- return 0; +- +- yaffs_checkpt_dev_to_dev(dev, &cp); +- +- n_bytes = n_blocks * sizeof(struct yaffs_block_info); +- +- ok = (yaffs2_checkpt_rd(dev, dev->block_info, n_bytes) == n_bytes); +- +- if (!ok) +- return 0; +- +- n_bytes = n_blocks * dev->chunk_bit_stride; +- +- ok = (yaffs2_checkpt_rd(dev, dev->chunk_bits, n_bytes) == n_bytes); +- +- return ok ? 1 : 0; +-} +- +-static void yaffs2_obj_checkpt_obj(struct yaffs_checkpt_obj *cp, +- struct yaffs_obj *obj) +-{ +- cp->obj_id = obj->obj_id; +- cp->parent_id = (obj->parent) ? obj->parent->obj_id : 0; +- cp->hdr_chunk = obj->hdr_chunk; +- cp->variant_type = obj->variant_type; +- cp->deleted = obj->deleted; +- cp->soft_del = obj->soft_del; +- cp->unlinked = obj->unlinked; +- cp->fake = obj->fake; +- cp->rename_allowed = obj->rename_allowed; +- cp->unlink_allowed = obj->unlink_allowed; +- cp->serial = obj->serial; +- cp->n_data_chunks = obj->n_data_chunks; +- +- if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) +- cp->size_or_equiv_obj = obj->variant.file_variant.file_size; +- else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) +- cp->size_or_equiv_obj = obj->variant.hardlink_variant.equiv_id; +-} +- +-static int yaffs2_checkpt_obj_to_obj(struct yaffs_obj *obj, +- struct yaffs_checkpt_obj *cp) +-{ +- struct yaffs_obj *parent; +- +- if (obj->variant_type != cp->variant_type) { +- yaffs_trace(YAFFS_TRACE_ERROR, +- "Checkpoint read object %d type %d chunk %d does not match existing object type %d", +- cp->obj_id, cp->variant_type, cp->hdr_chunk, +- obj->variant_type); +- return 0; +- } +- +- obj->obj_id = cp->obj_id; +- +- if (cp->parent_id) +- parent = yaffs_find_or_create_by_number(obj->my_dev, +- cp->parent_id, +- YAFFS_OBJECT_TYPE_DIRECTORY); +- else +- parent = NULL; +- +- if (parent) { +- if (parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { +- yaffs_trace(YAFFS_TRACE_ALWAYS, +- "Checkpoint read object %d parent %d type %d chunk %d Parent type, %d, not directory", +- cp->obj_id, cp->parent_id, +- cp->variant_type, cp->hdr_chunk, +- parent->variant_type); +- return 0; +- } +- yaffs_add_obj_to_dir(parent, obj); +- } +- +- obj->hdr_chunk = cp->hdr_chunk; +- obj->variant_type = cp->variant_type; +- obj->deleted = cp->deleted; +- obj->soft_del = cp->soft_del; +- obj->unlinked = cp->unlinked; +- obj->fake = cp->fake; +- obj->rename_allowed = cp->rename_allowed; +- obj->unlink_allowed = cp->unlink_allowed; +- obj->serial = cp->serial; +- obj->n_data_chunks = cp->n_data_chunks; +- +- if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) +- obj->variant.file_variant.file_size = cp->size_or_equiv_obj; +- else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) +- obj->variant.hardlink_variant.equiv_id = cp->size_or_equiv_obj; +- +- if (obj->hdr_chunk > 0) +- obj->lazy_loaded = 1; +- return 1; +-} +- +-static int yaffs2_checkpt_tnode_worker(struct yaffs_obj *in, +- struct yaffs_tnode *tn, u32 level, +- int chunk_offset) +-{ +- int i; +- struct yaffs_dev *dev = in->my_dev; +- int ok = 1; +- u32 base_offset; +- +- if (!tn) +- return 1; +- +- if (level > 0) { +- for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) { +- if (!tn->internal[i]) +- continue; +- ok = yaffs2_checkpt_tnode_worker(in, +- tn->internal[i], +- level - 1, +- (chunk_offset << +- YAFFS_TNODES_INTERNAL_BITS) + i); +- } +- return ok; +- } +- +- /* Level 0 tnode */ +- base_offset = chunk_offset << YAFFS_TNODES_LEVEL0_BITS; +- ok = (yaffs2_checkpt_wr(dev, &base_offset, sizeof(base_offset)) == +- sizeof(base_offset)); +- if (ok) +- ok = (yaffs2_checkpt_wr(dev, tn, dev->tnode_size) == +- dev->tnode_size); +- +- return ok; +-} +- +-static int yaffs2_wr_checkpt_tnodes(struct yaffs_obj *obj) +-{ +- u32 end_marker = ~0; +- int ok = 1; +- +- if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE) +- return ok; +- +- ok = yaffs2_checkpt_tnode_worker(obj, +- obj->variant.file_variant.top, +- obj->variant.file_variant. +- top_level, 0); +- if (ok) +- ok = (yaffs2_checkpt_wr(obj->my_dev, &end_marker, +- sizeof(end_marker)) == sizeof(end_marker)); +- +- return ok ? 1 : 0; +-} +- +-static int yaffs2_rd_checkpt_tnodes(struct yaffs_obj *obj) +-{ +- u32 base_chunk; +- int ok = 1; +- struct yaffs_dev *dev = obj->my_dev; +- struct yaffs_file_var *file_stuct_ptr = &obj->variant.file_variant; +- struct yaffs_tnode *tn; +- int nread = 0; +- +- ok = (yaffs2_checkpt_rd(dev, &base_chunk, sizeof(base_chunk)) == +- sizeof(base_chunk)); +- +- while (ok && (~base_chunk)) { +- nread++; +- /* Read level 0 tnode */ +- +- tn = yaffs_get_tnode(dev); +- if (tn) +- ok = (yaffs2_checkpt_rd(dev, tn, dev->tnode_size) == +- dev->tnode_size); +- else +- ok = 0; +- +- if (tn && ok) +- ok = yaffs_add_find_tnode_0(dev, +- file_stuct_ptr, +- base_chunk, tn) ? 1 : 0; +- +- if (ok) +- ok = (yaffs2_checkpt_rd +- (dev, &base_chunk, +- sizeof(base_chunk)) == sizeof(base_chunk)); +- } +- +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, +- "Checkpoint read tnodes %d records, last %d. ok %d", +- nread, base_chunk, ok); +- +- return ok ? 1 : 0; +-} +- +-static int yaffs2_wr_checkpt_objs(struct yaffs_dev *dev) +-{ +- struct yaffs_obj *obj; +- struct yaffs_checkpt_obj cp; +- int i; +- int ok = 1; +- struct list_head *lh; +- +- /* Iterate through the objects in each hash entry, +- * dumping them to the checkpointing stream. +- */ +- +- for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) { +- list_for_each(lh, &dev->obj_bucket[i].list) { +- obj = list_entry(lh, struct yaffs_obj, hash_link); +- if (!obj->defered_free) { +- yaffs2_obj_checkpt_obj(&cp, obj); +- cp.struct_type = sizeof(cp); +- +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, +- "Checkpoint write object %d parent %d type %d chunk %d obj addr %p", +- cp.obj_id, cp.parent_id, +- cp.variant_type, cp.hdr_chunk, obj); +- +- ok = (yaffs2_checkpt_wr(dev, &cp, +- sizeof(cp)) == sizeof(cp)); +- +- if (ok && +- obj->variant_type == +- YAFFS_OBJECT_TYPE_FILE) +- ok = yaffs2_wr_checkpt_tnodes(obj); +- } +- } +- } +- +- /* Dump end of list */ +- memset(&cp, 0xff, sizeof(struct yaffs_checkpt_obj)); +- cp.struct_type = sizeof(cp); +- +- if (ok) +- ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)); +- +- return ok ? 1 : 0; +-} +- +-static int yaffs2_rd_checkpt_objs(struct yaffs_dev *dev) +-{ +- struct yaffs_obj *obj; +- struct yaffs_checkpt_obj cp; +- int ok = 1; +- int done = 0; +- LIST_HEAD(hard_list); +- +- +- while (ok && !done) { +- ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp)); +- if (cp.struct_type != sizeof(cp)) { +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, +- "struct size %d instead of %d ok %d", +- cp.struct_type, (int)sizeof(cp), ok); +- ok = 0; +- } +- +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, +- "Checkpoint read object %d parent %d type %d chunk %d ", +- cp.obj_id, cp.parent_id, cp.variant_type, +- cp.hdr_chunk); +- +- if (ok && cp.obj_id == ~0) { +- done = 1; +- } else if (ok) { +- obj = +- yaffs_find_or_create_by_number(dev, cp.obj_id, +- cp.variant_type); +- if (obj) { +- ok = yaffs2_checkpt_obj_to_obj(obj, &cp); +- if (!ok) +- break; +- if (obj->variant_type == +- YAFFS_OBJECT_TYPE_FILE) { +- ok = yaffs2_rd_checkpt_tnodes(obj); +- } else if (obj->variant_type == +- YAFFS_OBJECT_TYPE_HARDLINK) { +- list_add(&obj->hard_links, &hard_list); +- } +- } else { +- ok = 0; +- } +- } +- } +- +- if (ok) +- yaffs_link_fixup(dev, &hard_list); +- +- return ok ? 1 : 0; +-} +- +-static int yaffs2_wr_checkpt_sum(struct yaffs_dev *dev) +-{ +- u32 checkpt_sum; +- int ok; +- +- yaffs2_get_checkpt_sum(dev, &checkpt_sum); +- +- ok = (yaffs2_checkpt_wr(dev, &checkpt_sum, sizeof(checkpt_sum)) == +- sizeof(checkpt_sum)); +- +- if (!ok) +- return 0; +- +- return 1; +-} +- +-static int yaffs2_rd_checkpt_sum(struct yaffs_dev *dev) +-{ +- u32 checkpt_sum0; +- u32 checkpt_sum1; +- int ok; +- +- yaffs2_get_checkpt_sum(dev, &checkpt_sum0); +- +- ok = (yaffs2_checkpt_rd(dev, &checkpt_sum1, sizeof(checkpt_sum1)) == +- sizeof(checkpt_sum1)); +- +- if (!ok) +- return 0; +- +- if (checkpt_sum0 != checkpt_sum1) +- return 0; +- +- return 1; +-} +- +-static int yaffs2_wr_checkpt_data(struct yaffs_dev *dev) +-{ +- int ok = 1; +- +- if (!yaffs2_checkpt_required(dev)) { +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, +- "skipping checkpoint write"); +- ok = 0; +- } +- +- if (ok) +- ok = yaffs2_checkpt_open(dev, 1); +- +- if (ok) { +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, +- "write checkpoint validity"); +- ok = yaffs2_wr_checkpt_validity_marker(dev, 1); +- } +- if (ok) { +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, +- "write checkpoint device"); +- ok = yaffs2_wr_checkpt_dev(dev); +- } +- if (ok) { +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, +- "write checkpoint objects"); +- ok = yaffs2_wr_checkpt_objs(dev); +- } +- if (ok) { +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, +- "write checkpoint validity"); +- ok = yaffs2_wr_checkpt_validity_marker(dev, 0); +- } +- +- if (ok) +- ok = yaffs2_wr_checkpt_sum(dev); +- +- if (!yaffs_checkpt_close(dev)) +- ok = 0; +- +- if (ok) +- dev->is_checkpointed = 1; +- else +- dev->is_checkpointed = 0; +- +- return dev->is_checkpointed; +-} +- +-static int yaffs2_rd_checkpt_data(struct yaffs_dev *dev) +-{ +- int ok = 1; +- +- if (!dev->param.is_yaffs2) +- ok = 0; +- +- if (ok && dev->param.skip_checkpt_rd) { +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, +- "skipping checkpoint read"); +- ok = 0; +- } +- +- if (ok) +- ok = yaffs2_checkpt_open(dev, 0); /* open for read */ +- +- if (ok) { +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, +- "read checkpoint validity"); +- ok = yaffs2_rd_checkpt_validity_marker(dev, 1); +- } +- if (ok) { +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, +- "read checkpoint device"); +- ok = yaffs2_rd_checkpt_dev(dev); +- } +- if (ok) { +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, +- "read checkpoint objects"); +- ok = yaffs2_rd_checkpt_objs(dev); +- } +- if (ok) { +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, +- "read checkpoint validity"); +- ok = yaffs2_rd_checkpt_validity_marker(dev, 0); +- } +- +- if (ok) { +- ok = yaffs2_rd_checkpt_sum(dev); +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, +- "read checkpoint checksum %d", ok); +- } +- +- if (!yaffs_checkpt_close(dev)) +- ok = 0; +- +- if (ok) +- dev->is_checkpointed = 1; +- else +- dev->is_checkpointed = 0; +- +- return ok ? 1 : 0; +-} +- +-void yaffs2_checkpt_invalidate(struct yaffs_dev *dev) +-{ +- if (dev->is_checkpointed || dev->blocks_in_checkpt > 0) { +- dev->is_checkpointed = 0; +- yaffs2_checkpt_invalidate_stream(dev); +- } +- if (dev->param.sb_dirty_fn) +- dev->param.sb_dirty_fn(dev); +-} +- +-int yaffs_checkpoint_save(struct yaffs_dev *dev) +-{ +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, +- "save entry: is_checkpointed %d", +- dev->is_checkpointed); +- +- yaffs_verify_objects(dev); +- yaffs_verify_blocks(dev); +- yaffs_verify_free_chunks(dev); +- +- if (!dev->is_checkpointed) { +- yaffs2_checkpt_invalidate(dev); +- yaffs2_wr_checkpt_data(dev); +- } +- +- yaffs_trace(YAFFS_TRACE_CHECKPOINT | YAFFS_TRACE_MOUNT, +- "save exit: is_checkpointed %d", +- dev->is_checkpointed); +- +- return dev->is_checkpointed; +-} +- +-int yaffs2_checkpt_restore(struct yaffs_dev *dev) +-{ +- int retval; +- +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, +- "restore entry: is_checkpointed %d", +- dev->is_checkpointed); +- +- retval = yaffs2_rd_checkpt_data(dev); +- +- if (dev->is_checkpointed) { +- yaffs_verify_objects(dev); +- yaffs_verify_blocks(dev); +- yaffs_verify_free_chunks(dev); +- } +- +- yaffs_trace(YAFFS_TRACE_CHECKPOINT, +- "restore exit: is_checkpointed %d", +- dev->is_checkpointed); +- +- return retval; +-} +- +-int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size) +-{ +- /* if new_size > old_file_size. +- * We're going to be writing a hole. +- * If the hole is small then write zeros otherwise write a start +- * of hole marker. +- */ +- loff_t old_file_size; +- loff_t increase; +- int small_hole; +- int result = YAFFS_OK; +- struct yaffs_dev *dev = NULL; +- u8 *local_buffer = NULL; +- int small_increase_ok = 0; +- +- if (!obj) +- return YAFFS_FAIL; +- +- if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE) +- return YAFFS_FAIL; +- +- dev = obj->my_dev; +- +- /* Bail out if not yaffs2 mode */ +- if (!dev->param.is_yaffs2) +- return YAFFS_OK; +- +- old_file_size = obj->variant.file_variant.file_size; +- +- if (new_size <= old_file_size) +- return YAFFS_OK; +- +- increase = new_size - old_file_size; +- +- if (increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->data_bytes_per_chunk && +- yaffs_check_alloc_available(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1)) +- small_hole = 1; +- else +- small_hole = 0; +- +- if (small_hole) +- local_buffer = yaffs_get_temp_buffer(dev); +- +- if (local_buffer) { +- /* fill hole with zero bytes */ +- loff_t pos = old_file_size; +- int this_write; +- int written; +- memset(local_buffer, 0, dev->data_bytes_per_chunk); +- small_increase_ok = 1; +- +- while (increase > 0 && small_increase_ok) { +- this_write = increase; +- if (this_write > dev->data_bytes_per_chunk) +- this_write = dev->data_bytes_per_chunk; +- written = +- yaffs_do_file_wr(obj, local_buffer, pos, this_write, +- 0); +- if (written == this_write) { +- pos += this_write; +- increase -= this_write; +- } else { +- small_increase_ok = 0; +- } +- } +- +- yaffs_release_temp_buffer(dev, local_buffer); +- +- /* If out of space then reverse any chunks we've added */ +- if (!small_increase_ok) +- yaffs_resize_file_down(obj, old_file_size); +- } +- +- if (!small_increase_ok && +- obj->parent && +- obj->parent->obj_id != YAFFS_OBJECTID_UNLINKED && +- obj->parent->obj_id != YAFFS_OBJECTID_DELETED) { +- /* Write a hole start header with the old file size */ +- yaffs_update_oh(obj, NULL, 0, 1, 0, NULL); +- } +- +- return result; +-} +- +-struct yaffs_block_index { +- int seq; +- int block; +-}; +- +-static int yaffs2_ybicmp(const void *a, const void *b) +-{ +- int aseq = ((struct yaffs_block_index *)a)->seq; +- int bseq = ((struct yaffs_block_index *)b)->seq; +- int ablock = ((struct yaffs_block_index *)a)->block; +- int bblock = ((struct yaffs_block_index *)b)->block; +- +- if (aseq == bseq) +- return ablock - bblock; +- +- return aseq - bseq; +-} +- +-static inline int yaffs2_scan_chunk(struct yaffs_dev *dev, +- struct yaffs_block_info *bi, +- int blk, int chunk_in_block, +- int *found_chunks, +- u8 *chunk_data, +- struct list_head *hard_list, +- int summary_available) +-{ +- struct yaffs_obj_hdr *oh; +- struct yaffs_obj *in; +- struct yaffs_obj *parent; +- int equiv_id; +- loff_t file_size; +- int is_shrink; +- int is_unlinked; +- struct yaffs_ext_tags tags; +- int result; +- int alloc_failed = 0; +- int chunk = blk * dev->param.chunks_per_block + chunk_in_block; +- struct yaffs_file_var *file_var; +- struct yaffs_hardlink_var *hl_var; +- struct yaffs_symlink_var *sl_var; +- +- if (summary_available) { +- result = yaffs_summary_fetch(dev, &tags, chunk_in_block); +- tags.seq_number = bi->seq_number; +- } +- +- if (!summary_available || tags.obj_id == 0) { +- result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL, &tags); +- dev->tags_used++; +- } else { +- dev->summary_used++; +- } +- +- /* Let's have a good look at this chunk... */ +- +- if (!tags.chunk_used) { +- /* An unassigned chunk in the block. +- * If there are used chunks after this one, then +- * it is a chunk that was skipped due to failing +- * the erased check. Just skip it so that it can +- * be deleted. +- * But, more typically, We get here when this is +- * an unallocated chunk and his means that +- * either the block is empty or this is the one +- * being allocated from +- */ +- +- if (*found_chunks) { +- /* This is a chunk that was skipped due +- * to failing the erased check */ +- } else if (chunk_in_block == 0) { +- /* We're looking at the first chunk in +- * the block so the block is unused */ +- bi->block_state = YAFFS_BLOCK_STATE_EMPTY; +- dev->n_erased_blocks++; +- } else { +- if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN || +- bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) { +- if (dev->seq_number == bi->seq_number) { +- /* Allocating from this block*/ +- yaffs_trace(YAFFS_TRACE_SCAN, +- " Allocating from %d %d", +- blk, chunk_in_block); +- +- bi->block_state = +- YAFFS_BLOCK_STATE_ALLOCATING; +- dev->alloc_block = blk; +- dev->alloc_page = chunk_in_block; +- dev->alloc_block_finder = blk; +- } else { +- /* This is a partially written block +- * that is not the current +- * allocation block. +- */ +- yaffs_trace(YAFFS_TRACE_SCAN, +- "Partially written block %d detected. gc will fix this.", +- blk); +- } +- } +- } +- +- dev->n_free_chunks++; +- +- } else if (tags.ecc_result == +- YAFFS_ECC_RESULT_UNFIXED) { +- yaffs_trace(YAFFS_TRACE_SCAN, +- " Unfixed ECC in chunk(%d:%d), chunk ignored", +- blk, chunk_in_block); +- dev->n_free_chunks++; +- } else if (tags.obj_id > YAFFS_MAX_OBJECT_ID || +- tags.chunk_id > YAFFS_MAX_CHUNK_ID || +- tags.obj_id == YAFFS_OBJECTID_SUMMARY || +- (tags.chunk_id > 0 && +- tags.n_bytes > dev->data_bytes_per_chunk) || +- tags.seq_number != bi->seq_number) { +- yaffs_trace(YAFFS_TRACE_SCAN, +- "Chunk (%d:%d) with bad tags:obj = %d, chunk_id = %d, n_bytes = %d, ignored", +- blk, chunk_in_block, tags.obj_id, +- tags.chunk_id, tags.n_bytes); +- dev->n_free_chunks++; +- } else if (tags.chunk_id > 0) { +- /* chunk_id > 0 so it is a data chunk... */ +- loff_t endpos; +- loff_t chunk_base = (tags.chunk_id - 1) * +- dev->data_bytes_per_chunk; +- +- *found_chunks = 1; +- +- yaffs_set_chunk_bit(dev, blk, chunk_in_block); +- bi->pages_in_use++; +- +- in = yaffs_find_or_create_by_number(dev, +- tags.obj_id, +- YAFFS_OBJECT_TYPE_FILE); +- if (!in) +- /* Out of memory */ +- alloc_failed = 1; +- +- if (in && +- in->variant_type == YAFFS_OBJECT_TYPE_FILE && +- chunk_base < in->variant.file_variant.shrink_size) { +- /* This has not been invalidated by +- * a resize */ +- if (!yaffs_put_chunk_in_file(in, tags.chunk_id, +- chunk, -1)) +- alloc_failed = 1; +- +- /* File size is calculated by looking at +- * the data chunks if we have not +- * seen an object header yet. +- * Stop this practice once we find an +- * object header. +- */ +- endpos = chunk_base + tags.n_bytes; +- +- if (!in->valid && +- in->variant.file_variant.scanned_size < endpos) { +- in->variant.file_variant. +- scanned_size = endpos; +- in->variant.file_variant. +- file_size = endpos; +- } +- } else if (in) { +- /* This chunk has been invalidated by a +- * resize, or a past file deletion +- * so delete the chunk*/ +- yaffs_chunk_del(dev, chunk, 1, __LINE__); +- } +- } else { +- /* chunk_id == 0, so it is an ObjectHeader. +- * Thus, we read in the object header and make +- * the object +- */ +- *found_chunks = 1; +- +- yaffs_set_chunk_bit(dev, blk, chunk_in_block); +- bi->pages_in_use++; +- +- oh = NULL; +- in = NULL; +- +- if (tags.extra_available) { +- in = yaffs_find_or_create_by_number(dev, +- tags.obj_id, +- tags.extra_obj_type); +- if (!in) +- alloc_failed = 1; +- } +- +- if (!in || +- (!in->valid && dev->param.disable_lazy_load) || +- tags.extra_shadows || +- (!in->valid && (tags.obj_id == YAFFS_OBJECTID_ROOT || +- tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND))) { +- +- /* If we don't have valid info then we +- * need to read the chunk +- * TODO In future we can probably defer +- * reading the chunk and living with +- * invalid data until needed. +- */ +- +- result = yaffs_rd_chunk_tags_nand(dev, +- chunk, +- chunk_data, +- NULL); +- +- oh = (struct yaffs_obj_hdr *)chunk_data; +- +- if (dev->param.inband_tags) { +- /* Fix up the header if they got +- * corrupted by inband tags */ +- oh->shadows_obj = +- oh->inband_shadowed_obj_id; +- oh->is_shrink = +- oh->inband_is_shrink; +- } +- +- if (!in) { +- in = yaffs_find_or_create_by_number(dev, +- tags.obj_id, oh->type); +- if (!in) +- alloc_failed = 1; +- } +- } +- +- if (!in) { +- /* TODO Hoosterman we have a problem! */ +- yaffs_trace(YAFFS_TRACE_ERROR, +- "yaffs tragedy: Could not make object for object %d at chunk %d during scan", +- tags.obj_id, chunk); +- return YAFFS_FAIL; +- } +- +- if (in->valid) { +- /* We have already filled this one. +- * We have a duplicate that will be +- * discarded, but we first have to suck +- * out resize info if it is a file. +- */ +- if ((in->variant_type == YAFFS_OBJECT_TYPE_FILE) && +- ((oh && oh->type == YAFFS_OBJECT_TYPE_FILE) || +- (tags.extra_available && +- tags.extra_obj_type == YAFFS_OBJECT_TYPE_FILE) +- )) { +- loff_t this_size = (oh) ? +- yaffs_oh_to_size(oh) : +- tags.extra_file_size; +- u32 parent_obj_id = (oh) ? +- oh->parent_obj_id : +- tags.extra_parent_id; +- +- is_shrink = (oh) ? +- oh->is_shrink : +- tags.extra_is_shrink; +- +- /* If it is deleted (unlinked +- * at start also means deleted) +- * we treat the file size as +- * being zeroed at this point. +- */ +- if (parent_obj_id == YAFFS_OBJECTID_DELETED || +- parent_obj_id == YAFFS_OBJECTID_UNLINKED) { +- this_size = 0; +- is_shrink = 1; +- } +- +- if (is_shrink && +- in->variant.file_variant.shrink_size > +- this_size) +- in->variant.file_variant.shrink_size = +- this_size; +- +- if (is_shrink) +- bi->has_shrink_hdr = 1; +- } +- /* Use existing - destroy this one. */ +- yaffs_chunk_del(dev, chunk, 1, __LINE__); +- } +- +- if (!in->valid && in->variant_type != +- (oh ? oh->type : tags.extra_obj_type)) +- yaffs_trace(YAFFS_TRACE_ERROR, +- "yaffs tragedy: Bad object type, %d != %d, for object %d at chunk %d during scan", +- oh ? oh->type : tags.extra_obj_type, +- in->variant_type, tags.obj_id, +- chunk); +- +- if (!in->valid && +- (tags.obj_id == YAFFS_OBJECTID_ROOT || +- tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND)) { +- /* We only load some info, don't fiddle +- * with directory structure */ +- in->valid = 1; +- +- if (oh) { +- in->yst_mode = oh->yst_mode; +- yaffs_load_attribs(in, oh); +- in->lazy_loaded = 0; +- } else { +- in->lazy_loaded = 1; +- } +- in->hdr_chunk = chunk; +- +- } else if (!in->valid) { +- /* we need to load this info */ +- in->valid = 1; +- in->hdr_chunk = chunk; +- if (oh) { +- in->variant_type = oh->type; +- in->yst_mode = oh->yst_mode; +- yaffs_load_attribs(in, oh); +- +- if (oh->shadows_obj > 0) +- yaffs_handle_shadowed_obj(dev, +- oh->shadows_obj, 1); +- +- yaffs_set_obj_name_from_oh(in, oh); +- parent = yaffs_find_or_create_by_number(dev, +- oh->parent_obj_id, +- YAFFS_OBJECT_TYPE_DIRECTORY); +- file_size = yaffs_oh_to_size(oh); +- is_shrink = oh->is_shrink; +- equiv_id = oh->equiv_id; +- } else { +- in->variant_type = tags.extra_obj_type; +- parent = yaffs_find_or_create_by_number(dev, +- tags.extra_parent_id, +- YAFFS_OBJECT_TYPE_DIRECTORY); +- file_size = tags.extra_file_size; +- is_shrink = tags.extra_is_shrink; +- equiv_id = tags.extra_equiv_id; +- in->lazy_loaded = 1; +- } +- in->dirty = 0; +- +- if (!parent) +- alloc_failed = 1; +- +- /* directory stuff... +- * hook up to parent +- */ +- +- if (parent && +- parent->variant_type == YAFFS_OBJECT_TYPE_UNKNOWN) { +- /* Set up as a directory */ +- parent->variant_type = +- YAFFS_OBJECT_TYPE_DIRECTORY; +- INIT_LIST_HEAD(&parent-> +- variant.dir_variant.children); +- } else if (!parent || +- parent->variant_type != +- YAFFS_OBJECT_TYPE_DIRECTORY) { +- /* Hoosterman, another problem.... +- * Trying to use a non-directory as a directory +- */ +- +- yaffs_trace(YAFFS_TRACE_ERROR, +- "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." +- ); +- parent = dev->lost_n_found; +- } +- yaffs_add_obj_to_dir(parent, in); +- +- is_unlinked = (parent == dev->del_dir) || +- (parent == dev->unlinked_dir); +- +- if (is_shrink) +- /* Mark the block */ +- bi->has_shrink_hdr = 1; +- +- /* Note re hardlinks. +- * Since we might scan a hardlink before its equivalent +- * object is scanned we put them all in a list. +- * After scanning is complete, we should have all the +- * objects, so we run through this list and fix up all +- * the chains. +- */ +- +- switch (in->variant_type) { +- case YAFFS_OBJECT_TYPE_UNKNOWN: +- /* Todo got a problem */ +- break; +- case YAFFS_OBJECT_TYPE_FILE: +- file_var = &in->variant.file_variant; +- if (file_var->scanned_size < file_size) { +- /* This covers the case where the file +- * size is greater than the data held. +- * This will happen if the file is +- * resized to be larger than its +- * current data extents. +- */ +- file_var->file_size = file_size; +- file_var->scanned_size = file_size; +- } +- +- if (file_var->shrink_size > file_size) +- file_var->shrink_size = file_size; +- +- break; +- case YAFFS_OBJECT_TYPE_HARDLINK: +- hl_var = &in->variant.hardlink_variant; +- if (!is_unlinked) { +- hl_var->equiv_id = equiv_id; +- list_add(&in->hard_links, hard_list); +- } +- break; +- case YAFFS_OBJECT_TYPE_DIRECTORY: +- /* Do nothing */ +- break; +- case YAFFS_OBJECT_TYPE_SPECIAL: +- /* Do nothing */ +- break; +- case YAFFS_OBJECT_TYPE_SYMLINK: +- sl_var = &in->variant.symlink_variant; +- if (oh) { +- sl_var->alias = +- yaffs_clone_str(oh->alias); +- if (!sl_var->alias) +- alloc_failed = 1; +- } +- break; +- } +- } +- } +- return alloc_failed ? YAFFS_FAIL : YAFFS_OK; +-} +- +-int yaffs2_scan_backwards(struct yaffs_dev *dev) +-{ +- int blk; +- int block_iter; +- int start_iter; +- int end_iter; +- int n_to_scan = 0; +- enum yaffs_block_state state; +- int c; +- int deleted; +- LIST_HEAD(hard_list); +- struct yaffs_block_info *bi; +- u32 seq_number; +- int n_blocks = dev->internal_end_block - dev->internal_start_block + 1; +- u8 *chunk_data; +- int found_chunks; +- int alloc_failed = 0; +- struct yaffs_block_index *block_index = NULL; +- int alt_block_index = 0; +- int summary_available; +- +- yaffs_trace(YAFFS_TRACE_SCAN, +- "yaffs2_scan_backwards starts intstartblk %d intendblk %d...", +- dev->internal_start_block, dev->internal_end_block); +- +- dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER; +- +- block_index = +- kmalloc(n_blocks * sizeof(struct yaffs_block_index), GFP_NOFS); +- +- if (!block_index) { +- block_index = +- vmalloc(n_blocks * sizeof(struct yaffs_block_index)); +- alt_block_index = 1; +- } +- +- if (!block_index) { +- yaffs_trace(YAFFS_TRACE_SCAN, +- "yaffs2_scan_backwards() could not allocate block index!" +- ); +- return YAFFS_FAIL; +- } +- +- dev->blocks_in_checkpt = 0; +- +- chunk_data = yaffs_get_temp_buffer(dev); +- +- /* Scan all the blocks to determine their state */ +- bi = dev->block_info; +- for (blk = dev->internal_start_block; blk <= dev->internal_end_block; +- blk++) { +- yaffs_clear_chunk_bits(dev, blk); +- bi->pages_in_use = 0; +- bi->soft_del_pages = 0; +- +- yaffs_query_init_block_state(dev, blk, &state, &seq_number); +- +- bi->block_state = state; +- bi->seq_number = seq_number; +- +- if (bi->seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA) +- bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT; +- if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK) +- bi->block_state = YAFFS_BLOCK_STATE_DEAD; +- +- yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, +- "Block scanning block %d state %d seq %d", +- blk, bi->block_state, seq_number); +- +- if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) { +- dev->blocks_in_checkpt++; +- +- } else if (bi->block_state == YAFFS_BLOCK_STATE_DEAD) { +- yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, +- "block %d is bad", blk); +- } else if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) { +- yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty "); +- dev->n_erased_blocks++; +- dev->n_free_chunks += dev->param.chunks_per_block; +- } else if (bi->block_state == +- YAFFS_BLOCK_STATE_NEEDS_SCAN) { +- /* Determine the highest sequence number */ +- if (seq_number >= YAFFS_LOWEST_SEQUENCE_NUMBER && +- seq_number < YAFFS_HIGHEST_SEQUENCE_NUMBER) { +- block_index[n_to_scan].seq = seq_number; +- block_index[n_to_scan].block = blk; +- n_to_scan++; +- if (seq_number >= dev->seq_number) +- dev->seq_number = seq_number; +- } else { +- /* TODO: Nasty sequence number! */ +- yaffs_trace(YAFFS_TRACE_SCAN, +- "Block scanning block %d has bad sequence number %d", +- blk, seq_number); +- } +- } +- bi++; +- } +- +- yaffs_trace(YAFFS_TRACE_SCAN, "%d blocks to be sorted...", n_to_scan); +- +- cond_resched(); +- +- /* Sort the blocks by sequence number */ +- sort(block_index, n_to_scan, sizeof(struct yaffs_block_index), +- yaffs2_ybicmp, NULL); +- +- cond_resched(); +- +- yaffs_trace(YAFFS_TRACE_SCAN, "...done"); +- +- /* Now scan the blocks looking at the data. */ +- start_iter = 0; +- end_iter = n_to_scan - 1; +- yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "%d blocks to scan", n_to_scan); +- +- /* For each block.... backwards */ +- for (block_iter = end_iter; +- !alloc_failed && block_iter >= start_iter; +- block_iter--) { +- /* Cooperative multitasking! This loop can run for so +- long that watchdog timers expire. */ +- cond_resched(); +- +- /* get the block to scan in the correct order */ +- blk = block_index[block_iter].block; +- bi = yaffs_get_block_info(dev, blk); +- deleted = 0; +- +- summary_available = yaffs_summary_read(dev, dev->sum_tags, blk); +- +- /* For each chunk in each block that needs scanning.... */ +- found_chunks = 0; +- if (summary_available) +- c = dev->chunks_per_summary - 1; +- else +- c = dev->param.chunks_per_block - 1; +- +- for (/* c is already initialised */; +- !alloc_failed && c >= 0 && +- (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN || +- bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING); +- c--) { +- /* Scan backwards... +- * Read the tags and decide what to do +- */ +- if (yaffs2_scan_chunk(dev, bi, blk, c, +- &found_chunks, chunk_data, +- &hard_list, summary_available) == +- YAFFS_FAIL) +- alloc_failed = 1; +- } +- +- if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN) { +- /* If we got this far while scanning, then the block +- * is fully allocated. */ +- bi->block_state = YAFFS_BLOCK_STATE_FULL; +- } +- +- /* Now let's see if it was dirty */ +- if (bi->pages_in_use == 0 && +- !bi->has_shrink_hdr && +- bi->block_state == YAFFS_BLOCK_STATE_FULL) { +- yaffs_block_became_dirty(dev, blk); +- } +- } +- +- yaffs_skip_rest_of_block(dev); +- +- if (alt_block_index) +- vfree(block_index); +- else +- kfree(block_index); +- +- /* Ok, we've done all the scanning. +- * Fix up the hard link chains. +- * We have scanned all the objects, now it's time to add these +- * hardlinks. +- */ +- yaffs_link_fixup(dev, &hard_list); +- +- yaffs_release_temp_buffer(dev, chunk_data); +- +- if (alloc_failed) +- return YAFFS_FAIL; +- +- yaffs_trace(YAFFS_TRACE_SCAN, "yaffs2_scan_backwards ends"); +- +- return YAFFS_OK; +-} +diff --git a/fs/yaffs2/yaffs_yaffs2.h b/fs/yaffs2/yaffs_yaffs2.h +deleted file mode 100644 +index 2363bfd..0000000 +--- a/fs/yaffs2/yaffs_yaffs2.h ++++ /dev/null +@@ -1,39 +0,0 @@ +-/* +- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU Lesser General Public License version 2.1 as +- * published by the Free Software Foundation. +- * +- * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +- */ +- +-#ifndef __YAFFS_YAFFS2_H__ +-#define __YAFFS_YAFFS2_H__ +- +-#include "yaffs_guts.h" +- +-void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev); +-void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev); +-void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev, +- struct yaffs_block_info *bi); +-void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no, +- struct yaffs_block_info *bi); +-int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi); +-u32 yaffs2_find_refresh_block(struct yaffs_dev *dev); +-int yaffs2_checkpt_required(struct yaffs_dev *dev); +-int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev); +- +-void yaffs2_checkpt_invalidate(struct yaffs_dev *dev); +-int yaffs2_checkpt_save(struct yaffs_dev *dev); +-int yaffs2_checkpt_restore(struct yaffs_dev *dev); +- +-int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size); +-int yaffs2_scan_backwards(struct yaffs_dev *dev); +- +-#endif +diff --git a/fs/yaffs2/yportenv.h b/fs/yaffs2/yportenv.h +deleted file mode 100644 +index 666d909..0000000 +--- a/fs/yaffs2/yportenv.h ++++ /dev/null +@@ -1,82 +0,0 @@ +-/* +- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. +- * +- * Copyright (C) 2002-2011 Aleph One Ltd. +- * for Toby Churchill Ltd and Brightstar Engineering +- * +- * Created by Charles Manning +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU Lesser General Public License version 2.1 as +- * published by the Free Software Foundation. +- * +- * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +- */ +- +-#ifndef __YPORTENV_H__ +-#define __YPORTENV_H__ +- +-/* +- * Define the MTD version in terms of Linux Kernel versions +- * This allows yaffs to be used independantly of the kernel +- * as well as with it. +- */ +- +-#define MTD_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c)) +- +-#ifdef YAFFS_OUT_OF_TREE +-#include "moduleconfig.h" +-#endif +- +-#include +-#define MTD_VERSION_CODE LINUX_VERSION_CODE +- +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) +-#include +-#endif +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-/* These type wrappings are used to support Unicode names in WinCE. */ +-#define YCHAR char +-#define YUCHAR unsigned char +-#define _Y(x) x +- +-#define YAFFS_LOSTNFOUND_NAME "lost+found" +-#define YAFFS_LOSTNFOUND_PREFIX "obj" +- +- +-#define YAFFS_ROOT_MODE 0755 +-#define YAFFS_LOSTNFOUND_MODE 0700 +- +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) +-#define Y_CURRENT_TIME CURRENT_TIME.tv_sec +-#define Y_TIME_CONVERT(x) (x).tv_sec +-#else +-#define Y_CURRENT_TIME CURRENT_TIME +-#define Y_TIME_CONVERT(x) (x) +-#endif +- +-#define compile_time_assertion(assertion) \ +- ({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; }) +- +- +-#define yaffs_trace(msk, fmt, ...) do { \ +- if (yaffs_trace_mask & (msk)) \ +- printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__); \ +-} while (0) +- +- +-#endif +diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h +index f50a87d..5cf680a 100644 +--- a/include/asm-generic/pgtable.h ++++ b/include/asm-generic/pgtable.h +@@ -7,16 +7,6 @@ + #include + #include + +-/* +- * On almost all architectures and configurations, 0 can be used as the +- * upper ceiling to free_pgtables(): on many architectures it has the same +- * effect as using TASK_SIZE. However, there is one configuration which +- * must impose a more careful limit, to avoid freeing kernel pgtables. +- */ +-#ifndef USER_PGTABLES_CEILING +-#define USER_PGTABLES_CEILING 0UL +-#endif +- + #ifndef __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS + extern int ptep_set_access_flags(struct vm_area_struct *vma, + unsigned long address, pte_t *ptep, +diff --git a/include/drm/drmP.h b/include/drm/drmP.h +index 881fb15..fad21c9 100644 +--- a/include/drm/drmP.h ++++ b/include/drm/drmP.h +@@ -1559,8 +1559,9 @@ extern void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *s + + void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv); + void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv); +-int drm_prime_lookup_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t *handle); +-void drm_prime_remove_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf); ++int drm_prime_add_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle); ++int drm_prime_lookup_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t *handle); ++void drm_prime_remove_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf); + + int drm_prime_add_dma_buf(struct drm_device *dev, struct drm_gem_object *obj); + int drm_prime_lookup_obj(struct drm_device *dev, struct dma_buf *buf, +diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h +index d7da55c..1cdbfe9 100644 +--- a/include/drm/drm_pciids.h ++++ b/include/drm/drm_pciids.h +@@ -227,7 +227,6 @@ + {0x1002, 0x6819, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6821, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ +- {0x1002, 0x6822, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6823, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6824, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ +@@ -235,13 +234,11 @@ + {0x1002, 0x6827, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6829, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ +- {0x1002, 0x682A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x682B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x682D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x682F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6830, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6831, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ +- {0x1002, 0x6835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6837, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6838, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6839, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ +@@ -593,8 +590,6 @@ + {0x1002, 0x9999, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x999A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x999B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ +- {0x1002, 0x999C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ +- {0x1002, 0x999D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x99A0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x99A2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x99A4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ +diff --git a/include/linux/aufs_type.h b/include/linux/aufs_type.h +deleted file mode 100644 +index d5536d0..0000000 +--- a/include/linux/aufs_type.h ++++ /dev/null +@@ -1,19 +0,0 @@ +-/* +- * Copyright (C) 2012-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-#include +diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h +index 1dbdb1a..f94bc83 100644 +--- a/include/linux/blkdev.h ++++ b/include/linux/blkdev.h +@@ -836,7 +836,7 @@ static inline unsigned int blk_queue_get_max_sectors(struct request_queue *q, + unsigned int cmd_flags) + { + if (unlikely(cmd_flags & REQ_DISCARD)) +- return min(q->limits.max_discard_sectors, UINT_MAX >> 9); ++ return q->limits.max_discard_sectors; + + if (unlikely(cmd_flags & REQ_WRITE_SAME)) + return q->limits.max_write_same_sectors; +diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h +index 2322df7..7d73905 100644 +--- a/include/linux/cgroup.h ++++ b/include/linux/cgroup.h +@@ -303,6 +303,9 @@ struct cftype { + /* CFTYPE_* flags */ + unsigned int flags; + ++ /* file xattrs */ ++ struct simple_xattrs xattrs; ++ + int (*open)(struct inode *inode, struct file *file); + ssize_t (*read)(struct cgroup *cgrp, struct cftype *cft, + struct file *file, +diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h +index 4989b8a..a3c86c7 100644 +--- a/include/linux/clk-provider.h ++++ b/include/linux/clk-provider.h +@@ -239,9 +239,14 @@ struct clk_div_table { + * CLK_DIVIDER_ONE_BASED - by default the divisor is the value read from the + * register plus one. If CLK_DIVIDER_ONE_BASED is set then the divider is + * the raw value read from the register, with the value of zero considered +- * invalid ++ * invalid, unless CLK_DIVIDER_ALLOW_ZERO is set. + * CLK_DIVIDER_POWER_OF_TWO - clock divisor is 2 raised to the value read from + * the hardware register ++ * CLK_DIVIDER_ALLOW_ZERO - Allow zero divisors. For dividers which have ++ * CLK_DIVIDER_ONE_BASED set, it is possible to end up with a zero divisor. ++ * Some hardware implementations gracefully handle this case and allow a ++ * zero divisor by not modifying their input clock ++ * (divide by one / bypass). + */ + struct clk_divider { + struct clk_hw hw; +@@ -255,6 +260,7 @@ struct clk_divider { + + #define CLK_DIVIDER_ONE_BASED BIT(0) + #define CLK_DIVIDER_POWER_OF_TWO BIT(1) ++#define CLK_DIVIDER_ALLOW_ZERO BIT(2) + + extern const struct clk_ops clk_divider_ops; + struct clk *clk_register_divider(struct device *dev, const char *name, +diff --git a/include/linux/clk.h b/include/linux/clk.h +index b3ac22d..8272201 100644 +--- a/include/linux/clk.h ++++ b/include/linux/clk.h +@@ -28,16 +28,16 @@ struct clk; + * PRE_RATE_CHANGE - called immediately before the clk rate is changed, + * to indicate that the rate change will proceed. Drivers must + * immediately terminate any operations that will be affected by the +- * rate change. Callbacks may either return NOTIFY_DONE or +- * NOTIFY_STOP. ++ * rate change. Callbacks may either return NOTIFY_DONE, NOTIFY_OK, ++ * NOTIFY_STOP or NOTIFY_BAD. + * + * ABORT_RATE_CHANGE: called if the rate change failed for some reason + * after PRE_RATE_CHANGE. In this case, all registered notifiers on + * the clk will be called with ABORT_RATE_CHANGE. Callbacks must +- * always return NOTIFY_DONE. ++ * always return NOTIFY_DONE or NOTIFY_OK. + * + * POST_RATE_CHANGE - called after the clk rate change has successfully +- * completed. Callbacks must always return NOTIFY_DONE. ++ * completed. Callbacks must always return NOTIFY_DONE or NOTIFY_OK. + * + */ + #define PRE_RATE_CHANGE BIT(0) +@@ -224,15 +224,25 @@ void devm_clk_put(struct device *dev, struct clk *clk); + + + /** +- * clk_round_rate - adjust a rate to the exact rate a clock can provide ++ * clk_round_rate - round a rate to the exact rate a clock can provide not ++ * exceeding @rate + * @clk: clock source + * @rate: desired clock rate in Hz + * +- * Returns rounded clock rate in Hz, or negative errno. ++ * Returns rounded clock rate in Hz, or parent rate + */ + long clk_round_rate(struct clk *clk, unsigned long rate); + + /** ++ * clk_round_rate_nearest - round a rate to the exact rate a clock can provide ++ * @clk: the clk for which we are rounding a rate ++ * @rate: the rate which is to be rounded ++ * ++ * Returns rounded clock rate in Hz, or parent rate ++ */ ++long clk_round_rate_nearest(struct clk *clk, unsigned long rate); ++ ++/** + * clk_set_rate - set the clock rate for a clock source + * @clk: clock source + * @rate: desired clock rate in Hz +diff --git a/include/linux/clk/zynq.h b/include/linux/clk/zynq.h +index a501169..d9718ee 100644 +--- a/include/linux/clk/zynq.h ++++ b/include/linux/clk/zynq.h +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2012 Xilinx ++ * Copyright (C) 2012 - 2013 Xilinx + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and +@@ -14,26 +14,16 @@ + #ifndef __LINUX_CLK_ZYNQ_H_ + #define __LINUX_CLK_ZYNQ_H_ + +-void __init zynq_clock_init(void __iomem *slcr); ++#include + +-struct clk *clk_register_zynq_gd1m(const char *name, +- void __iomem *clkctrl, const char **pnames, +- spinlock_t *lock); +-struct clk *clk_register_zynq_gd2m(const char *name, +- void __iomem *clkctrl, const char **pnames, u8 num_parents, +- spinlock_t *lock); +-struct clk *clk_register_zynq_d2m(const char *name, +- void __iomem *clkctrl, const char **pnames, spinlock_t *lock); +-struct clk *clk_register_zynq_d1m(const char *name, +- void __iomem *clkctrl, const char **pnames, u8 num_parents, +- spinlock_t *lock); ++extern unsigned int zynq_clk_suspended; + +-struct clk *clk_register_zynq_clk621(const char *name, +- void __iomem *clkctrl, void __iomem *clk621, +- unsigned int basediv, +- unsigned int divadd, const char **pnames, u8 num_parents, +- spinlock_t *lock); ++void zynq_clock_init(void __iomem *slcr); ++int zynq_clk_suspend_early(void); ++void zynq_clk_resume_late(void); + +-//void __init xilinx_zynq_clocks_init(void __iomem *slcr); ++struct clk *clk_register_zynq_pll(const char *name, const char *parent, ++ void __iomem *pll_ctrl, void __iomem *pll_status, u8 lock_index, ++ spinlock_t *lock); + + #endif +diff --git a/include/linux/fs.h b/include/linux/fs.h +index 1a39c33..7617ee0 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -2551,7 +2551,6 @@ extern int inode_change_ok(const struct inode *, struct iattr *); + extern int inode_newsize_ok(const struct inode *, loff_t offset); + extern void setattr_copy(struct inode *inode, const struct iattr *attr); + +-extern int update_time(struct inode *, struct timespec *, int); + extern int file_update_time(struct file *file); + + extern int generic_show_options(struct seq_file *m, struct dentry *root); +diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h +index db695d5..0c80d3f 100644 +--- a/include/linux/hugetlb.h ++++ b/include/linux/hugetlb.h +@@ -185,7 +185,8 @@ static inline struct hugetlbfs_sb_info *HUGETLBFS_SB(struct super_block *sb) + + extern const struct file_operations hugetlbfs_file_operations; + extern const struct vm_operations_struct hugetlb_vm_ops; +-struct file *hugetlb_file_setup(const char *name, size_t size, vm_flags_t acct, ++struct file *hugetlb_file_setup(const char *name, unsigned long addr, ++ size_t size, vm_flags_t acct, + struct user_struct **user, int creat_flags, + int page_size_log); + +@@ -204,8 +205,8 @@ static inline int is_file_hugepages(struct file *file) + + #define is_file_hugepages(file) 0 + static inline struct file * +-hugetlb_file_setup(const char *name, size_t size, vm_flags_t acctflag, +- struct user_struct **user, int creat_flags, ++hugetlb_file_setup(const char *name, unsigned long addr, size_t size, ++ vm_flags_t acctflag, struct user_struct **user, int creat_flags, + int page_size_log) + { + return ERR_PTR(-ENOSYS); +@@ -283,13 +284,6 @@ static inline struct hstate *hstate_file(struct file *f) + return hstate_inode(f->f_dentry->d_inode); + } + +-static inline struct hstate *hstate_sizelog(int page_size_log) +-{ +- if (!page_size_log) +- return &default_hstate; +- return size_to_hstate(1 << page_size_log); +-} +- + static inline struct hstate *hstate_vma(struct vm_area_struct *vma) + { + return hstate_file(vma->vm_file); +@@ -354,12 +348,11 @@ static inline int hstate_index(struct hstate *h) + return h - hstates; + } + +-#else /* CONFIG_HUGETLB_PAGE */ ++#else + struct hstate {}; + #define alloc_huge_page_node(h, nid) NULL + #define alloc_bootmem_huge_page(h) NULL + #define hstate_file(f) NULL +-#define hstate_sizelog(s) NULL + #define hstate_vma(v) NULL + #define hstate_inode(i) NULL + #define huge_page_size(h) PAGE_SIZE +@@ -374,6 +367,6 @@ static inline unsigned int pages_per_huge_page(struct hstate *h) + } + #define hstate_index_to_shift(index) 0 + #define hstate_index(h) 0 +-#endif /* CONFIG_HUGETLB_PAGE */ ++#endif + + #endif /* _LINUX_HUGETLB_H */ +diff --git a/include/linux/ipc_namespace.h b/include/linux/ipc_namespace.h +index c4d870b..ae221a7 100644 +--- a/include/linux/ipc_namespace.h ++++ b/include/linux/ipc_namespace.h +@@ -43,8 +43,8 @@ struct ipc_namespace { + + size_t shm_ctlmax; + size_t shm_ctlall; +- unsigned long shm_tot; + int shm_ctlmni; ++ int shm_tot; + /* + * Defines whether IPC_RMID is forced for _all_ shm segments regardless + * of shmctl() +diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h +index 383bef0..e30b663 100644 +--- a/include/linux/jbd2.h ++++ b/include/linux/jbd2.h +@@ -498,7 +498,6 @@ struct transaction_s + T_COMMIT, + T_COMMIT_DFLUSH, + T_COMMIT_JFLUSH, +- T_COMMIT_CALLBACK, + T_FINISHED + } t_state; + +@@ -1211,7 +1210,6 @@ int __jbd2_log_start_commit(journal_t *journal, tid_t tid); + int jbd2_journal_start_commit(journal_t *journal, tid_t *tid); + int jbd2_journal_force_commit_nested(journal_t *journal); + int jbd2_log_wait_commit(journal_t *journal, tid_t tid); +-int jbd2_complete_transaction(journal_t *journal, tid_t tid); + int jbd2_log_do_checkpoint(journal_t *journal); + int jbd2_trans_will_send_data_barrier(journal_t *journal, tid_t tid); + +diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h +index 25ce88d..f8f5162 100644 +--- a/include/linux/mm_types.h ++++ b/include/linux/mm_types.h +@@ -212,7 +212,6 @@ struct vm_region { + unsigned long vm_top; /* region allocated to here */ + unsigned long vm_pgoff; /* the offset in vm_file corresponding to vm_start */ + struct file *vm_file; /* the backing file or NULL */ +- struct file *vm_prfile; /* the virtual backing file or NULL */ + + int vm_usage; /* region usage count (access under nommu_region_sem) */ + bool vm_icache_flushed : 1; /* true if the icache has been flushed for +@@ -281,7 +280,6 @@ struct vm_area_struct { + unsigned long vm_pgoff; /* Offset (within vm_file) in PAGE_SIZE + units, *not* PAGE_CACHE_SIZE */ + struct file * vm_file; /* File we map to (can be NULL). */ +- struct file *vm_prfile; /* shadow of vm_file */ + void * vm_private_data; /* was vm_pte (shared mem) */ + + #ifndef CONFIG_MMU +diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h +index 7759fcc..6c6ed15 100644 +--- a/include/linux/nfs_fs_sb.h ++++ b/include/linux/nfs_fs_sb.h +@@ -53,7 +53,6 @@ struct nfs_client { + + u32 cl_minorversion;/* NFSv4 minorversion */ + struct rpc_cred *cl_machine_cred; +- int nfs_prog; + + #if IS_ENABLED(CONFIG_NFS_V4) + u64 cl_clientid; /* constant */ +@@ -75,9 +74,7 @@ struct nfs_client { + * This is used to generate the mv0 callback address. + */ + char cl_ipaddr[48]; +- + u32 cl_cb_ident; /* v4.0 callback identifier */ +- + const struct nfs4_minor_version_ops *cl_mvops; + + /* The sequence id to use for the next CREATE_SESSION */ +diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h +index ceb9ca9..29adb12 100644 +--- a/include/linux/nfs_xdr.h ++++ b/include/linux/nfs_xdr.h +@@ -11,7 +11,7 @@ + * reasonable for NFS over UDP. + */ + #define NFS_MAX_FILE_IO_SIZE (1048576U) +-#define NFS_DEF_FILE_IO_SIZE CONFIG_NFS_DEF_FILE_IO_SIZE ++#define NFS_DEF_FILE_IO_SIZE (4096U) + #define NFS_MIN_FILE_IO_SIZE (1024U) + + /* Forward declaration for NFS v3 */ +diff --git a/include/linux/sched.h b/include/linux/sched.h +index f5ad26e..7e49270 100644 +--- a/include/linux/sched.h ++++ b/include/linux/sched.h +@@ -2486,18 +2486,27 @@ static inline void threadgroup_change_end(struct task_struct *tsk) + * + * Lock the threadgroup @tsk belongs to. No new task is allowed to enter + * and member tasks aren't allowed to exit (as indicated by PF_EXITING) or +- * change ->group_leader/pid. This is useful for cases where the threadgroup +- * needs to stay stable across blockable operations. ++ * perform exec. This is useful for cases where the threadgroup needs to ++ * stay stable across blockable operations. + * + * fork and exit paths explicitly call threadgroup_change_{begin|end}() for + * synchronization. While held, no new task will be added to threadgroup + * and no existing live task will have its PF_EXITING set. + * +- * de_thread() does threadgroup_change_{begin|end}() when a non-leader +- * sub-thread becomes a new leader. ++ * During exec, a task goes and puts its thread group through unusual ++ * changes. After de-threading, exclusive access is assumed to resources ++ * which are usually shared by tasks in the same group - e.g. sighand may ++ * be replaced with a new one. Also, the exec'ing task takes over group ++ * leader role including its pid. Exclude these changes while locked by ++ * grabbing cred_guard_mutex which is used to synchronize exec path. + */ + static inline void threadgroup_lock(struct task_struct *tsk) + { ++ /* ++ * exec uses exit for de-threading nesting group_rwsem inside ++ * cred_guard_mutex. Grab cred_guard_mutex first. ++ */ ++ mutex_lock(&tsk->signal->cred_guard_mutex); + down_write(&tsk->signal->group_rwsem); + } + +@@ -2510,6 +2519,7 @@ static inline void threadgroup_lock(struct task_struct *tsk) + static inline void threadgroup_unlock(struct task_struct *tsk) + { + up_write(&tsk->signal->group_rwsem); ++ mutex_unlock(&tsk->signal->cred_guard_mutex); + } + #else + static inline void threadgroup_change_begin(struct task_struct *tsk) {} +diff --git a/include/linux/socket.h b/include/linux/socket.h +index 8602fe8..8c67490 100644 +--- a/include/linux/socket.h ++++ b/include/linux/socket.h +@@ -178,8 +178,8 @@ struct ucred { + #define AF_CAIF 37 /* CAIF sockets */ + #define AF_ALG 38 /* Algorithm sockets */ + #define AF_NFC 39 /* NFC sockets */ +-#define AF_MAX 40 /* For now.. */ +-#define AF_RPMSG 41 /* Remote-processor messaging */ ++#define AF_RPMSG 40 /* Remote-processor messaging */ ++#define AF_MAX 41 /* For now.. */ + + /* Protocol families, same as address families. */ + #define PF_UNSPEC AF_UNSPEC +diff --git a/include/linux/splice.h b/include/linux/splice.h +index 1ac5727..09a545a 100644 +--- a/include/linux/splice.h ++++ b/include/linux/splice.h +@@ -91,10 +91,4 @@ extern void splice_shrink_spd(struct splice_pipe_desc *); + extern void spd_release_page(struct splice_pipe_desc *, unsigned int); + + extern const struct pipe_buf_operations page_cache_pipe_buf_ops; +- +-extern long do_splice_from(struct pipe_inode_info *pipe, struct file *out, +- loff_t *ppos, size_t len, unsigned int flags); +-extern long do_splice_to(struct file *in, loff_t *ppos, +- struct pipe_inode_info *pipe, size_t len, +- unsigned int flags); + #endif +diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h +index dfb42ca..f841ba4 100644 +--- a/include/sound/emu10k1.h ++++ b/include/sound/emu10k1.h +@@ -1787,7 +1787,6 @@ struct snd_emu10k1 { + unsigned int next_free_voice; + + const struct firmware *firmware; +- const struct firmware *dock_fw; + + #ifdef CONFIG_PM_SLEEP + unsigned int *saved_ptr; +diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild +index 6ba8ced..4e67194 100644 +--- a/include/uapi/linux/Kbuild ++++ b/include/uapi/linux/Kbuild +@@ -56,7 +56,6 @@ header-y += atmppp.h + header-y += atmsap.h + header-y += atmsvc.h + header-y += audit.h +-header-y += aufs_type.h + header-y += auto_fs.h + header-y += auto_fs4.h + header-y += auxvec.h +@@ -418,4 +417,3 @@ header-y += x25.h + header-y += xattr.h + header-y += xfrm.h + header-y += hw_breakpoint.h +-header-y += aufs_type.h +diff --git a/include/uapi/linux/aufs_type.h b/include/uapi/linux/aufs_type.h +deleted file mode 100644 +index 2aba5b2..0000000 +--- a/include/uapi/linux/aufs_type.h ++++ /dev/null +@@ -1,234 +0,0 @@ +-/* +- * Copyright (C) 2005-2013 Junjiro R. Okajima +- * +- * This program, aufs is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-#ifndef __AUFS_TYPE_H__ +-#define __AUFS_TYPE_H__ +- +-#define AUFS_NAME "aufs" +- +-#ifdef __KERNEL__ +-/* +- * define it before including all other headers. +- * sched.h may use pr_* macros before defining "current", so define the +- * no-current version first, and re-define later. +- */ +-#define pr_fmt(fmt) AUFS_NAME " %s:%d: " fmt, __func__, __LINE__ +-#include +-#undef pr_fmt +-#define pr_fmt(fmt) \ +- AUFS_NAME " %s:%d:%.*s[%d]: " fmt, __func__, __LINE__, \ +- (int)sizeof(current->comm), current->comm, current->pid +-#else +-#include +-#include +-#endif /* __KERNEL__ */ +- +-#include +- +-#define AUFS_VERSION "3.8-20130325" +- +-/* todo? move this to linux-2.6.19/include/magic.h */ +-#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's') +- +-/* ---------------------------------------------------------------------- */ +- +-#ifdef CONFIG_AUFS_BRANCH_MAX_127 +-typedef int8_t aufs_bindex_t; +-#define AUFS_BRANCH_MAX 127 +-#else +-typedef int16_t aufs_bindex_t; +-#ifdef CONFIG_AUFS_BRANCH_MAX_511 +-#define AUFS_BRANCH_MAX 511 +-#elif defined(CONFIG_AUFS_BRANCH_MAX_1023) +-#define AUFS_BRANCH_MAX 1023 +-#elif defined(CONFIG_AUFS_BRANCH_MAX_32767) +-#define AUFS_BRANCH_MAX 32767 +-#endif +-#endif +- +-#ifdef __KERNEL__ +-#ifndef AUFS_BRANCH_MAX +-#error unknown CONFIG_AUFS_BRANCH_MAX value +-#endif +-#endif /* __KERNEL__ */ +- +-/* ---------------------------------------------------------------------- */ +- +-#define AUFS_FSTYPE AUFS_NAME +- +-#define AUFS_ROOT_INO 2 +-#define AUFS_FIRST_INO 11 +- +-#define AUFS_WH_PFX ".wh." +-#define AUFS_WH_PFX_LEN ((int)sizeof(AUFS_WH_PFX) - 1) +-#define AUFS_WH_TMP_LEN 4 +-/* a limit for rmdir/rename a dir */ +-#define AUFS_MAX_NAMELEN (NAME_MAX \ +- - AUFS_WH_PFX_LEN * 2 /* doubly whiteouted */\ +- - 1 /* dot */\ +- - AUFS_WH_TMP_LEN) /* hex */ +-#define AUFS_XINO_FNAME "." AUFS_NAME ".xino" +-#define AUFS_XINO_DEFPATH "/tmp/" AUFS_XINO_FNAME +-#define AUFS_XINO_TRUNC_INIT 64 /* blocks */ +-#define AUFS_XINO_TRUNC_STEP 4 /* blocks */ +-#define AUFS_DIRWH_DEF 3 +-#define AUFS_RDCACHE_DEF 10 /* seconds */ +-#define AUFS_RDCACHE_MAX 3600 /* seconds */ +-#define AUFS_RDBLK_DEF 512 /* bytes */ +-#define AUFS_RDHASH_DEF 32 +-#define AUFS_WKQ_NAME AUFS_NAME "d" +-#define AUFS_MFS_DEF_SEC 30 /* seconds */ +-#define AUFS_MFS_MAX_SEC 3600 /* seconds */ +-#define AUFS_PLINK_WARN 100 /* number of plinks */ +- +-/* pseudo-link maintenace under /proc */ +-#define AUFS_PLINK_MAINT_NAME "plink_maint" +-#define AUFS_PLINK_MAINT_DIR "fs/" AUFS_NAME +-#define AUFS_PLINK_MAINT_PATH AUFS_PLINK_MAINT_DIR "/" AUFS_PLINK_MAINT_NAME +- +-#define AUFS_DIROPQ_NAME AUFS_WH_PFX ".opq" /* whiteouted doubly */ +-#define AUFS_WH_DIROPQ AUFS_WH_PFX AUFS_DIROPQ_NAME +- +-#define AUFS_BASE_NAME AUFS_WH_PFX AUFS_NAME +-#define AUFS_PLINKDIR_NAME AUFS_WH_PFX "plnk" +-#define AUFS_ORPHDIR_NAME AUFS_WH_PFX "orph" +- +-/* doubly whiteouted */ +-#define AUFS_WH_BASE AUFS_WH_PFX AUFS_BASE_NAME +-#define AUFS_WH_PLINKDIR AUFS_WH_PFX AUFS_PLINKDIR_NAME +-#define AUFS_WH_ORPHDIR AUFS_WH_PFX AUFS_ORPHDIR_NAME +- +-/* branch permissions and attributes */ +-#define AUFS_BRPERM_RW "rw" +-#define AUFS_BRPERM_RO "ro" +-#define AUFS_BRPERM_RR "rr" +-#define AUFS_BRRATTR_WH "wh" +-#define AUFS_BRWATTR_NLWH "nolwh" +- +-/* ---------------------------------------------------------------------- */ +- +-/* ioctl */ +-enum { +- /* readdir in userspace */ +- AuCtl_RDU, +- AuCtl_RDU_INO, +- +- /* pathconf wrapper */ +- AuCtl_WBR_FD, +- +- /* busy inode */ +- AuCtl_IBUSY +-}; +- +-/* borrowed from linux/include/linux/kernel.h */ +-#ifndef ALIGN +-#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1) +-#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask)) +-#endif +- +-/* borrowed from linux/include/linux/compiler-gcc3.h */ +-#ifndef __aligned +-#define __aligned(x) __attribute__((aligned(x))) +-#endif +- +-#ifdef __KERNEL__ +-#ifndef __packed +-#define __packed __attribute__((packed)) +-#endif +-#endif +- +-struct au_rdu_cookie { +- uint64_t h_pos; +- int16_t bindex; +- uint8_t flags; +- uint8_t pad; +- uint32_t generation; +-} __aligned(8); +- +-struct au_rdu_ent { +- uint64_t ino; +- int16_t bindex; +- uint8_t type; +- uint8_t nlen; +- uint8_t wh; +- char name[0]; +-} __aligned(8); +- +-static inline int au_rdu_len(int nlen) +-{ +- /* include the terminating NULL */ +- return ALIGN(sizeof(struct au_rdu_ent) + nlen + 1, +- sizeof(uint64_t)); +-} +- +-union au_rdu_ent_ul { +- struct au_rdu_ent __user *e; +- uint64_t ul; +-}; +- +-enum { +- AufsCtlRduV_SZ, +- AufsCtlRduV_End +-}; +- +-struct aufs_rdu { +- /* input */ +- union { +- uint64_t sz; /* AuCtl_RDU */ +- uint64_t nent; /* AuCtl_RDU_INO */ +- }; +- union au_rdu_ent_ul ent; +- uint16_t verify[AufsCtlRduV_End]; +- +- /* input/output */ +- uint32_t blk; +- +- /* output */ +- union au_rdu_ent_ul tail; +- /* number of entries which were added in a single call */ +- uint64_t rent; +- uint8_t full; +- uint8_t shwh; +- +- struct au_rdu_cookie cookie; +-} __aligned(8); +- +-/* ---------------------------------------------------------------------- */ +- +-struct aufs_wbr_fd { +- uint32_t oflags; +- int16_t brid; +-} __aligned(8); +- +-/* ---------------------------------------------------------------------- */ +- +-struct aufs_ibusy { +- uint64_t ino, h_ino; +- int16_t bindex; +-} __aligned(8); +- +-/* ---------------------------------------------------------------------- */ +- +-#define AuCtlType 'A' +-#define AUFS_CTL_RDU _IOWR(AuCtlType, AuCtl_RDU, struct aufs_rdu) +-#define AUFS_CTL_RDU_INO _IOWR(AuCtlType, AuCtl_RDU_INO, struct aufs_rdu) +-#define AUFS_CTL_WBR_FD _IOW(AuCtlType, AuCtl_WBR_FD, \ +- struct aufs_wbr_fd) +-#define AUFS_CTL_IBUSY _IOWR(AuCtlType, AuCtl_IBUSY, struct aufs_ibusy) +- +-#endif /* __AUFS_TYPE_H__ */ +diff --git a/include/uapi/linux/msdos_fs.h b/include/uapi/linux/msdos_fs.h +index f74f157..996719f 100644 +--- a/include/uapi/linux/msdos_fs.h ++++ b/include/uapi/linux/msdos_fs.h +@@ -45,7 +45,6 @@ + + #define CASE_LOWER_BASE 8 /* base is lower case */ + #define CASE_LOWER_EXT 16 /* extension is lower case */ +-#define FAT_NO_83NAME 32 /* no 8.3 short filename for this file */ + + #define DELETED_FLAG 0xe5 /* marks file as deleted when in name[0] */ + #define IS_FREE(n) (!*(n) || *(n) == DELETED_FLAG) +diff --git a/include/uapi/linux/nfs_mount.h b/include/uapi/linux/nfs_mount.h +index 9541d71..576bddd 100644 +--- a/include/uapi/linux/nfs_mount.h ++++ b/include/uapi/linux/nfs_mount.h +@@ -20,7 +20,7 @@ + * mount-to-kernel version compatibility. Some of these aren't used yet + * but here they are anyway. + */ +-#define NFS_MOUNT_VERSION 7 ++#define NFS_MOUNT_VERSION 6 + #define NFS_MAX_CONTEXT_LEN 256 + + struct nfs_mount_data { +@@ -43,8 +43,6 @@ struct nfs_mount_data { + struct nfs3_fh root; /* 4 */ + int pseudoflavor; /* 5 */ + char context[NFS_MAX_CONTEXT_LEN + 1]; /* 6 */ +- int nfs_prog; /* 7 */ +- int mount_prog; /* 7 */ + }; + + /* bits in the flags field visible to user space */ +diff --git a/init/Kconfig b/init/Kconfig +index e4ed683e..be8b7f5 100644 +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1203,31 +1203,6 @@ menuconfig EXPERT + config HAVE_UID16 + bool + +-config UPTIME_LIMITED_KERNEL +- bool "Create a kernel with uptime limitations" +- default n +- help +- Limit the amount of time a kernel can run. The associated UPTIME_LIMIT* +- kernel config options should be used to tune the behaviour. +- +-config UPTIME_LIMIT_DURATION +- int "Kernel uptime limit in minutes" +- depends on UPTIME_LIMITED_KERNEL +- range 0 14400 +- default 0 +- help +- Define the uptime limitation on a kernel in minutes. Once +- the defined time expires the kernel will emit a warning, cease +- to be usable and eventually restart. The valid range is 0 (disable) +- to 14400 (10 days) +- +-config UPTIME_LIMIT_KERNEL_REBOOT +- bool "Reboot a time limited kernel at expiration" +- depends on UPTIME_LIMITED_KERNEL +- default y +- help +- Reboot an uptime limited kernel at expiration. +- + config UID16 + bool "Enable 16-bit UID system calls" if EXPERT + depends on HAVE_UID16 +diff --git a/init/do_mounts.c b/init/do_mounts.c +index f6358b6..1d1b634 100644 +--- a/init/do_mounts.c ++++ b/init/do_mounts.c +@@ -412,9 +412,7 @@ retry: + printk("DEBUG_BLOCK_EXT_DEVT is enabled, you need to specify " + "explicit textual name for \"root=\" boot option.\n"); + #endif +- printk(KERN_EMERG "VFS: Unable to mount root fs on %s\n", b); +- printk(KERN_EMERG "User configuration error - no valid root filesystem found\n"); +- panic("Invalid configuration from end user prevents continuing"); ++ panic("VFS: Unable to mount root fs on %s", b); + } + + printk("List of all partitions:\n"); +@@ -426,9 +424,7 @@ retry: + #ifdef CONFIG_BLOCK + __bdevname(ROOT_DEV, b); + #endif +- printk(KERN_EMERG "VFS: Unable to mount root fs on %s\n", b); +- printk(KERN_EMERG "User configuration error - no valid root filesystem found\n"); +- panic("Invalid configuration from end user prevents continuing"); ++ panic("VFS: Unable to mount root fs on %s", b); + out: + put_page(page); + } +diff --git a/init/main.c b/init/main.c +index 0805741..cee4b5c 100644 +--- a/init/main.c ++++ b/init/main.c +@@ -847,7 +847,6 @@ static int __ref kernel_init(void *unused) + + static noinline void __init kernel_init_freeable(void) + { +- struct stat console_stat; + /* + * Wait until kthreadd is all set-up. + */ +@@ -877,12 +876,6 @@ static noinline void __init kernel_init_freeable(void) + + do_basic_setup(); + +- /* Use /dev/console to infer if the rootfs is setup properly */ +- if (sys_newlstat((char __user *) "/dev/console", (struct stat __user *) &console_stat) +- || !S_ISCHR(console_stat.st_mode)) { +- panic("/dev/console is missing or not a character device!\nPlease ensure your rootfs is properly configured\n"); +- } +- + /* Open the /dev/console on the rootfs, this should never fail */ + if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0) + printk(KERN_WARNING "Warning: unable to open an initial console.\n"); +diff --git a/ipc/shm.c b/ipc/shm.c +index 9ec2316..4fa6d8f 100644 +--- a/ipc/shm.c ++++ b/ipc/shm.c +@@ -462,7 +462,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) + size_t size = params->u.size; + int error; + struct shmid_kernel *shp; +- size_t numpages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; ++ int numpages = (size + PAGE_SIZE -1) >> PAGE_SHIFT; + struct file * file; + char name[13]; + int id; +@@ -491,14 +491,10 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) + + sprintf (name, "SYSV%08x", key); + if (shmflg & SHM_HUGETLB) { +- struct hstate *hs = hstate_sizelog((shmflg >> SHM_HUGE_SHIFT) +- & SHM_HUGE_MASK); +- size_t hugesize = ALIGN(size, huge_page_size(hs)); +- + /* hugetlb_file_setup applies strict accounting */ + if (shmflg & SHM_NORESERVE) + acctflag = VM_NORESERVE; +- file = hugetlb_file_setup(name, hugesize, acctflag, ++ file = hugetlb_file_setup(name, 0, size, acctflag, + &shp->mlock_user, HUGETLB_SHMFS_INODE, + (shmflg >> SHM_HUGE_SHIFT) & SHM_HUGE_MASK); + } else { +diff --git a/kernel/Makefile b/kernel/Makefile +index 324daf7..6c072b6 100644 +--- a/kernel/Makefile ++++ b/kernel/Makefile +@@ -32,7 +32,6 @@ obj-$(CONFIG_FREEZER) += freezer.o + obj-$(CONFIG_PROFILING) += profile.o + obj-$(CONFIG_STACKTRACE) += stacktrace.o + obj-y += time/ +-obj-$(CONFIG_UPTIME_LIMITED_KERNEL) += uptime_limit.o + obj-$(CONFIG_DEBUG_MUTEXES) += mutex-debug.o + obj-$(CONFIG_LOCKDEP) += lockdep.o + ifeq ($(CONFIG_PROC_FS),y) +diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c +index a291aa2..642a89c 100644 +--- a/kernel/audit_tree.c ++++ b/kernel/audit_tree.c +@@ -617,9 +617,9 @@ void audit_trim_trees(void) + } + spin_unlock(&hash_lock); + trim_marked(tree); ++ put_tree(tree); + drop_collected_mounts(root_mnt); + skip_it: +- put_tree(tree); + mutex_lock(&audit_filter_mutex); + } + list_del(&cursor); +diff --git a/kernel/cgroup.c b/kernel/cgroup.c +index cddf1d9..1e23664 100644 +--- a/kernel/cgroup.c ++++ b/kernel/cgroup.c +@@ -162,9 +162,6 @@ struct cfent { + struct list_head node; + struct dentry *dentry; + struct cftype *type; +- +- /* file xattrs */ +- struct simple_xattrs xattrs; + }; + + /* +@@ -911,12 +908,13 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode) + } else { + struct cfent *cfe = __d_cfe(dentry); + struct cgroup *cgrp = dentry->d_parent->d_fsdata; ++ struct cftype *cft = cfe->type; + + WARN_ONCE(!list_empty(&cfe->node) && + cgrp != &cgrp->root->top_cgroup, + "cfe still linked for %s\n", cfe->type->name); +- simple_xattrs_free(&cfe->xattrs); + kfree(cfe); ++ simple_xattrs_free(&cft->xattrs); + } + iput(inode); + } +@@ -2068,7 +2066,7 @@ static int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader) + if (!group) + return -ENOMEM; + /* pre-allocate to guarantee space while iterating in rcu read-side. */ +- retval = flex_array_prealloc(group, 0, group_size, GFP_KERNEL); ++ retval = flex_array_prealloc(group, 0, group_size - 1, GFP_KERNEL); + if (retval) + goto out_free_group_list; + +@@ -2555,7 +2553,7 @@ static struct simple_xattrs *__d_xattrs(struct dentry *dentry) + if (S_ISDIR(dentry->d_inode->i_mode)) + return &__d_cgrp(dentry)->xattrs; + else +- return &__d_cfe(dentry)->xattrs; ++ return &__d_cft(dentry)->xattrs; + } + + static inline int xattr_enabled(struct dentry *dentry) +@@ -2731,6 +2729,8 @@ static int cgroup_add_file(struct cgroup *cgrp, struct cgroup_subsys *subsys, + umode_t mode; + char name[MAX_CGROUP_TYPE_NAMELEN + MAX_CFTYPE_NAME + 2] = { 0 }; + ++ simple_xattrs_init(&cft->xattrs); ++ + if (subsys && !test_bit(ROOT_NOPREFIX, &cgrp->root->flags)) { + strcpy(name, subsys->name); + strcat(name, "."); +@@ -2755,7 +2755,6 @@ static int cgroup_add_file(struct cgroup *cgrp, struct cgroup_subsys *subsys, + cfe->type = (void *)cft; + cfe->dentry = dentry; + dentry->d_fsdata = cfe; +- simple_xattrs_init(&cfe->xattrs); + list_add_tail(&cfe->node, &parent->files); + cfe = NULL; + } +diff --git a/kernel/fork.c b/kernel/fork.c +index 253c12f..5630e52 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -417,8 +417,6 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) + struct address_space *mapping = file->f_mapping; + + get_file(file); +- if (tmp->vm_prfile) +- get_file(tmp->vm_prfile); + if (tmp->vm_flags & VM_DENYWRITE) + atomic_dec(&inode->i_writecount); + mutex_lock(&mapping->i_mmap_mutex); +diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c +index 60f7e32..e4cee8d 100644 +--- a/kernel/hrtimer.c ++++ b/kernel/hrtimer.c +@@ -298,10 +298,6 @@ ktime_t ktime_sub_ns(const ktime_t kt, u64 nsec) + } else { + unsigned long rem = do_div(nsec, NSEC_PER_SEC); + +- /* Make sure nsec fits into long */ +- if (unlikely(nsec > KTIME_SEC_MAX)) +- return (ktime_t){ .tv64 = KTIME_MAX }; +- + tmp = ktime_set((long)nsec, rem); + } + +@@ -1312,8 +1308,6 @@ retry: + + expires = ktime_sub(hrtimer_get_expires(timer), + base->offset); +- if (expires.tv64 < 0) +- expires.tv64 = KTIME_MAX; + if (expires.tv64 < expires_next.tv64) + expires_next = expires; + break; +diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c +index 93f8e8f..0d095dc 100644 +--- a/kernel/rcutree_trace.c ++++ b/kernel/rcutree_trace.c +@@ -97,7 +97,7 @@ static const struct file_operations rcubarrier_fops = { + .open = rcubarrier_open, + .read = seq_read, + .llseek = no_llseek, +- .release = single_release, ++ .release = seq_release, + }; + + #ifdef CONFIG_RCU_BOOST +@@ -208,7 +208,7 @@ static const struct file_operations rcuexp_fops = { + .open = rcuexp_open, + .read = seq_read, + .llseek = no_llseek, +- .release = single_release, ++ .release = seq_release, + }; + + #ifdef CONFIG_RCU_BOOST +@@ -308,7 +308,7 @@ static const struct file_operations rcuhier_fops = { + .open = rcuhier_open, + .read = seq_read, + .llseek = no_llseek, +- .release = single_release, ++ .release = seq_release, + }; + + static void show_one_rcugp(struct seq_file *m, struct rcu_state *rsp) +@@ -350,7 +350,7 @@ static const struct file_operations rcugp_fops = { + .open = rcugp_open, + .read = seq_read, + .llseek = no_llseek, +- .release = single_release, ++ .release = seq_release, + }; + + static void print_one_rcu_pending(struct seq_file *m, struct rcu_data *rdp) +diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c +index 239a323..a13987a 100644 +--- a/kernel/time/tick-broadcast.c ++++ b/kernel/time/tick-broadcast.c +@@ -66,8 +66,6 @@ static void tick_broadcast_start_periodic(struct clock_event_device *bc) + */ + int tick_check_broadcast_device(struct clock_event_device *dev) + { +- struct clock_event_device *cur = tick_broadcast_device.evtdev; +- + if ((dev->features & CLOCK_EVT_FEAT_DUMMY) || + (tick_broadcast_device.evtdev && + tick_broadcast_device.evtdev->rating >= dev->rating) || +@@ -75,8 +73,6 @@ int tick_check_broadcast_device(struct clock_event_device *dev) + return 0; + + clockevents_exchange_device(tick_broadcast_device.evtdev, dev); +- if (cur) +- cur->event_handler = clockevents_handle_noop; + tick_broadcast_device.evtdev = dev; + if (!cpumask_empty(tick_get_broadcast_mask())) + tick_broadcast_start_periodic(dev); +diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c +index 7076b3f..b1600a6 100644 +--- a/kernel/time/tick-common.c ++++ b/kernel/time/tick-common.c +@@ -323,7 +323,6 @@ static void tick_shutdown(unsigned int *cpup) + */ + dev->mode = CLOCK_EVT_MODE_UNUSED; + clockevents_exchange_device(dev, NULL); +- dev->event_handler = clockevents_handle_noop; + td->evtdev = NULL; + } + raw_spin_unlock_irqrestore(&tick_device_lock, flags); +diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c +index 03dbc77..35cc3a8 100644 +--- a/kernel/trace/ftrace.c ++++ b/kernel/trace/ftrace.c +@@ -650,7 +650,7 @@ int ftrace_profile_pages_init(struct ftrace_profile_stat *stat) + + pages = DIV_ROUND_UP(functions, PROFILES_PER_PAGE); + +- for (i = 1; i < pages; i++) { ++ for (i = 0; i < pages; i++) { + pg->next = (void *)get_zeroed_page(GFP_KERNEL); + if (!pg->next) + goto out_free; +@@ -3714,8 +3714,7 @@ out: + if (fail) + return -EINVAL; + +- ftrace_graph_filter_enabled = !!(*idx); +- ++ ftrace_graph_filter_enabled = 1; + return 0; + } + +diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c +index 55a9d05..fe1d581 100644 +--- a/kernel/trace/trace.c ++++ b/kernel/trace/trace.c +@@ -4885,8 +4885,6 @@ static __init int tracer_init_debugfs(void) + trace_access_lock_init(); + + d_tracer = tracing_init_dentry(); +- if (!d_tracer) +- return 0; + + trace_create_file("trace_options", 0644, d_tracer, + NULL, &tracing_iter_fops); +@@ -5020,32 +5018,36 @@ void trace_init_global_iter(struct trace_iterator *iter) + iter->cpu_file = TRACE_PIPE_ALL_CPU; + } + +-void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) ++static void ++__ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode) + { ++ static arch_spinlock_t ftrace_dump_lock = ++ (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; + /* use static because iter can be a bit big for the stack */ + static struct trace_iterator iter; +- static atomic_t dump_running; + unsigned int old_userobj; ++ static int dump_ran; + unsigned long flags; + int cnt = 0, cpu; + +- /* Only allow one dump user at a time. */ +- if (atomic_inc_return(&dump_running) != 1) { +- atomic_dec(&dump_running); +- return; +- } ++ /* only one dump */ ++ local_irq_save(flags); ++ arch_spin_lock(&ftrace_dump_lock); ++ if (dump_ran) ++ goto out; ++ ++ dump_ran = 1; + +- /* +- * Always turn off tracing when we dump. +- * We don't need to show trace output of what happens +- * between multiple crashes. +- * +- * If the user does a sysrq-z, then they can re-enable +- * tracing with echo 1 > tracing_on. +- */ + tracing_off(); + +- local_irq_save(flags); ++ /* Did function tracer already get disabled? */ ++ if (ftrace_is_dead()) { ++ printk("# WARNING: FUNCTION TRACING IS CORRUPTED\n"); ++ printk("# MAY BE MISSING FUNCTION EVENTS\n"); ++ } ++ ++ if (disable_tracing) ++ ftrace_kill(); + + trace_init_global_iter(&iter); + +@@ -5078,12 +5080,6 @@ void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) + + printk(KERN_TRACE "Dumping ftrace buffer:\n"); + +- /* Did function tracer already get disabled? */ +- if (ftrace_is_dead()) { +- printk("# WARNING: FUNCTION TRACING IS CORRUPTED\n"); +- printk("# MAY BE MISSING FUNCTION EVENTS\n"); +- } +- + /* + * We need to stop all tracing on all CPUS to read the + * the next buffer. This is a bit expensive, but is +@@ -5123,14 +5119,26 @@ void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) + printk(KERN_TRACE "---------------------------------\n"); + + out_enable: +- trace_flags |= old_userobj; ++ /* Re-enable tracing if requested */ ++ if (!disable_tracing) { ++ trace_flags |= old_userobj; + +- for_each_tracing_cpu(cpu) { +- atomic_dec(&iter.tr->data[cpu]->disabled); ++ for_each_tracing_cpu(cpu) { ++ atomic_dec(&iter.tr->data[cpu]->disabled); ++ } ++ tracing_on(); + } +- atomic_dec(&dump_running); ++ ++ out: ++ arch_spin_unlock(&ftrace_dump_lock); + local_irq_restore(flags); + } ++ ++/* By default: disable tracing after the dump */ ++void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) ++{ ++ __ftrace_dump(true, oops_dump_mode); ++} + EXPORT_SYMBOL_GPL(ftrace_dump); + + __init static int tracer_alloc_buffers(void) +diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c +index 81f6275..5fc7aa5 100644 +--- a/kernel/trace/trace_selftest.c ++++ b/kernel/trace/trace_selftest.c +@@ -702,6 +702,8 @@ trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr) + /* Maximum number of functions to trace before diagnosing a hang */ + #define GRAPH_MAX_FUNC_TEST 100000000 + ++static void ++__ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode); + static unsigned int graph_hang_thresh; + + /* Wrap the real function entry probe to avoid possible hanging */ +@@ -711,11 +713,8 @@ static int trace_graph_entry_watchdog(struct ftrace_graph_ent *trace) + if (unlikely(++graph_hang_thresh > GRAPH_MAX_FUNC_TEST)) { + ftrace_graph_stop(); + printk(KERN_WARNING "BUG: Function graph tracer hang!\n"); +- if (ftrace_dump_on_oops) { +- ftrace_dump(DUMP_ALL); +- /* ftrace_dump() disables tracing */ +- tracing_on(); +- } ++ if (ftrace_dump_on_oops) ++ __ftrace_dump(false, DUMP_ALL); + return 0; + } + +diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c +index b20428c..83a8b5b 100644 +--- a/kernel/trace/trace_stack.c ++++ b/kernel/trace/trace_stack.c +@@ -20,24 +20,13 @@ + + #define STACK_TRACE_ENTRIES 500 + +-#ifdef CC_USING_FENTRY +-# define fentry 1 +-#else +-# define fentry 0 +-#endif +- + static unsigned long stack_dump_trace[STACK_TRACE_ENTRIES+1] = + { [0 ... (STACK_TRACE_ENTRIES)] = ULONG_MAX }; + static unsigned stack_dump_index[STACK_TRACE_ENTRIES]; + +-/* +- * Reserve one entry for the passed in ip. This will allow +- * us to remove most or all of the stack size overhead +- * added by the stack tracer itself. +- */ + static struct stack_trace max_stack_trace = { +- .max_entries = STACK_TRACE_ENTRIES - 1, +- .entries = &stack_dump_trace[1], ++ .max_entries = STACK_TRACE_ENTRIES, ++ .entries = stack_dump_trace, + }; + + static unsigned long max_stack_size; +@@ -50,34 +39,25 @@ static DEFINE_MUTEX(stack_sysctl_mutex); + int stack_tracer_enabled; + static int last_stack_tracer_enabled; + +-static inline void +-check_stack(unsigned long ip, unsigned long *stack) ++static inline void check_stack(void) + { + unsigned long this_size, flags; + unsigned long *p, *top, *start; +- static int tracer_frame; +- int frame_size = ACCESS_ONCE(tracer_frame); + int i; + +- this_size = ((unsigned long)stack) & (THREAD_SIZE-1); ++ this_size = ((unsigned long)&this_size) & (THREAD_SIZE-1); + this_size = THREAD_SIZE - this_size; +- /* Remove the frame of the tracer */ +- this_size -= frame_size; + + if (this_size <= max_stack_size) + return; + + /* we do not handle interrupt stacks yet */ +- if (!object_is_on_stack(stack)) ++ if (!object_is_on_stack(&this_size)) + return; + + local_irq_save(flags); + arch_spin_lock(&max_stack_lock); + +- /* In case another CPU set the tracer_frame on us */ +- if (unlikely(!frame_size)) +- this_size -= tracer_frame; +- + /* a race could have already updated it */ + if (this_size <= max_stack_size) + goto out; +@@ -90,18 +70,10 @@ check_stack(unsigned long ip, unsigned long *stack) + save_stack_trace(&max_stack_trace); + + /* +- * Add the passed in ip from the function tracer. +- * Searching for this on the stack will skip over +- * most of the overhead from the stack tracer itself. +- */ +- stack_dump_trace[0] = ip; +- max_stack_trace.nr_entries++; +- +- /* + * Now find where in the stack these are. + */ + i = 0; +- start = stack; ++ start = &this_size; + top = (unsigned long *) + (((unsigned long)start & ~(THREAD_SIZE-1)) + THREAD_SIZE); + +@@ -125,18 +97,6 @@ check_stack(unsigned long ip, unsigned long *stack) + found = 1; + /* Start the search from here */ + start = p + 1; +- /* +- * We do not want to show the overhead +- * of the stack tracer stack in the +- * max stack. If we haven't figured +- * out what that is, then figure it out +- * now. +- */ +- if (unlikely(!tracer_frame) && i == 1) { +- tracer_frame = (p - stack) * +- sizeof(unsigned long); +- max_stack_size -= tracer_frame; +- } + } + } + +@@ -153,7 +113,6 @@ static void + stack_trace_call(unsigned long ip, unsigned long parent_ip, + struct ftrace_ops *op, struct pt_regs *pt_regs) + { +- unsigned long stack; + int cpu; + + preempt_disable_notrace(); +@@ -163,26 +122,7 @@ stack_trace_call(unsigned long ip, unsigned long parent_ip, + if (per_cpu(trace_active, cpu)++ != 0) + goto out; + +- /* +- * When fentry is used, the traced function does not get +- * its stack frame set up, and we lose the parent. +- * The ip is pretty useless because the function tracer +- * was called before that function set up its stack frame. +- * In this case, we use the parent ip. +- * +- * By adding the return address of either the parent ip +- * or the current ip we can disregard most of the stack usage +- * caused by the stack tracer itself. +- * +- * The function tracer always reports the address of where the +- * mcount call was, but the stack will hold the return address. +- */ +- if (fentry) +- ip = parent_ip; +- else +- ip += MCOUNT_INSN_SIZE; +- +- check_stack(ip, &stack); ++ check_stack(); + + out: + per_cpu(trace_active, cpu)--; +@@ -431,8 +371,6 @@ static __init int stack_trace_init(void) + struct dentry *d_tracer; + + d_tracer = tracing_init_dentry(); +- if (!d_tracer) +- return 0; + + trace_create_file("stack_max_size", 0644, d_tracer, + &max_stack_size, &stack_max_size_fops); +diff --git a/kernel/trace/trace_stat.c b/kernel/trace/trace_stat.c +index 847f88a..96cffb2 100644 +--- a/kernel/trace/trace_stat.c ++++ b/kernel/trace/trace_stat.c +@@ -307,8 +307,6 @@ static int tracing_stat_init(void) + struct dentry *d_tracing; + + d_tracing = tracing_init_dentry(); +- if (!d_tracing) +- return 0; + + stat_dir = debugfs_create_dir("trace_stat", d_tracing); + if (!stat_dir) +diff --git a/kernel/uptime_limit.c b/kernel/uptime_limit.c +deleted file mode 100644 +index b6a1a5e..0000000 +--- a/kernel/uptime_limit.c ++++ /dev/null +@@ -1,166 +0,0 @@ +-/* +- * uptime_limit.c +- * +- * This file contains the functions which can limit kernel uptime +- * +- * Copyright (C) 2011 Bruce Ashfield (bruce.ashfield@windriver.com) +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +- * +- * +- * This functionality is somewhat close to the softdog watchdog +- * implementation, but it cannot be used directly for several reasons: +- * +- * - The soft watchdog should be available while this functionality is active +- * - The duration range is different between this and the softdog. The +- * timeout available here is potentially quite a bit longer. +- * - At expiration, there are different expiration requirements and actions. +- * - This functionality is specific to a particular use case and should +- * not impact mainline functionality +- * +- */ +-#include +-#include +-#include +-#include +-#include +- +-#define UPTIME_LIMIT_IN_SECONDS (CONFIG_UPTIME_LIMIT_DURATION * 60) +-#define MIN(X, Y) ((X) <= (Y) ? (X) : (Y)) +-#define TEN_MINUTES_IN_SECONDS 600 +- +-enum uptime_expiration_type { +- uptime_no_action, +- uptime_reboot +-}; +- +-static enum uptime_expiration_type uptime_expiration_action = uptime_no_action; +-static struct timer_list timelimit_timer; +-static struct task_struct *uptime_worker_task; +- +-static void timelimit_expire(unsigned long timeout_seconds) +-{ +- char msg[128]; +- int msglen = 127; +- +- if (timeout_seconds) { +- if (timeout_seconds >= 60) +- snprintf(msg, msglen, +- "Uptime: kernel validity duration has %d %s remaining\n", +- (int) timeout_seconds / 60, "minute(s)"); +- else +- snprintf(msg, msglen, +- "Uptime: kernel validity duration has %d %s remaining\n", +- (int) timeout_seconds, "seconds"); +- +- printk(KERN_CRIT "%s", msg); +- +- timelimit_timer.expires = jiffies + timeout_seconds * HZ; +- timelimit_timer.data = 0; +- add_timer_on(&timelimit_timer, cpumask_first(cpu_online_mask)); +- } else { +- printk(KERN_CRIT "Uptime: Kernel validity timeout has expired\n"); +-#ifdef CONFIG_UPTIME_LIMIT_KERNEL_REBOOT +- uptime_expiration_action = uptime_reboot; +- wake_up_process(uptime_worker_task); +- } +-#endif +-} +- +-/* +- * This thread starts and then immediately goes to sleep. When it is woken +- * up, it carries out the instructions left in uptime_expiration_action. If +- * no action was specified it simply goes back to sleep. +- */ +-static int uptime_worker(void *unused) +-{ +- set_current_state(TASK_INTERRUPTIBLE); +- +- while (!kthread_should_stop()) { +- schedule(); +- +- if (kthread_should_stop()) +- break; +- +- if (uptime_expiration_action == uptime_reboot) { +- printk(KERN_CRIT "Uptime: restarting machine\n"); +- kernel_restart(NULL); +- } +- +- set_current_state(TASK_INTERRUPTIBLE); +- } +- __set_current_state(TASK_RUNNING); +- +- return 0; +-} +- +-static int timeout_enable(int cpu) +-{ +- int err = 0; +- int warning_limit; +- +- /* +- * Create an uptime worker thread. This thread is required since the +- * safe version of kernel restart cannot be called from a +- * non-interruptible context. Which means we cannot call it directly +- * from a timer callback. So we arrange for the timer expiration to +- * wakeup a thread, which performs the action. +- */ +- uptime_worker_task = kthread_create(uptime_worker, +- (void *)(unsigned long)cpu, +- "uptime_worker/%d", cpu); +- if (IS_ERR(uptime_worker_task)) { +- printk(KERN_ERR "Uptime: task for cpu %i failed\n", cpu); +- err = PTR_ERR(uptime_worker_task); +- goto out; +- } +- /* bind to cpu0 to avoid migration and hot plug nastiness */ +- kthread_bind(uptime_worker_task, cpu); +- wake_up_process(uptime_worker_task); +- +- /* Create the timer that will wake the uptime thread at expiration */ +- init_timer(&timelimit_timer); +- timelimit_timer.function = timelimit_expire; +- /* +- * Fire two timers. One warning timeout and the final timer +- * which will carry out the expiration action. The warning timer will +- * expire at the minimum of half the original time or ten minutes. +- */ +- warning_limit = MIN(UPTIME_LIMIT_IN_SECONDS/2, TEN_MINUTES_IN_SECONDS); +- timelimit_timer.expires = jiffies + warning_limit * HZ; +- timelimit_timer.data = UPTIME_LIMIT_IN_SECONDS - warning_limit; +- +- add_timer_on(&timelimit_timer, cpumask_first(cpu_online_mask)); +-out: +- return err; +-} +- +-static int __init timelimit_init(void) +-{ +- int err = 0; +- +- printk(KERN_INFO "Uptime: system uptime restrictions enabled\n"); +- +- /* +- * Enable the timeout thread for cpu 0 only, assuming that the +- * uptime limit is non-zero, to protect against any cpu +- * migration issues. +- */ +- if (UPTIME_LIMIT_IN_SECONDS) +- err = timeout_enable(0); +- +- return err; +-} +-device_initcall(timelimit_init); +diff --git a/lib/oid_registry.c b/lib/oid_registry.c +index 318f382..d8de11f 100644 +--- a/lib/oid_registry.c ++++ b/lib/oid_registry.c +@@ -9,7 +9,6 @@ + * 2 of the Licence, or (at your option) any later version. + */ + +-#include + #include + #include + #include +@@ -17,10 +16,6 @@ + #include + #include "oid_registry_data.c" + +-MODULE_DESCRIPTION("OID Registry"); +-MODULE_AUTHOR("Red Hat, Inc."); +-MODULE_LICENSE("GPL"); +- + /** + * look_up_OID - Find an OID registration for the specified data + * @data: Binary representation of the OID +diff --git a/mm/memory.c b/mm/memory.c +index e670f1d..32a495a 100644 +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -3421,8 +3421,6 @@ static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma, + /* file_update_time outside page_lock */ + if (vma->vm_file && !page_mkwrite) + file_update_time(vma->vm_file); +- if (vma->vm_prfile && !page_mkwrite) +- file_update_time(vma->vm_prfile); + } else { + unlock_page(vmf.page); + if (anon) +diff --git a/mm/mmap.c b/mm/mmap.c +index e60fbb8..90db251 100644 +--- a/mm/mmap.c ++++ b/mm/mmap.c +@@ -242,8 +242,6 @@ static struct vm_area_struct *remove_vma(struct vm_area_struct *vma) + vma->vm_ops->close(vma); + if (vma->vm_file) + fput(vma->vm_file); +- if (vma->vm_prfile) +- fput(vma->vm_prfile); + mpol_put(vma_policy(vma)); + kmem_cache_free(vm_area_cachep, vma); + return next; +@@ -818,8 +816,6 @@ again: remove_next = 1 + (end > next->vm_end); + if (file) { + uprobe_munmap(next, next->vm_start, next->vm_end); + fput(file); +- if (vma->vm_prfile) +- fput(vma->vm_prfile); + } + if (next->anon_vma) + anon_vma_merge(vma, next); +@@ -1300,20 +1296,15 @@ SYSCALL_DEFINE6(mmap_pgoff, unsigned long, addr, unsigned long, len, + file = fget(fd); + if (!file) + goto out; +- if (is_file_hugepages(file)) +- len = ALIGN(len, huge_page_size(hstate_file(file))); + } else if (flags & MAP_HUGETLB) { + struct user_struct *user = NULL; +- +- len = ALIGN(len, huge_page_size(hstate_sizelog( +- (flags >> MAP_HUGE_SHIFT) & MAP_HUGE_MASK))); + /* + * VM_NORESERVE is used because the reservations will be + * taken when vm_ops->mmap() is called + * A dummy user value is used because we are not locking + * memory so no accounting is necessary + */ +- file = hugetlb_file_setup(HUGETLB_ANON_FILE, len, ++ file = hugetlb_file_setup(HUGETLB_ANON_FILE, addr, len, + VM_NORESERVE, + &user, HUGETLB_ANONHUGE_INODE, + (flags >> MAP_HUGE_SHIFT) & MAP_HUGE_MASK); +@@ -2298,7 +2289,7 @@ static void unmap_region(struct mm_struct *mm, + update_hiwater_rss(mm); + unmap_vmas(&tlb, vma, start, end); + free_pgtables(&tlb, vma, prev ? prev->vm_end : FIRST_USER_ADDRESS, +- next ? next->vm_start : USER_PGTABLES_CEILING); ++ next ? next->vm_start : 0); + tlb_finish_mmu(&tlb, start, end); + } + +@@ -2380,8 +2371,6 @@ static int __split_vma(struct mm_struct * mm, struct vm_area_struct * vma, + + if (new->vm_file) + get_file(new->vm_file); +- if (new->vm_prfile) +- get_file(new->vm_prfile); + + if (new->vm_ops && new->vm_ops->open) + new->vm_ops->open(new); +@@ -2401,8 +2390,6 @@ static int __split_vma(struct mm_struct * mm, struct vm_area_struct * vma, + new->vm_ops->close(new); + if (new->vm_file) + fput(new->vm_file); +- if (new->vm_prfile) +- fput(new->vm_prfile); + unlink_anon_vmas(new); + out_free_mpol: + mpol_put(pol); +@@ -2680,7 +2667,7 @@ void exit_mmap(struct mm_struct *mm) + /* Use -1 here to ensure all VMAs in the mm are unmapped */ + unmap_vmas(&tlb, vma, 0, -1); + +- free_pgtables(&tlb, vma, FIRST_USER_ADDRESS, USER_PGTABLES_CEILING); ++ free_pgtables(&tlb, vma, FIRST_USER_ADDRESS, 0); + tlb_finish_mmu(&tlb, 0, -1); + + /* +@@ -2800,8 +2787,6 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, + goto out_free_mempol; + if (new_vma->vm_file) + get_file(new_vma->vm_file); +- if (new_vma->vm_prfile) +- get_file(new_vma->vm_prfile); + if (new_vma->vm_ops && new_vma->vm_ops->open) + new_vma->vm_ops->open(new_vma); + vma_link(mm, new_vma, prev, rb_link, rb_parent); +diff --git a/mm/nommu.c b/mm/nommu.c +index 6c486d3..bbe1f3f 100644 +--- a/mm/nommu.c ++++ b/mm/nommu.c +@@ -648,8 +648,6 @@ static void __put_nommu_region(struct vm_region *region) + + if (region->vm_file) + fput(region->vm_file); +- if (region->vm_prfile) +- fput(region->vm_prfile); + + /* IO memory and memory shared directly out of the pagecache + * from ramfs/tmpfs mustn't be released here */ +@@ -808,8 +806,6 @@ static void delete_vma(struct mm_struct *mm, struct vm_area_struct *vma) + vma->vm_ops->close(vma); + if (vma->vm_file) + fput(vma->vm_file); +- if (vma->vm_prfile) +- fput(vma->vm_prfile); + put_nommu_region(vma->vm_region); + kmem_cache_free(vm_area_cachep, vma); + } +@@ -1373,8 +1369,6 @@ unsigned long do_mmap_pgoff(struct file *file, + } + } + fput(region->vm_file); +- if (region->vm_prfile) +- fput(region->vm_prfile); + kmem_cache_free(vm_region_jar, region); + region = pregion; + result = start; +@@ -1451,13 +1445,9 @@ error_just_free: + error: + if (region->vm_file) + fput(region->vm_file); +- if (region->vm_prfile) +- fput(region->vm_prfile); + kmem_cache_free(vm_region_jar, region); + if (vma->vm_file) + fput(vma->vm_file); +- if (vma->vm_prfile) +- fput(vma->vm_prfile); + kmem_cache_free(vm_area_cachep, vma); + kleave(" = %d", ret); + return ret; +diff --git a/mm/page_io.c b/mm/page_io.c +index 6182870..78eee32 100644 +--- a/mm/page_io.c ++++ b/mm/page_io.c +@@ -214,7 +214,6 @@ int swap_writepage(struct page *page, struct writeback_control *wbc) + kiocb.ki_left = PAGE_SIZE; + kiocb.ki_nbytes = PAGE_SIZE; + +- set_page_writeback(page); + unlock_page(page); + ret = mapping->a_ops->direct_IO(KERNEL_WRITE, + &kiocb, &iov, +@@ -223,23 +222,7 @@ int swap_writepage(struct page *page, struct writeback_control *wbc) + if (ret == PAGE_SIZE) { + count_vm_event(PSWPOUT); + ret = 0; +- } else { +- /* +- * In the case of swap-over-nfs, this can be a +- * temporary failure if the system has limited +- * memory for allocating transmit buffers. +- * Mark the page dirty and avoid +- * rotate_reclaimable_page but rate-limit the +- * messages but do not flag PageError like +- * the normal direct-to-bio case as it could +- * be temporary. +- */ +- set_page_dirty(page); +- ClearPageReclaim(page); +- pr_err_ratelimited("Write error on dio swapfile (%Lu)\n", +- page_file_offset(page)); + } +- end_page_writeback(page); + return ret; + } + +diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c +index 97cbbaa..ded146b 100644 +--- a/net/ipv4/arp.c ++++ b/net/ipv4/arp.c +@@ -897,14 +897,7 @@ static int arp_process(struct sk_buff *skb) + agents are active. Taking the first reply prevents + arp trashing and chooses the fastest router. + */ +- /* +- * If n->updated is after jiffies, then the clock has wrapped and +- * we are *well* past the locktime, so set the override flag +- */ +- if (time_after(n->updated, jiffies)) +- override = 1; +- else +- override = time_after(jiffies, n->updated + n->parms->locktime); ++ override = time_after(jiffies, n->updated + n->parms->locktime); + + /* Broadcast replies and request packets + do not assert neighbour reachability. +diff --git a/net/ipv4/netfilter/ipt_rpfilter.c b/net/ipv4/netfilter/ipt_rpfilter.c +index c49dcd0..c301300 100644 +--- a/net/ipv4/netfilter/ipt_rpfilter.c ++++ b/net/ipv4/netfilter/ipt_rpfilter.c +@@ -66,12 +66,6 @@ static bool rpfilter_lookup_reverse(struct flowi4 *fl4, + return dev_match; + } + +-static bool rpfilter_is_local(const struct sk_buff *skb) +-{ +- const struct rtable *rt = skb_rtable(skb); +- return rt && (rt->rt_flags & RTCF_LOCAL); +-} +- + static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par) + { + const struct xt_rpfilter_info *info; +@@ -82,7 +76,7 @@ static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par) + info = par->matchinfo; + invert = info->flags & XT_RPFILTER_INVERT; + +- if (rpfilter_is_local(skb)) ++ if (par->in->flags & IFF_LOOPBACK) + return true ^ invert; + + iph = ip_hdr(skb); +diff --git a/net/ipv6/netfilter/ip6t_NPT.c b/net/ipv6/netfilter/ip6t_NPT.c +index 0ea43c7..83acc14 100644 +--- a/net/ipv6/netfilter/ip6t_NPT.c ++++ b/net/ipv6/netfilter/ip6t_NPT.c +@@ -57,7 +57,7 @@ static bool ip6t_npt_map_pfx(const struct ip6t_npt_tginfo *npt, + if (pfx_len - i >= 32) + mask = 0; + else +- mask = htonl((1 << (i - pfx_len + 32)) - 1); ++ mask = htonl(~((1 << (pfx_len - i)) - 1)); + + idx = i / 32; + addr->s6_addr32[idx] &= mask; +diff --git a/net/ipv6/netfilter/ip6t_rpfilter.c b/net/ipv6/netfilter/ip6t_rpfilter.c +index e0983f3..5060d54 100644 +--- a/net/ipv6/netfilter/ip6t_rpfilter.c ++++ b/net/ipv6/netfilter/ip6t_rpfilter.c +@@ -71,12 +71,6 @@ static bool rpfilter_lookup_reverse6(const struct sk_buff *skb, + return ret; + } + +-static bool rpfilter_is_local(const struct sk_buff *skb) +-{ +- const struct rt6_info *rt = (const void *) skb_dst(skb); +- return rt && (rt->rt6i_flags & RTF_LOCAL); +-} +- + static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par) + { + const struct xt_rpfilter_info *info = par->matchinfo; +@@ -84,7 +78,7 @@ static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par) + struct ipv6hdr *iph; + bool invert = info->flags & XT_RPFILTER_INVERT; + +- if (rpfilter_is_local(skb)) ++ if (par->in->flags & IFF_LOOPBACK) + return true ^ invert; + + iph = ipv6_hdr(skb); +diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c +index 64619f4..79a48f3 100644 +--- a/net/mac80211/pm.c ++++ b/net/mac80211/pm.c +@@ -52,8 +52,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) + ieee80211_stop_queues_by_reason(hw, + IEEE80211_QUEUE_STOP_REASON_SUSPEND); + +- /* flush out all packets and station cleanup call_rcu()s */ +- rcu_barrier(); ++ /* flush out all packets */ ++ synchronize_net(); + + drv_flush(local, false); + +diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c +index 38ca630..6d6d8f2 100644 +--- a/net/netfilter/ipset/ip_set_core.c ++++ b/net/netfilter/ipset/ip_set_core.c +@@ -1470,8 +1470,7 @@ ip_set_utest(struct sock *ctnl, struct sk_buff *skb, + if (ret == -EAGAIN) + ret = 1; + +- return (ret < 0 && ret != -ENOTEMPTY) ? ret : +- ret > 0 ? 0 : -IPSET_ERR_EXIST; ++ return ret < 0 ? ret : ret > 0 ? 0 : -IPSET_ERR_EXIST; + } + + /* Get headed data of a set */ +diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c +index 09c744a..8371c2b 100644 +--- a/net/netfilter/ipset/ip_set_list_set.c ++++ b/net/netfilter/ipset/ip_set_list_set.c +@@ -174,13 +174,9 @@ list_set_add(struct list_set *map, u32 i, ip_set_id_t id, + { + const struct set_elem *e = list_set_elem(map, i); + +- if (e->id != IPSET_INVALID_ID) { +- const struct set_elem *x = list_set_elem(map, map->size - 1); +- +- /* Last element replaced or pushed off */ +- if (x->id != IPSET_INVALID_ID) +- ip_set_put_byindex(x->id); +- } ++ if (i == map->size - 1 && e->id != IPSET_INVALID_ID) ++ /* Last element replaced: e.g. add new,before,last */ ++ ip_set_put_byindex(e->id); + if (with_timeout(map->timeout)) + list_elem_tadd(map, i, id, ip_set_timeout_set(timeout)); + else +diff --git a/net/netfilter/ipvs/ip_vs_pe_sip.c b/net/netfilter/ipvs/ip_vs_pe_sip.c +index e5920fb..12475ef 100644 +--- a/net/netfilter/ipvs/ip_vs_pe_sip.c ++++ b/net/netfilter/ipvs/ip_vs_pe_sip.c +@@ -37,10 +37,14 @@ static int get_callid(const char *dptr, unsigned int dataoff, + if (ret > 0) + break; + if (!ret) +- return -EINVAL; ++ return 0; + dataoff += *matchoff; + } + ++ /* Empty callid is useless */ ++ if (!*matchlen) ++ return -EINVAL; ++ + /* Too large is useless */ + if (*matchlen > IP_VS_PEDATA_MAXLEN) + return -EINVAL; +diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c +index 91527d5..884f2b3 100644 +--- a/net/netfilter/nf_conntrack_helper.c ++++ b/net/netfilter/nf_conntrack_helper.c +@@ -236,9 +236,7 @@ int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl, + /* We only allow helper re-assignment of the same sort since + * we cannot reallocate the helper extension area. + */ +- struct nf_conntrack_helper *tmp = rcu_dereference(help->helper); +- +- if (tmp && tmp->help != helper->help) { ++ if (help->helper != helper) { + RCU_INIT_POINTER(help->helper, NULL); + goto out; + } +diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c +index a081915..627b0e5 100644 +--- a/net/netfilter/nf_conntrack_netlink.c ++++ b/net/netfilter/nf_conntrack_netlink.c +@@ -1705,9 +1705,6 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, + if (nlh->nlmsg_flags & NLM_F_CREATE) { + enum ip_conntrack_events events; + +- if (!cda[CTA_TUPLE_ORIG] || !cda[CTA_TUPLE_REPLY]) +- return -EINVAL; +- + ct = ctnetlink_create_conntrack(net, zone, cda, &otuple, + &rtuple, u3); + if (IS_ERR(ct)) +diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c +index b4e0d1c..df8f4f2 100644 +--- a/net/netfilter/nf_conntrack_sip.c ++++ b/net/netfilter/nf_conntrack_sip.c +@@ -1547,7 +1547,7 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff, + + msglen = origlen = end - dptr; + if (msglen > datalen) +- return NF_ACCEPT; ++ return NF_DROP; + + ret = process_sip_msg(skb, ct, protoff, dataoff, + &dptr, &msglen); +diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c +index 4bc2aaf..5f2f910 100644 +--- a/net/netfilter/nf_nat_core.c ++++ b/net/netfilter/nf_nat_core.c +@@ -468,22 +468,33 @@ EXPORT_SYMBOL_GPL(nf_nat_packet); + struct nf_nat_proto_clean { + u8 l3proto; + u8 l4proto; ++ bool hash; + }; + +-/* kill conntracks with affected NAT section */ +-static int nf_nat_proto_remove(struct nf_conn *i, void *data) ++/* Clear NAT section of all conntracks, in case we're loaded again. */ ++static int nf_nat_proto_clean(struct nf_conn *i, void *data) + { + const struct nf_nat_proto_clean *clean = data; + struct nf_conn_nat *nat = nfct_nat(i); + + if (!nat) + return 0; +- ++ if (!(i->status & IPS_SRC_NAT_DONE)) ++ return 0; + if ((clean->l3proto && nf_ct_l3num(i) != clean->l3proto) || + (clean->l4proto && nf_ct_protonum(i) != clean->l4proto)) + return 0; + +- return i->status & IPS_NAT_MASK ? 1 : 0; ++ if (clean->hash) { ++ spin_lock_bh(&nf_nat_lock); ++ hlist_del_rcu(&nat->bysource); ++ spin_unlock_bh(&nf_nat_lock); ++ } else { ++ memset(nat, 0, sizeof(*nat)); ++ i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | ++ IPS_SEQ_ADJUST); ++ } ++ return 0; + } + + static void nf_nat_l4proto_clean(u8 l3proto, u8 l4proto) +@@ -495,8 +506,16 @@ static void nf_nat_l4proto_clean(u8 l3proto, u8 l4proto) + struct net *net; + + rtnl_lock(); ++ /* Step 1 - remove from bysource hash */ ++ clean.hash = true; + for_each_net(net) +- nf_ct_iterate_cleanup(net, nf_nat_proto_remove, &clean); ++ nf_ct_iterate_cleanup(net, nf_nat_proto_clean, &clean); ++ synchronize_rcu(); ++ ++ /* Step 2 - clean NAT section */ ++ clean.hash = false; ++ for_each_net(net) ++ nf_ct_iterate_cleanup(net, nf_nat_proto_clean, &clean); + rtnl_unlock(); + } + +@@ -508,9 +527,16 @@ static void nf_nat_l3proto_clean(u8 l3proto) + struct net *net; + + rtnl_lock(); ++ /* Step 1 - remove from bysource hash */ ++ clean.hash = true; ++ for_each_net(net) ++ nf_ct_iterate_cleanup(net, nf_nat_proto_clean, &clean); ++ synchronize_rcu(); + ++ /* Step 2 - clean NAT section */ ++ clean.hash = false; + for_each_net(net) +- nf_ct_iterate_cleanup(net, nf_nat_proto_remove, &clean); ++ nf_ct_iterate_cleanup(net, nf_nat_proto_clean, &clean); + rtnl_unlock(); + } + +@@ -748,7 +774,7 @@ static void __net_exit nf_nat_net_exit(struct net *net) + { + struct nf_nat_proto_clean clean = {}; + +- nf_ct_iterate_cleanup(net, &nf_nat_proto_remove, &clean); ++ nf_ct_iterate_cleanup(net, &nf_nat_proto_clean, &clean); + synchronize_rcu(); + nf_ct_free_hashtable(net->ct.nat_bysource, net->ct.nat_htable_size); + } +diff --git a/net/wireless/reg.c b/net/wireless/reg.c +index 91ef82b..82c4fc7 100644 +--- a/net/wireless/reg.c ++++ b/net/wireless/reg.c +@@ -883,7 +883,7 @@ static void handle_channel(struct wiphy *wiphy, + return; + + REG_DBG_PRINT("Disabling freq %d MHz\n", chan->center_freq); +- chan->flags |= IEEE80211_CHAN_DISABLED; ++ chan->flags = IEEE80211_CHAN_DISABLED; + return; + } + +diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl +index 68b85e1..3368939 100644 +--- a/scripts/kconfig/streamline_config.pl ++++ b/scripts/kconfig/streamline_config.pl +@@ -156,6 +156,7 @@ sub read_kconfig { + + my $state = "NONE"; + my $config; ++ my @kconfigs; + + my $cont = 0; + my $line; +@@ -189,13 +190,7 @@ sub read_kconfig { + + # collect any Kconfig sources + if (/^source\s*"(.*)"/) { +- my $kconfig = $1; +- # prevent reading twice. +- if (!defined($read_kconfigs{$kconfig})) { +- $read_kconfigs{$kconfig} = 1; +- read_kconfig($kconfig); +- } +- next; ++ $kconfigs[$#kconfigs+1] = $1; + } + + # configs found +@@ -255,6 +250,14 @@ sub read_kconfig { + } + } + close($kinfile); ++ ++ # read in any configs that were found. ++ foreach my $kconfig (@kconfigs) { ++ if (!defined($read_kconfigs{$kconfig})) { ++ $read_kconfigs{$kconfig} = 1; ++ read_kconfig($kconfig); ++ } ++ } + } + + if ($kconfig) { +diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c +index 36664b6..ff36c50 100644 +--- a/scripts/mod/modpost.c ++++ b/scripts/mod/modpost.c +@@ -1701,7 +1701,7 @@ static void read_symbols(char *modname) + char *version; + char *license; + struct module *mod; +- struct elf_info info = { .hdr = NULL }; ++ struct elf_info info = { }; + Elf_Sym *sym; + + if (!parse_elf(&info, modname)) +@@ -2092,7 +2092,7 @@ static int dump_sym(struct symbol *sym) + + static void write_dump(const char *fname) + { +- struct buffer buf = { NULL, 0, 0 }; ++ struct buffer buf = { }; + struct symbol *symbol; + int n; + +@@ -2118,7 +2118,7 @@ struct ext_sym_list { + int main(int argc, char **argv) + { + struct module *mod; +- struct buffer buf = { NULL, 0, 0 }; ++ struct buffer buf = { }; + char *kernel_read = NULL, *module_read = NULL; + char *dump_write = NULL; + int opt; +diff --git a/security/commoncap.c b/security/commoncap.c +index 176edf1..7ee08c7 100644 +--- a/security/commoncap.c ++++ b/security/commoncap.c +@@ -988,11 +988,9 @@ int cap_mmap_addr(unsigned long addr) + } + return ret; + } +-EXPORT_SYMBOL(cap_mmap_addr); + + int cap_mmap_file(struct file *file, unsigned long reqprot, + unsigned long prot, unsigned long flags) + { + return 0; + } +-EXPORT_SYMBOL(cap_mmap_file); +diff --git a/security/device_cgroup.c b/security/device_cgroup.c +index a20f167..d794abc 100644 +--- a/security/device_cgroup.c ++++ b/security/device_cgroup.c +@@ -7,7 +7,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -632,7 +631,6 @@ int __devcgroup_inode_permission(struct inode *inode, int mask) + return __devcgroup_check_permission(type, imajor(inode), iminor(inode), + access); + } +-EXPORT_SYMBOL(__devcgroup_inode_permission); + + int devcgroup_inode_mknod(int mode, dev_t dev) + { +diff --git a/security/security.c b/security/security.c +index 5d00a30..7b88c6a 100644 +--- a/security/security.c ++++ b/security/security.c +@@ -396,7 +396,6 @@ int security_path_rmdir(struct path *dir, struct dentry *dentry) + return 0; + return security_ops->path_rmdir(dir, dentry); + } +-EXPORT_SYMBOL(security_path_rmdir); + + int security_path_unlink(struct path *dir, struct dentry *dentry) + { +@@ -413,7 +412,6 @@ int security_path_symlink(struct path *dir, struct dentry *dentry, + return 0; + return security_ops->path_symlink(dir, dentry, old_name); + } +-EXPORT_SYMBOL(security_path_symlink); + + int security_path_link(struct dentry *old_dentry, struct path *new_dir, + struct dentry *new_dentry) +@@ -422,7 +420,6 @@ int security_path_link(struct dentry *old_dentry, struct path *new_dir, + return 0; + return security_ops->path_link(old_dentry, new_dir, new_dentry); + } +-EXPORT_SYMBOL(security_path_link); + + int security_path_rename(struct path *old_dir, struct dentry *old_dentry, + struct path *new_dir, struct dentry *new_dentry) +@@ -441,7 +438,6 @@ int security_path_truncate(struct path *path) + return 0; + return security_ops->path_truncate(path); + } +-EXPORT_SYMBOL(security_path_truncate); + + int security_path_chmod(struct path *path, umode_t mode) + { +@@ -449,7 +445,6 @@ int security_path_chmod(struct path *path, umode_t mode) + return 0; + return security_ops->path_chmod(path, mode); + } +-EXPORT_SYMBOL(security_path_chmod); + + int security_path_chown(struct path *path, kuid_t uid, kgid_t gid) + { +@@ -457,7 +452,6 @@ int security_path_chown(struct path *path, kuid_t uid, kgid_t gid) + return 0; + return security_ops->path_chown(path, uid, gid); + } +-EXPORT_SYMBOL(security_path_chown); + + int security_path_chroot(struct path *path) + { +@@ -534,7 +528,6 @@ int security_inode_readlink(struct dentry *dentry) + return 0; + return security_ops->inode_readlink(dentry); + } +-EXPORT_SYMBOL(security_inode_readlink); + + int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd) + { +@@ -549,7 +542,6 @@ int security_inode_permission(struct inode *inode, int mask) + return 0; + return security_ops->inode_permission(inode, mask); + } +-EXPORT_SYMBOL(security_inode_permission); + + int security_inode_setattr(struct dentry *dentry, struct iattr *attr) + { +@@ -671,7 +663,6 @@ int security_file_permission(struct file *file, int mask) + + return fsnotify_perm(file, mask); + } +-EXPORT_SYMBOL(security_file_permission); + + int security_file_alloc(struct file *file) + { +@@ -732,7 +723,6 @@ int security_mmap_file(struct file *file, unsigned long prot, + return ret; + return ima_file_mmap(file, prot); + } +-EXPORT_SYMBOL(security_mmap_file); + + int security_mmap_addr(unsigned long addr) + { +diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c +index bdd888e..e6b0166 100644 +--- a/sound/pci/emu10k1/emu10k1_main.c ++++ b/sound/pci/emu10k1/emu10k1_main.c +@@ -657,14 +657,14 @@ static int snd_emu10k1_cardbus_init(struct snd_emu10k1 *emu) + return 0; + } + +-static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, +- const struct firmware *fw_entry) ++static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu) + { + int n, i; + int reg; + int value; + unsigned int write_post; + unsigned long flags; ++ const struct firmware *fw_entry = emu->firmware; + + if (!fw_entry) + return -EIO; +@@ -725,34 +725,9 @@ static int emu1010_firmware_thread(void *data) + /* Return to Audio Dock programming mode */ + snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n"); + snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK); +- +- if (!emu->dock_fw) { +- const char *filename = NULL; +- switch (emu->card_capabilities->emu_model) { +- case EMU_MODEL_EMU1010: +- filename = DOCK_FILENAME; +- break; +- case EMU_MODEL_EMU1010B: +- filename = MICRO_DOCK_FILENAME; +- break; +- case EMU_MODEL_EMU1616: +- filename = MICRO_DOCK_FILENAME; +- break; +- } +- if (filename) { +- err = request_firmware(&emu->dock_fw, +- filename, +- &emu->pci->dev); +- if (err) +- continue; +- } +- } +- +- if (emu->dock_fw) { +- err = snd_emu1010_load_firmware(emu, emu->dock_fw); +- if (err) +- continue; +- } ++ err = snd_emu1010_load_firmware(emu); ++ if (err != 0) ++ continue; + + snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0); + snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, ®); +@@ -887,7 +862,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) + filename, emu->firmware->size); + } + +- err = snd_emu1010_load_firmware(emu, emu->firmware); ++ err = snd_emu1010_load_firmware(emu); + if (err != 0) { + snd_printk(KERN_INFO "emu1010: Loading Firmware failed\n"); + return err; +@@ -1278,8 +1253,6 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu) + kthread_stop(emu->emu1010.firmware_thread); + if (emu->firmware) + release_firmware(emu->firmware); +- if (emu->dock_fw) +- release_firmware(emu->dock_fw); + if (emu->irq >= 0) + free_irq(emu->irq, emu); + /* remove reserved page */ +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 7f45d48..ee975a2 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -5823,7 +5823,6 @@ enum { + ALC269_TYPE_ALC280, + ALC269_TYPE_ALC282, + ALC269_TYPE_ALC284, +- ALC269_TYPE_ALC286, + }; + + /* +@@ -5847,7 +5846,6 @@ static int alc269_parse_auto_config(struct hda_codec *codec) + case ALC269_TYPE_ALC269VB: + case ALC269_TYPE_ALC269VD: + case ALC269_TYPE_ALC282: +- case ALC269_TYPE_ALC286: + ssids = alc269_ssids; + break; + default: +@@ -6453,9 +6451,6 @@ static int patch_alc269(struct hda_codec *codec) + case 0x10ec0292: + spec->codec_variant = ALC269_TYPE_ALC284; + break; +- case 0x10ec0286: +- spec->codec_variant = ALC269_TYPE_ALC286; +- break; + } + + /* automatic parse from the BIOS config */ +@@ -7162,7 +7157,6 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = { + { .id = 0x10ec0282, .name = "ALC282", .patch = patch_alc269 }, + { .id = 0x10ec0283, .name = "ALC283", .patch = patch_alc269 }, + { .id = 0x10ec0284, .name = "ALC284", .patch = patch_alc269 }, +- { .id = 0x10ec0286, .name = "ALC286", .patch = patch_alc269 }, + { .id = 0x10ec0290, .name = "ALC290", .patch = patch_alc269 }, + { .id = 0x10ec0292, .name = "ALC292", .patch = patch_alc269 }, + { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", +diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c +index 5d36319..a4c16fd 100644 +--- a/sound/soc/codecs/max98088.c ++++ b/sound/soc/codecs/max98088.c +@@ -2006,7 +2006,7 @@ static int max98088_probe(struct snd_soc_codec *codec) + ret); + goto err_access; + } +- dev_info(codec->dev, "revision %c\n", ret - 0x40 + 'A'); ++ dev_info(codec->dev, "revision %c\n", ret + 'A'); + + snd_soc_write(codec, M98088_REG_51_PWR_SYS, M98088_PWRSV); + +diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c +index 40dd50a..e2ca12f 100644 +--- a/sound/usb/6fire/pcm.c ++++ b/sound/usb/6fire/pcm.c +@@ -575,6 +575,7 @@ static void usb6fire_pcm_init_urb(struct pcm_urb *urb, + urb->instance.pipe = in ? usb_rcvisocpipe(chip->dev, ep) + : usb_sndisocpipe(chip->dev, ep); + urb->instance.interval = 1; ++ urb->instance.transfer_flags = URB_ISO_ASAP; + urb->instance.complete = handler; + urb->instance.context = urb; + urb->instance.number_of_packets = PCM_N_PACKETS_PER_URB; +diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c +index b45e29b..fde9a7a 100644 +--- a/sound/usb/caiaq/audio.c ++++ b/sound/usb/caiaq/audio.c +@@ -670,6 +670,7 @@ static void read_completed(struct urb *urb) + + if (send_it) { + out->number_of_packets = outframe; ++ out->transfer_flags = URB_ISO_ASAP; + usb_submit_urb(out, GFP_ATOMIC); + } else { + struct snd_usb_caiaq_cb_info *oinfo = out->context; +@@ -685,6 +686,7 @@ requeue: + } + + urb->number_of_packets = FRAMES_PER_URB; ++ urb->transfer_flags = URB_ISO_ASAP; + usb_submit_urb(urb, GFP_ATOMIC); + } + +@@ -749,6 +751,7 @@ static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret) + * BYTES_PER_FRAME; + urbs[i]->context = &dev->data_cb_info[i]; + urbs[i]->interval = 1; ++ urbs[i]->transfer_flags = URB_ISO_ASAP; + urbs[i]->number_of_packets = FRAMES_PER_URB; + urbs[i]->complete = (dir == SNDRV_PCM_STREAM_CAPTURE) ? + read_completed : write_completed; +diff --git a/sound/usb/card.c b/sound/usb/card.c +index a9d5779..ccf95cf 100644 +--- a/sound/usb/card.c ++++ b/sound/usb/card.c +@@ -612,9 +612,7 @@ int snd_usb_autoresume(struct snd_usb_audio *chip) + int err = -ENODEV; + + down_read(&chip->shutdown_rwsem); +- if (chip->probing) +- err = 0; +- else if (!chip->shutdown) ++ if (!chip->shutdown && !chip->probing) + err = usb_autopm_get_interface(chip->pm_intf); + up_read(&chip->shutdown_rwsem); + +diff --git a/sound/usb/card.h b/sound/usb/card.h +index d32ea41..8a751b4 100644 +--- a/sound/usb/card.h ++++ b/sound/usb/card.h +@@ -116,7 +116,6 @@ struct snd_usb_substream { + unsigned int altset_idx; /* USB data format: index of alternate setting */ + unsigned int txfr_quirk:1; /* allow sub-frame alignment */ + unsigned int fmt_type; /* USB audio format type (1-3) */ +- unsigned int pkt_offset_adj; /* Bytes to drop from beginning of packets (for non-compliant devices) */ + + unsigned int running: 1; /* running status */ + +diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c +index 63cca3a..21049b8 100644 +--- a/sound/usb/endpoint.c ++++ b/sound/usb/endpoint.c +@@ -677,7 +677,7 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep, + if (!u->urb->transfer_buffer) + goto out_of_memory; + u->urb->pipe = ep->pipe; +- u->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; ++ u->urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; + u->urb->interval = 1 << ep->datainterval; + u->urb->context = u; + u->urb->complete = snd_complete_urb; +@@ -716,7 +716,8 @@ static int sync_ep_set_params(struct snd_usb_endpoint *ep, + u->urb->transfer_dma = ep->sync_dma + i * 4; + u->urb->transfer_buffer_length = 4; + u->urb->pipe = ep->pipe; +- u->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; ++ u->urb->transfer_flags = URB_ISO_ASAP | ++ URB_NO_TRANSFER_DMA_MAP; + u->urb->number_of_packets = 1; + u->urb->interval = 1 << ep->syncinterval; + u->urb->context = u; +diff --git a/sound/usb/midi.c b/sound/usb/midi.c +index e5fee18..34b9bb7 100644 +--- a/sound/usb/midi.c ++++ b/sound/usb/midi.c +@@ -126,6 +126,7 @@ struct snd_usb_midi { + struct snd_usb_midi_in_endpoint *in; + } endpoints[MIDI_MAX_ENDPOINTS]; + unsigned long input_triggered; ++ bool autopm_reference; + unsigned int opened[2]; + unsigned char disconnected; + unsigned char input_running; +@@ -1039,6 +1040,7 @@ static int substream_open(struct snd_rawmidi_substream *substream, int dir, + { + struct snd_usb_midi* umidi = substream->rmidi->private_data; + struct snd_kcontrol *ctl; ++ int err; + + down_read(&umidi->disc_rwsem); + if (umidi->disconnected) { +@@ -1049,6 +1051,13 @@ static int substream_open(struct snd_rawmidi_substream *substream, int dir, + mutex_lock(&umidi->mutex); + if (open) { + if (!umidi->opened[0] && !umidi->opened[1]) { ++ err = usb_autopm_get_interface(umidi->iface); ++ umidi->autopm_reference = err >= 0; ++ if (err < 0 && err != -EACCES) { ++ mutex_unlock(&umidi->mutex); ++ up_read(&umidi->disc_rwsem); ++ return -EIO; ++ } + if (umidi->roland_load_ctl) { + ctl = umidi->roland_load_ctl; + ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; +@@ -1071,6 +1080,8 @@ static int substream_open(struct snd_rawmidi_substream *substream, int dir, + snd_ctl_notify(umidi->card, + SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); + } ++ if (umidi->autopm_reference) ++ usb_autopm_put_interface(umidi->iface); + } + } + mutex_unlock(&umidi->mutex); +@@ -2245,8 +2256,6 @@ int snd_usbmidi_create(struct snd_card *card, + return err; + } + +- usb_autopm_get_interface_no_resume(umidi->iface); +- + list_add_tail(&umidi->list, midi_list); + return 0; + } +diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c +index 6ad617b..8b81cb5 100644 +--- a/sound/usb/misc/ua101.c ++++ b/sound/usb/misc/ua101.c +@@ -1120,7 +1120,8 @@ static int alloc_stream_urbs(struct ua101 *ua, struct ua101_stream *stream, + usb_init_urb(&urb->urb); + urb->urb.dev = ua->dev; + urb->urb.pipe = stream->usb_pipe; +- urb->urb.transfer_flags = URB_NO_TRANSFER_DMA_MAP; ++ urb->urb.transfer_flags = URB_ISO_ASAP | ++ URB_NO_TRANSFER_DMA_MAP; + urb->urb.transfer_buffer = addr; + urb->urb.transfer_dma = dma; + urb->urb.transfer_buffer_length = max_packet_size; +diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c +index bcc50ed..d82e378 100644 +--- a/sound/usb/pcm.c ++++ b/sound/usb/pcm.c +@@ -1161,7 +1161,7 @@ static void retire_capture_urb(struct snd_usb_substream *subs, + stride = runtime->frame_bits >> 3; + + for (i = 0; i < urb->number_of_packets; i++) { +- cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset + subs->pkt_offset_adj; ++ cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset; + if (urb->iso_frame_desc[i].status && printk_ratelimit()) { + snd_printdd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status); + // continue; +diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c +index f581c3e..b9ca776 100644 +--- a/sound/usb/quirks.c ++++ b/sound/usb/quirks.c +@@ -837,7 +837,6 @@ static void set_format_emu_quirk(struct snd_usb_substream *subs, + break; + } + snd_emuusb_set_samplerate(subs->stream->chip, emu_samplerate_id); +- subs->pkt_offset_adj = (emu_samplerate_id >= EMU_QUIRK_SR_176400HZ) ? 4 : 0; + } + + void snd_usb_set_format_quirk(struct snd_usb_substream *subs, +diff --git a/sound/usb/stream.c b/sound/usb/stream.c +index cfc4d4e..ad181d5 100644 +--- a/sound/usb/stream.c ++++ b/sound/usb/stream.c +@@ -94,7 +94,6 @@ static void snd_usb_init_substream(struct snd_usb_stream *as, + subs->dev = as->chip->dev; + subs->txfr_quirk = as->chip->txfr_quirk; + subs->speed = snd_usb_get_speed(subs->dev); +- subs->pkt_offset_adj = 0; + + snd_usb_set_pcm_ops(as->pcm, stream); + +@@ -397,14 +396,6 @@ static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, + if (!csep && altsd->bNumEndpoints >= 2) + csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT); + +- /* +- * If we can't locate the USB_DT_CS_ENDPOINT descriptor in the extra +- * bytes after the first endpoint, go search the entire interface. +- * Some devices have it directly *before* the standard endpoint. +- */ +- if (!csep) +- csep = snd_usb_find_desc(alts->extra, alts->extralen, NULL, USB_DT_CS_ENDPOINT); +- + if (!csep || csep->bLength < 7 || + csep->bDescriptorSubtype != UAC_EP_GENERAL) { + snd_printk(KERN_WARNING "%d:%u:%d : no or invalid" +diff --git a/sound/usb/usx2y/usb_stream.c b/sound/usb/usx2y/usb_stream.c +index bf618e1..1e7a47a 100644 +--- a/sound/usb/usx2y/usb_stream.c ++++ b/sound/usb/usx2y/usb_stream.c +@@ -69,6 +69,7 @@ static void init_pipe_urbs(struct usb_stream_kernel *sk, unsigned use_packsize, + ++u, transfer += transfer_length) { + struct urb *urb = urbs[u]; + struct usb_iso_packet_descriptor *desc; ++ urb->transfer_flags = URB_ISO_ASAP; + urb->transfer_buffer = transfer; + urb->dev = dev; + urb->pipe = pipe; +diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c +index b376532..520ef96 100644 +--- a/sound/usb/usx2y/usbusx2yaudio.c ++++ b/sound/usb/usx2y/usbusx2yaudio.c +@@ -503,6 +503,7 @@ static int usX2Y_urbs_start(struct snd_usX2Y_substream *subs) + if (0 == i) + atomic_set(&subs->state, state_STARTING3); + urb->dev = usX2Y->dev; ++ urb->transfer_flags = URB_ISO_ASAP; + for (pack = 0; pack < nr_of_packs(); pack++) { + urb->iso_frame_desc[pack].offset = subs->maxpacksize * pack; + urb->iso_frame_desc[pack].length = subs->maxpacksize; +diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c +index f2a1acd..cc56007 100644 +--- a/sound/usb/usx2y/usx2yhwdeppcm.c ++++ b/sound/usb/usx2y/usx2yhwdeppcm.c +@@ -443,6 +443,7 @@ static int usX2Y_usbpcm_urbs_start(struct snd_usX2Y_substream *subs) + if (0 == u) + atomic_set(&subs->state, state_STARTING3); + urb->dev = usX2Y->dev; ++ urb->transfer_flags = URB_ISO_ASAP; + for (pack = 0; pack < nr_of_packs(); pack++) { + urb->iso_frame_desc[pack].offset = subs->maxpacksize * (pack + u * nr_of_packs()); + urb->iso_frame_desc[pack].length = subs->maxpacksize; +diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile +index 0b0a907..a20e320 100644 +--- a/tools/lib/traceevent/Makefile ++++ b/tools/lib/traceevent/Makefile +@@ -122,7 +122,7 @@ export Q VERBOSE + + EVENT_PARSE_VERSION = $(EP_VERSION).$(EP_PATCHLEVEL).$(EP_EXTRAVERSION) + +-INCLUDES = -I. $(CONFIG_INCLUDES) ++INCLUDES = -I. -I/usr/local/include $(CONFIG_INCLUDES) + + # Set compile option CFLAGS if not set elsewhere + CFLAGS ?= -g -Wall +diff --git a/tools/perf/Makefile b/tools/perf/Makefile +index 215a0d4..fb1b1c4 100644 +--- a/tools/perf/Makefile ++++ b/tools/perf/Makefile +@@ -637,10 +637,9 @@ ifndef NO_NEWT + ifneq ($(call try-cc,$(SOURCE_NEWT),$(FLAGS_NEWT),libnewt),y) + msg := $(warning newt not found, disables TUI support. Please install newt-devel or libnewt-dev); + else +- # Some releases like Fedora has /usr/include/slang/slang.h other than /usr/include/slang.h +- SLANG_INC ?= -idirafter =/usr/include/slang ++ # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h ++ BASIC_CFLAGS += -I/usr/include/slang + BASIC_CFLAGS += -DNEWT_SUPPORT +- BASIC_CFLAGS += $(SLANG_INC) + EXTLIBS += -lnewt -lslang + LIB_OBJS += $(OUTPUT)ui/browser.o + LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o +@@ -695,7 +694,6 @@ else + FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS) + + ifneq ($(call try-cc,$(SOURCE_PERL_EMBED),$(FLAGS_PERL_EMBED),perl),y) +- msg := $(warning libperl not found, disables Perl scripting support. Please install libperl-dev or perl-devel); + BASIC_CFLAGS += -DNO_LIBPERL + else + ALL_LDFLAGS += $(PERL_EMBED_LDFLAGS) +@@ -743,10 +741,10 @@ else + + PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG)) + +- PYTHON_EMBED_LDOPTS := $(shell pkg-config --libs python 2>/dev/null) ++ PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null) + PYTHON_EMBED_LDFLAGS := $(call strip-libs,$(PYTHON_EMBED_LDOPTS)) + PYTHON_EMBED_LIBADD := $(call grep-libs,$(PYTHON_EMBED_LDOPTS)) +- PYTHON_EMBED_CCOPTS := $(shell pkg-config --cflags python 2>/dev/null) ++ PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) + FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) + + ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED),python),y) +@@ -1123,7 +1121,7 @@ install: all try-install-man + $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr' + + install-python_ext: +- $(PYTHON_WORD) util/setup.py --quiet install --prefix='$(DESTDIR_SQ)/usr' ++ $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)' + + # 'make install-doc' should call 'make -C Documentation install' + $(INSTALL_DOC_TARGETS): +diff --git a/tools/perf/perf.h b/tools/perf/perf.h +index 6fe24ac..2c340e7 100644 +--- a/tools/perf/perf.h ++++ b/tools/perf/perf.h +@@ -7,8 +7,6 @@ void get_term_dimensions(struct winsize *ws); + + #include + +-#include +- + #if defined(__i386__) + #define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory") + #define cpu_relax() asm volatile("rep; nop" ::: "memory"); +diff --git a/tools/perf/scripts/python/Perf-Trace-Util/Context.c b/tools/perf/scripts/python/Perf-Trace-Util/Context.c +index 57d3aa3..315067b 100644 +--- a/tools/perf/scripts/python/Perf-Trace-Util/Context.c ++++ b/tools/perf/scripts/python/Perf-Trace-Util/Context.c +@@ -19,10 +19,6 @@ + * + */ + +-#ifdef __mips__ +-#include +-#endif +- + #include + #include "../../../perf.h" + #include "../../../util/trace-event.h" +diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c +index ff162ae..07aaeea 100644 +--- a/tools/perf/util/annotate.c ++++ b/tools/perf/util/annotate.c +@@ -826,7 +826,7 @@ fallback: + snprintf(command, sizeof(command), + "%s %s%s --start-address=0x%016" PRIx64 + " --stop-address=0x%016" PRIx64 +- " -d %s %s -C %s|grep -v %s|sed 's/\t/ /g'", ++ " -d %s %s -C %s|grep -v %s|expand", + objdump_path ? objdump_path : "objdump", + disassembler_style ? "-M " : "", + disassembler_style ? disassembler_style : "", +diff --git a/tools/perf/util/include/linux/compiler.h b/tools/perf/util/include/linux/compiler.h +index d0c6cd6..96b919d 100644 +--- a/tools/perf/util/include/linux/compiler.h ++++ b/tools/perf/util/include/linux/compiler.h +@@ -4,7 +4,6 @@ + #ifndef __always_inline + #define __always_inline inline + #endif +-#undef __user + #define __user + #ifndef __attribute_const__ + #define __attribute_const__ +diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c +index 8efa0a2..14683df 100644 +--- a/tools/perf/util/scripting-engines/trace-event-python.c ++++ b/tools/perf/util/scripting-engines/trace-event-python.c +@@ -19,10 +19,6 @@ + * + */ + +-#ifdef __mips__ +-#include +-#endif +- + #include + + #include +diff --git a/usr/Makefile b/usr/Makefile +index ddb506b..029ffe6 100644 +--- a/usr/Makefile ++++ b/usr/Makefile +@@ -35,7 +35,7 @@ $(obj)/initramfs_data.o: $(obj)/initramfs_data.cpio$(suffix_y) FORCE + # Generate the initramfs cpio archive + + hostprogs-y := gen_init_cpio +-initramfs := $(INITRAMFS_WRAPPER) $(CONFIG_SHELL) $(srctree)/scripts/gen_initramfs_list.sh ++initramfs := $(CONFIG_SHELL) $(srctree)/scripts/gen_initramfs_list.sh + ramfs-input := $(if $(filter-out "",$(CONFIG_INITRAMFS_SOURCE)), \ + $(shell echo $(CONFIG_INITRAMFS_SOURCE)),-d) + ramfs-args := \ +-- +1.7.9.5 + diff --git a/recipes-kernel/linux/linux-yocto/xlnx_3.8/0002-microblaze-Dont-mark-arch_kgdb_ops-as-const.patch b/recipes-kernel/linux/linux-yocto/xlnx_3.8/0002-microblaze-Dont-mark-arch_kgdb_ops-as-const.patch new file mode 100644 index 00000000..53be2bf4 --- /dev/null +++ b/recipes-kernel/linux/linux-yocto/xlnx_3.8/0002-microblaze-Dont-mark-arch_kgdb_ops-as-const.patch @@ -0,0 +1,35 @@ +From fd2c402c79a9a73e5b2384f0897f3f95f599afdd Mon Sep 17 00:00:00 2001 +From: Graeme Smecher +Date: Sat, 8 Jun 2013 09:52:08 -0700 +Subject: [PATCH] microblaze: Don't mark arch_kgdb_ops as const. + +Other architectures don't do it, and it conflicts with the extern'd definition +in include/linux/kgdb.h. + +The patch fails checkpatch but it reflects current +functions declaration and solved compilation error. + +Signed-off-by: Graeme Smecher +CC: Michal Simek +CC: linux-kernel@vger.kernel.org +Signed-off-by: Michal Simek +--- + arch/microblaze/kernel/kgdb.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/microblaze/kernel/kgdb.c b/arch/microblaze/kernel/kgdb.c +index 8adc9244..09a5e82 100644 +--- a/arch/microblaze/kernel/kgdb.c ++++ b/arch/microblaze/kernel/kgdb.c +@@ -141,7 +141,7 @@ void kgdb_arch_exit(void) + /* + * Global data + */ +-const struct kgdb_arch arch_kgdb_ops = { ++struct kgdb_arch arch_kgdb_ops = { + #ifdef __MICROBLAZEEL__ + .gdb_bpt_instr = {0x18, 0x00, 0x0c, 0xba}, /* brki r16, 0x18 */ + #else +-- +1.8.4 + diff --git a/recipes-kernel/linux/linux-yocto/xlnx_3.8_modifications_to_v14.5.scc b/recipes-kernel/linux/linux-yocto/xlnx_3.8_modifications_to_v14.5.scc new file mode 100644 index 00000000..1f4a6e5b --- /dev/null +++ b/recipes-kernel/linux/linux-yocto/xlnx_3.8_modifications_to_v14.5.scc @@ -0,0 +1,3 @@ +patch xlnx_3.8/0001-Forward-code-to-match-xlnx_3.8-branch-on-linux_xlnx..patch +patch xlnx_3.8/0002-microblaze-Dont-mark-arch_kgdb_ops-as-const.patch + diff --git a/recipes-kernel/linux/linux-yocto_3.8.bbappend b/recipes-kernel/linux/linux-yocto_3.8.bbappend index 9c7d6d1e..bc1f1e48 100644 --- a/recipes-kernel/linux/linux-yocto_3.8.bbappend +++ b/recipes-kernel/linux/linux-yocto_3.8.bbappend @@ -1,6 +1,4 @@ include linux-yocto-common.inc - -# default architecture configuration -SRC_URI_append_zynq = " file://zynq-default-standard.scc" -SRC_URI_append_microblaze = " file://microblaze-default-standard.scc" +# include some kernel version specifics shared between standard and tiny +include linux-yocto-common-3.8.inc -- cgit v1.2.3-54-g00ecf