diff --git a/kernel/kernel/files/configs/kernel-i686-config b/kernel/kernel/files/configs/kernel-i686-config old mode 100644 new mode 100755 diff --git a/kernel/kernel/files/configs/kernel-x86_64-config b/kernel/kernel/files/configs/kernel-x86_64-config old mode 100644 new mode 100755 index 4b4b19ec..e4359c8b --- a/kernel/kernel/files/configs/kernel-x86_64-config +++ b/kernel/kernel/files/configs/kernel-x86_64-config @@ -1,7325 +1,9968 @@ -# -# Automatically generated file; DO NOT EDIT. -# Linux/x86_64 4.19.56 Kernel Configuration -# - -# -# Compiler: gcc (Pisi Linux) 7.3.0 -# -CONFIG_CC_IS_GCC=y -CONFIG_GCC_VERSION=70300 -CONFIG_CLANG_VERSION=0 -CONFIG_CC_HAS_ASM_GOTO=y -CONFIG_IRQ_WORK=y -CONFIG_BUILDTIME_EXTABLE_SORT=y -CONFIG_THREAD_INFO_IN_TASK=y - -# -# General setup -# -CONFIG_INIT_ENV_ARG_LIMIT=32 -# CONFIG_COMPILE_TEST is not set -CONFIG_LOCALVERSION="" -# CONFIG_LOCALVERSION_AUTO is not set -CONFIG_BUILD_SALT="" -CONFIG_HAVE_KERNEL_GZIP=y -CONFIG_HAVE_KERNEL_BZIP2=y -CONFIG_HAVE_KERNEL_LZMA=y -CONFIG_HAVE_KERNEL_XZ=y -CONFIG_HAVE_KERNEL_LZO=y -CONFIG_HAVE_KERNEL_LZ4=y -CONFIG_KERNEL_GZIP=y -# CONFIG_KERNEL_BZIP2 is not set -# CONFIG_KERNEL_LZMA is not set -# CONFIG_KERNEL_XZ is not set -# CONFIG_KERNEL_LZO is not set -# CONFIG_KERNEL_LZ4 is not set -CONFIG_DEFAULT_HOSTNAME="" -CONFIG_SWAP=y -CONFIG_SYSVIPC=y -CONFIG_SYSVIPC_SYSCTL=y -CONFIG_POSIX_MQUEUE=y -CONFIG_POSIX_MQUEUE_SYSCTL=y -CONFIG_CROSS_MEMORY_ATTACH=y -# CONFIG_USELIB is not set -CONFIG_AUDIT=y -CONFIG_HAVE_ARCH_AUDITSYSCALL=y -CONFIG_AUDITSYSCALL=y -CONFIG_AUDIT_WATCH=y -CONFIG_AUDIT_TREE=y - -# -# IRQ subsystem -# -CONFIG_GENERIC_IRQ_PROBE=y -CONFIG_GENERIC_IRQ_SHOW=y -CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y -CONFIG_GENERIC_PENDING_IRQ=y -CONFIG_GENERIC_IRQ_MIGRATION=y -CONFIG_GENERIC_IRQ_CHIP=y -CONFIG_IRQ_DOMAIN=y -CONFIG_IRQ_SIM=y -CONFIG_IRQ_DOMAIN_HIERARCHY=y -CONFIG_GENERIC_MSI_IRQ=y -CONFIG_GENERIC_MSI_IRQ_DOMAIN=y -CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y -CONFIG_GENERIC_IRQ_RESERVATION_MODE=y -CONFIG_IRQ_FORCED_THREADING=y -CONFIG_SPARSE_IRQ=y -# CONFIG_GENERIC_IRQ_DEBUGFS is not set -CONFIG_CLOCKSOURCE_WATCHDOG=y -CONFIG_ARCH_CLOCKSOURCE_DATA=y -CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y -CONFIG_GENERIC_TIME_VSYSCALL=y -CONFIG_GENERIC_CLOCKEVENTS=y -CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y -CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y -CONFIG_GENERIC_CMOS_UPDATE=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_FULL is not set -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -# CONFIG_PREEMPT_NONE is not set -CONFIG_PREEMPT_VOLUNTARY=y -# CONFIG_PREEMPT is not set - -# -# CPU/Task time and stats accounting -# -CONFIG_TICK_CPU_ACCOUNTING=y -# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set -# CONFIG_IRQ_TIME_ACCOUNTING is not set -CONFIG_HAVE_SCHED_AVG_IRQ=y -CONFIG_BSD_PROCESS_ACCT=y -CONFIG_BSD_PROCESS_ACCT_V3=y -CONFIG_TASKSTATS=y -CONFIG_TASK_DELAY_ACCT=y -CONFIG_TASK_XACCT=y -CONFIG_TASK_IO_ACCOUNTING=y -CONFIG_CPU_ISOLATION=y - -# -# RCU Subsystem -# -CONFIG_TREE_RCU=y -# CONFIG_RCU_EXPERT is not set -CONFIG_SRCU=y -CONFIG_TREE_SRCU=y -CONFIG_RCU_STALL_COMMON=y -CONFIG_RCU_NEED_SEGCBLIST=y -CONFIG_BUILD_BIN2C=y -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -CONFIG_LOG_BUF_SHIFT=18 -CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 -CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13 -CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y -CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y -CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y -CONFIG_ARCH_SUPPORTS_INT128=y -# CONFIG_NUMA_BALANCING is not set -CONFIG_CGROUPS=y -CONFIG_PAGE_COUNTER=y -CONFIG_MEMCG=y -CONFIG_MEMCG_SWAP=y -CONFIG_MEMCG_SWAP_ENABLED=y -CONFIG_MEMCG_KMEM=y -CONFIG_BLK_CGROUP=y -# CONFIG_DEBUG_BLK_CGROUP is not set -CONFIG_CGROUP_WRITEBACK=y -CONFIG_CGROUP_SCHED=y -CONFIG_FAIR_GROUP_SCHED=y -CONFIG_CFS_BANDWIDTH=y -CONFIG_RT_GROUP_SCHED=y -CONFIG_CGROUP_PIDS=y -# CONFIG_CGROUP_RDMA is not set -CONFIG_CGROUP_FREEZER=y -CONFIG_CGROUP_HUGETLB=y -CONFIG_CPUSETS=y -CONFIG_PROC_PID_CPUSET=y -CONFIG_CGROUP_DEVICE=y -CONFIG_CGROUP_CPUACCT=y -CONFIG_CGROUP_PERF=y -# CONFIG_CGROUP_BPF is not set -CONFIG_SOCK_CGROUP_DATA=y -CONFIG_NAMESPACES=y -CONFIG_UTS_NS=y -CONFIG_IPC_NS=y -CONFIG_USER_NS=y -CONFIG_PID_NS=y -CONFIG_NET_NS=y -# CONFIG_CHECKPOINT_RESTORE is not set -CONFIG_SCHED_AUTOGROUP=y -# CONFIG_SYSFS_DEPRECATED is not set -CONFIG_RELAY=y -CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="" -CONFIG_RD_GZIP=y -CONFIG_RD_BZIP2=y -CONFIG_RD_LZMA=y -CONFIG_RD_XZ=y -CONFIG_RD_LZO=y -CONFIG_RD_LZ4=y -CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_SYSCTL=y -CONFIG_ANON_INODES=y -CONFIG_HAVE_UID16=y -CONFIG_SYSCTL_EXCEPTION_TRACE=y -CONFIG_HAVE_PCSPKR_PLATFORM=y -CONFIG_BPF=y -# CONFIG_EXPERT is not set -CONFIG_UID16=y -CONFIG_MULTIUSER=y -CONFIG_SGETMASK_SYSCALL=y -CONFIG_SYSFS_SYSCALL=y -CONFIG_FHANDLE=y -CONFIG_POSIX_TIMERS=y -CONFIG_PRINTK=y -CONFIG_PRINTK_NMI=y -CONFIG_BUG=y -CONFIG_ELF_CORE=y -CONFIG_PCSPKR_PLATFORM=y -CONFIG_BASE_FULL=y -CONFIG_FUTEX=y -CONFIG_FUTEX_PI=y -CONFIG_EPOLL=y -CONFIG_SIGNALFD=y -CONFIG_TIMERFD=y -CONFIG_EVENTFD=y -CONFIG_SHMEM=y -CONFIG_AIO=y -CONFIG_ADVISE_SYSCALLS=y -CONFIG_MEMBARRIER=y -CONFIG_KALLSYMS=y -CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y -CONFIG_KALLSYMS_BASE_RELATIVE=y -CONFIG_BPF_SYSCALL=y -# CONFIG_BPF_JIT_ALWAYS_ON is not set -# CONFIG_USERFAULTFD is not set -CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y -CONFIG_RSEQ=y -# CONFIG_EMBEDDED is not set -CONFIG_HAVE_PERF_EVENTS=y - -# -# Kernel Performance Events And Counters -# -CONFIG_PERF_EVENTS=y -CONFIG_VM_EVENT_COUNTERS=y -# CONFIG_COMPAT_BRK is not set -CONFIG_SLAB=y -# CONFIG_SLUB is not set -CONFIG_SLAB_MERGE_DEFAULT=y -# CONFIG_SLAB_FREELIST_RANDOM is not set -CONFIG_SYSTEM_DATA_VERIFICATION=y -CONFIG_PROFILING=y -CONFIG_TRACEPOINTS=y -CONFIG_64BIT=y -CONFIG_X86_64=y -CONFIG_X86=y -CONFIG_INSTRUCTION_DECODER=y -CONFIG_OUTPUT_FORMAT="elf64-x86-64" -CONFIG_ARCH_DEFCONFIG="arch/x86/configs/x86_64_defconfig" -CONFIG_LOCKDEP_SUPPORT=y -CONFIG_STACKTRACE_SUPPORT=y -CONFIG_MMU=y -CONFIG_ARCH_MMAP_RND_BITS_MIN=28 -CONFIG_ARCH_MMAP_RND_BITS_MAX=32 -CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 -CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16 -CONFIG_GENERIC_ISA_DMA=y -CONFIG_GENERIC_BUG=y -CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y -CONFIG_GENERIC_HWEIGHT=y -CONFIG_ARCH_MAY_HAVE_PC_FDC=y -CONFIG_RWSEM_XCHGADD_ALGORITHM=y -CONFIG_GENERIC_CALIBRATE_DELAY=y -CONFIG_ARCH_HAS_CPU_RELAX=y -CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y -CONFIG_ARCH_HAS_FILTER_PGPROT=y -CONFIG_HAVE_SETUP_PER_CPU_AREA=y -CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y -CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y -CONFIG_ARCH_HIBERNATION_POSSIBLE=y -CONFIG_ARCH_SUSPEND_POSSIBLE=y -CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y -CONFIG_ARCH_WANT_GENERAL_HUGETLB=y -CONFIG_ZONE_DMA32=y -CONFIG_AUDIT_ARCH=y -CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y -CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y -CONFIG_HAVE_INTEL_TXT=y -CONFIG_X86_64_SMP=y -CONFIG_ARCH_SUPPORTS_UPROBES=y -CONFIG_FIX_EARLYCON_MEM=y -CONFIG_PGTABLE_LEVELS=4 -CONFIG_CC_HAS_SANE_STACKPROTECTOR=y - -# -# Processor type and features -# -CONFIG_ZONE_DMA=y -CONFIG_SMP=y -CONFIG_X86_FEATURE_NAMES=y -CONFIG_X86_X2APIC=y -CONFIG_X86_MPPARSE=y -# CONFIG_GOLDFISH is not set -CONFIG_RETPOLINE=y -# CONFIG_INTEL_RDT is not set -CONFIG_X86_EXTENDED_PLATFORM=y -# CONFIG_X86_NUMACHIP is not set -# CONFIG_X86_VSMP is not set -# CONFIG_X86_UV is not set -# CONFIG_X86_GOLDFISH is not set -# CONFIG_X86_INTEL_MID is not set -# CONFIG_X86_INTEL_LPSS is not set -CONFIG_X86_AMD_PLATFORM_DEVICE=y -CONFIG_IOSF_MBI=m -# CONFIG_IOSF_MBI_DEBUG is not set -CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y -CONFIG_SCHED_OMIT_FRAME_POINTER=y -CONFIG_HYPERVISOR_GUEST=y -CONFIG_PARAVIRT=y -# CONFIG_PARAVIRT_SPINLOCKS is not set -CONFIG_XEN=y -CONFIG_XEN_PV=y -CONFIG_XEN_PV_SMP=y -CONFIG_XEN_DOM0=y -CONFIG_XEN_PVHVM=y -CONFIG_XEN_PVHVM_SMP=y -CONFIG_XEN_512GB=y -CONFIG_XEN_SAVE_RESTORE=y -CONFIG_XEN_DEBUG_FS=y -CONFIG_XEN_PVH=y -CONFIG_KVM_GUEST=y -# CONFIG_KVM_DEBUG_FS is not set -CONFIG_PARAVIRT_TIME_ACCOUNTING=y -CONFIG_PARAVIRT_CLOCK=y -# CONFIG_JAILHOUSE_GUEST is not set -CONFIG_NO_BOOTMEM=y -# CONFIG_MK8 is not set -# CONFIG_MPSC is not set -# CONFIG_MCORE2 is not set -# CONFIG_MATOM is not set -CONFIG_GENERIC_CPU=y -CONFIG_X86_INTERNODE_CACHE_SHIFT=6 -CONFIG_X86_L1_CACHE_SHIFT=6 -CONFIG_X86_TSC=y -CONFIG_X86_CMPXCHG64=y -CONFIG_X86_CMOV=y -CONFIG_X86_MINIMUM_CPU_FAMILY=64 -CONFIG_X86_DEBUGCTLMSR=y -CONFIG_CPU_SUP_INTEL=y -CONFIG_CPU_SUP_AMD=y -CONFIG_CPU_SUP_CENTAUR=y -CONFIG_HPET_TIMER=y -CONFIG_HPET_EMULATE_RTC=y -CONFIG_DMI=y -CONFIG_GART_IOMMU=y -# CONFIG_CALGARY_IOMMU is not set -CONFIG_NR_CPUS_RANGE_BEGIN=2 -CONFIG_NR_CPUS_RANGE_END=512 -CONFIG_NR_CPUS_DEFAULT=64 -CONFIG_NR_CPUS=8 -CONFIG_SCHED_SMT=y -CONFIG_SCHED_MC=y -CONFIG_SCHED_MC_PRIO=y -CONFIG_X86_LOCAL_APIC=y -CONFIG_X86_IO_APIC=y -CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y -CONFIG_X86_MCE=y -# CONFIG_X86_MCELOG_LEGACY is not set -CONFIG_X86_MCE_INTEL=y -CONFIG_X86_MCE_AMD=y -CONFIG_X86_MCE_THRESHOLD=y -# CONFIG_X86_MCE_INJECT is not set -CONFIG_X86_THERMAL_VECTOR=y - -# -# Performance monitoring -# -CONFIG_PERF_EVENTS_INTEL_UNCORE=y -CONFIG_PERF_EVENTS_INTEL_RAPL=y -CONFIG_PERF_EVENTS_INTEL_CSTATE=y -# CONFIG_PERF_EVENTS_AMD_POWER is not set -CONFIG_X86_16BIT=y -CONFIG_X86_ESPFIX64=y -CONFIG_X86_VSYSCALL_EMULATION=y -CONFIG_I8K=m -CONFIG_MICROCODE=y -CONFIG_MICROCODE_INTEL=y -CONFIG_MICROCODE_AMD=y -CONFIG_MICROCODE_OLD_INTERFACE=y -CONFIG_X86_MSR=y -CONFIG_X86_CPUID=y -# CONFIG_X86_5LEVEL is not set -CONFIG_X86_DIRECT_GBPAGES=y -CONFIG_ARCH_HAS_MEM_ENCRYPT=y -# CONFIG_AMD_MEM_ENCRYPT is not set -CONFIG_NUMA=y -CONFIG_AMD_NUMA=y -CONFIG_X86_64_ACPI_NUMA=y -CONFIG_NODES_SPAN_OTHER_NODES=y -# CONFIG_NUMA_EMU is not set -CONFIG_NODES_SHIFT=10 -CONFIG_ARCH_SPARSEMEM_ENABLE=y -CONFIG_ARCH_SPARSEMEM_DEFAULT=y -CONFIG_ARCH_SELECT_MEMORY_MODEL=y -CONFIG_ARCH_MEMORY_PROBE=y -CONFIG_ARCH_PROC_KCORE_TEXT=y -CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 -# CONFIG_X86_PMEM_LEGACY is not set -CONFIG_X86_CHECK_BIOS_CORRUPTION=y -CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK=y -CONFIG_X86_RESERVE_LOW=64 -CONFIG_MTRR=y -CONFIG_MTRR_SANITIZER=y -CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT=1 -CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT=1 -CONFIG_X86_PAT=y -CONFIG_ARCH_USES_PG_UNCACHED=y -CONFIG_ARCH_RANDOM=y -CONFIG_X86_SMAP=y -CONFIG_X86_INTEL_UMIP=y -# CONFIG_X86_INTEL_MPX is not set -CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS=y -CONFIG_EFI=y -CONFIG_EFI_STUB=y -# CONFIG_EFI_MIXED is not set -CONFIG_SECCOMP=y -# CONFIG_HZ_100 is not set -# CONFIG_HZ_250 is not set -# CONFIG_HZ_300 is not set -CONFIG_HZ_1000=y -CONFIG_HZ=1000 -CONFIG_SCHED_HRTICK=y -CONFIG_KEXEC=y -# CONFIG_KEXEC_FILE is not set -CONFIG_CRASH_DUMP=y -CONFIG_KEXEC_JUMP=y -CONFIG_PHYSICAL_START=0x200000 -CONFIG_RELOCATABLE=y -CONFIG_RANDOMIZE_BASE=y -CONFIG_X86_NEED_RELOCS=y -CONFIG_PHYSICAL_ALIGN=0x1000000 -CONFIG_DYNAMIC_MEMORY_LAYOUT=y -CONFIG_RANDOMIZE_MEMORY=y -CONFIG_RANDOMIZE_MEMORY_PHYSICAL_PADDING=0xa -CONFIG_HOTPLUG_CPU=y -# CONFIG_BOOTPARAM_HOTPLUG_CPU0 is not set -# CONFIG_DEBUG_HOTPLUG_CPU0 is not set -# CONFIG_COMPAT_VDSO is not set -CONFIG_LEGACY_VSYSCALL_EMULATE=y -# CONFIG_LEGACY_VSYSCALL_NONE is not set -# CONFIG_CMDLINE_BOOL is not set -CONFIG_MODIFY_LDT_SYSCALL=y -CONFIG_HAVE_LIVEPATCH=y -CONFIG_ARCH_HAS_ADD_PAGES=y -CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y -CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y -CONFIG_USE_PERCPU_NUMA_NODE_ID=y -CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y -CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION=y -CONFIG_ARCH_ENABLE_THP_MIGRATION=y - -# -# Power management and ACPI options -# -CONFIG_ARCH_HIBERNATION_HEADER=y -CONFIG_SUSPEND=y -CONFIG_SUSPEND_FREEZER=y -CONFIG_HIBERNATE_CALLBACKS=y -CONFIG_HIBERNATION=y -CONFIG_PM_STD_PARTITION="" -CONFIG_PM_SLEEP=y -CONFIG_PM_SLEEP_SMP=y -# CONFIG_PM_AUTOSLEEP is not set -# CONFIG_PM_WAKELOCKS is not set -CONFIG_PM=y -CONFIG_PM_DEBUG=y -# CONFIG_PM_ADVANCED_DEBUG is not set -CONFIG_PM_TEST_SUSPEND=y -CONFIG_PM_SLEEP_DEBUG=y -CONFIG_PM_TRACE=y -CONFIG_PM_TRACE_RTC=y -CONFIG_PM_CLK=y -# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set -CONFIG_ARCH_SUPPORTS_ACPI=y -CONFIG_ACPI=y -CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y -CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y -CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y -# CONFIG_ACPI_DEBUGGER is not set -CONFIG_ACPI_SPCR_TABLE=y -CONFIG_ACPI_LPIT=y -CONFIG_ACPI_SLEEP=y -# CONFIG_ACPI_PROCFS_POWER is not set -CONFIG_ACPI_REV_OVERRIDE_POSSIBLE=y -CONFIG_ACPI_EC_DEBUGFS=m -CONFIG_ACPI_AC=y -CONFIG_ACPI_BATTERY=y -CONFIG_ACPI_BUTTON=y -CONFIG_ACPI_VIDEO=m -CONFIG_ACPI_FAN=y -# CONFIG_ACPI_TAD is not set -CONFIG_ACPI_DOCK=y -CONFIG_ACPI_CPU_FREQ_PSS=y -CONFIG_ACPI_PROCESSOR_CSTATE=y -CONFIG_ACPI_PROCESSOR_IDLE=y -CONFIG_ACPI_CPPC_LIB=y -CONFIG_ACPI_PROCESSOR=y -CONFIG_ACPI_IPMI=m -CONFIG_ACPI_HOTPLUG_CPU=y -CONFIG_ACPI_PROCESSOR_AGGREGATOR=m -CONFIG_ACPI_THERMAL=y -CONFIG_ACPI_NUMA=y -CONFIG_ARCH_HAS_ACPI_TABLE_UPGRADE=y -CONFIG_ACPI_TABLE_UPGRADE=y -# CONFIG_ACPI_DEBUG is not set -CONFIG_ACPI_PCI_SLOT=y -CONFIG_ACPI_CONTAINER=y -CONFIG_ACPI_HOTPLUG_MEMORY=y -CONFIG_ACPI_HOTPLUG_IOAPIC=y -CONFIG_ACPI_SBS=m -CONFIG_ACPI_HED=y -CONFIG_ACPI_CUSTOM_METHOD=m -CONFIG_ACPI_BGRT=y -# CONFIG_ACPI_NFIT is not set -CONFIG_HAVE_ACPI_APEI=y -CONFIG_HAVE_ACPI_APEI_NMI=y -CONFIG_ACPI_APEI=y -CONFIG_ACPI_APEI_GHES=y -CONFIG_ACPI_APEI_PCIEAER=y -CONFIG_ACPI_APEI_MEMORY_FAILURE=y -# CONFIG_ACPI_APEI_EINJ is not set -# CONFIG_ACPI_APEI_ERST_DEBUG is not set -CONFIG_DPTF_POWER=m -CONFIG_ACPI_WATCHDOG=y -CONFIG_ACPI_EXTLOG=m -# CONFIG_PMIC_OPREGION is not set -CONFIG_ACPI_CONFIGFS=m -CONFIG_X86_PM_TIMER=y -CONFIG_SFI=y - -# -# CPU Frequency scaling -# -CONFIG_CPU_FREQ=y -CONFIG_CPU_FREQ_GOV_ATTR_SET=y -CONFIG_CPU_FREQ_GOV_COMMON=y -CONFIG_CPU_FREQ_STAT=y -CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y -# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set -# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set -# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set -# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set -# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set -CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -CONFIG_CPU_FREQ_GOV_POWERSAVE=m -CONFIG_CPU_FREQ_GOV_USERSPACE=y -CONFIG_CPU_FREQ_GOV_ONDEMAND=m -CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m -# CONFIG_CPU_FREQ_GOV_SCHEDUTIL is not set - -# -# CPU frequency scaling drivers -# -CONFIG_X86_INTEL_PSTATE=y -CONFIG_X86_PCC_CPUFREQ=y -CONFIG_X86_ACPI_CPUFREQ=y -CONFIG_X86_ACPI_CPUFREQ_CPB=y -CONFIG_X86_POWERNOW_K8=y -CONFIG_X86_AMD_FREQ_SENSITIVITY=m -# CONFIG_X86_SPEEDSTEP_CENTRINO is not set -CONFIG_X86_P4_CLOCKMOD=y - -# -# shared options -# -CONFIG_X86_SPEEDSTEP_LIB=y - -# -# CPU Idle -# -CONFIG_CPU_IDLE=y -CONFIG_CPU_IDLE_GOV_LADDER=y -CONFIG_CPU_IDLE_GOV_MENU=y -CONFIG_INTEL_IDLE=y - -# -# Bus options (PCI etc.) -# -CONFIG_PCI=y -CONFIG_PCI_DIRECT=y -CONFIG_PCI_MMCONFIG=y -CONFIG_PCI_XEN=y -CONFIG_PCI_DOMAINS=y -CONFIG_MMCONF_FAM10H=y -CONFIG_PCIEPORTBUS=y -CONFIG_HOTPLUG_PCI_PCIE=y -CONFIG_PCIEAER=y -CONFIG_PCIEAER_INJECT=m -CONFIG_PCIE_ECRC=y -CONFIG_PCIEASPM=y -# CONFIG_PCIEASPM_DEBUG is not set -CONFIG_PCIEASPM_DEFAULT=y -# CONFIG_PCIEASPM_POWERSAVE is not set -# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set -# CONFIG_PCIEASPM_PERFORMANCE is not set -CONFIG_PCIE_PME=y -# CONFIG_PCIE_DPC is not set -# CONFIG_PCIE_PTM is not set -CONFIG_PCI_MSI=y -CONFIG_PCI_MSI_IRQ_DOMAIN=y -CONFIG_PCI_QUIRKS=y -# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set -CONFIG_PCI_STUB=y -# CONFIG_PCI_PF_STUB is not set -CONFIG_XEN_PCIDEV_FRONTEND=m -CONFIG_PCI_ATS=y -CONFIG_PCI_LOCKLESS_CONFIG=y -CONFIG_PCI_IOV=y -CONFIG_PCI_PRI=y -CONFIG_PCI_PASID=y -CONFIG_PCI_LABEL=y -# CONFIG_PCI_HYPERV is not set -CONFIG_HOTPLUG_PCI=y -CONFIG_HOTPLUG_PCI_ACPI=y -CONFIG_HOTPLUG_PCI_ACPI_IBM=m -# CONFIG_HOTPLUG_PCI_CPCI is not set -# CONFIG_HOTPLUG_PCI_SHPC is not set - -# -# PCI controller drivers -# - -# -# Cadence PCIe controllers support -# -# CONFIG_VMD is not set - -# -# DesignWare PCI Core Support -# -# CONFIG_PCIE_DW_PLAT_HOST is not set - -# -# PCI Endpoint -# -# CONFIG_PCI_ENDPOINT is not set - -# -# PCI switch controller drivers -# -# CONFIG_PCI_SW_SWITCHTEC is not set -CONFIG_ISA_DMA_API=y -CONFIG_AMD_NB=y -CONFIG_PCCARD=y -CONFIG_PCMCIA=y -CONFIG_PCMCIA_LOAD_CIS=y -CONFIG_CARDBUS=y - -# -# PC-card bridges -# -CONFIG_YENTA=m -CONFIG_YENTA_O2=y -CONFIG_YENTA_RICOH=y -CONFIG_YENTA_TI=y -CONFIG_YENTA_ENE_TUNE=y -CONFIG_YENTA_TOSHIBA=y -CONFIG_PD6729=m -CONFIG_I82092=m -CONFIG_PCCARD_NONSTATIC=y -# CONFIG_RAPIDIO is not set -# CONFIG_X86_SYSFB is not set - -# -# Binary Emulations -# -CONFIG_IA32_EMULATION=y -# CONFIG_IA32_AOUT is not set -CONFIG_X86_X32=y -CONFIG_COMPAT_32=y -CONFIG_COMPAT=y -CONFIG_COMPAT_FOR_U64_ALIGNMENT=y -CONFIG_SYSVIPC_COMPAT=y -CONFIG_X86_DEV_DMA_OPS=y -CONFIG_HAVE_GENERIC_GUP=y - -# -# Firmware Drivers -# -CONFIG_EDD=m -# CONFIG_EDD_OFF is not set -CONFIG_FIRMWARE_MEMMAP=y -CONFIG_DELL_RBU=m -CONFIG_DCDBAS=m -CONFIG_DMIID=y -CONFIG_DMI_SYSFS=y -CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y -CONFIG_ISCSI_IBFT_FIND=y -CONFIG_ISCSI_IBFT=m -# CONFIG_FW_CFG_SYSFS is not set -CONFIG_GOOGLE_FIRMWARE=y -CONFIG_GOOGLE_SMI=m -# CONFIG_GOOGLE_COREBOOT_TABLE_ACPI is not set -# CONFIG_GOOGLE_MEMCONSOLE_X86_LEGACY is not set - -# -# EFI (Extensible Firmware Interface) Support -# -CONFIG_EFI_VARS=m -CONFIG_EFI_ESRT=y -CONFIG_EFI_VARS_PSTORE=m -# CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE is not set -CONFIG_EFI_RUNTIME_MAP=y -# CONFIG_EFI_FAKE_MEMMAP is not set -CONFIG_EFI_RUNTIME_WRAPPERS=y -CONFIG_EFI_BOOTLOADER_CONTROL=m -CONFIG_EFI_CAPSULE_LOADER=m -CONFIG_EFI_TEST=m -CONFIG_APPLE_PROPERTIES=y -# CONFIG_RESET_ATTACK_MITIGATION is not set -CONFIG_UEFI_CPER=y -CONFIG_UEFI_CPER_X86=y -CONFIG_EFI_DEV_PATH_PARSER=y - -# -# Tegra firmware driver -# -CONFIG_HAVE_KVM=y -CONFIG_HAVE_KVM_IRQCHIP=y -CONFIG_HAVE_KVM_IRQFD=y -CONFIG_HAVE_KVM_IRQ_ROUTING=y -CONFIG_HAVE_KVM_EVENTFD=y -CONFIG_KVM_MMIO=y -CONFIG_KVM_ASYNC_PF=y -CONFIG_HAVE_KVM_MSI=y -CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT=y -CONFIG_KVM_VFIO=y -CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y -CONFIG_KVM_COMPAT=y -CONFIG_HAVE_KVM_IRQ_BYPASS=y -CONFIG_VIRTUALIZATION=y -CONFIG_KVM=m -CONFIG_KVM_INTEL=m -CONFIG_KVM_AMD=m -CONFIG_KVM_AMD_SEV=y -CONFIG_KVM_MMU_AUDIT=y -CONFIG_VHOST_NET=m -CONFIG_VHOST_SCSI=m -CONFIG_VHOST_VSOCK=m -CONFIG_VHOST=m -# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set - -# -# General architecture-dependent options -# -CONFIG_CRASH_CORE=y -CONFIG_KEXEC_CORE=y -CONFIG_HOTPLUG_SMT=y -CONFIG_OPROFILE=m -CONFIG_OPROFILE_EVENT_MULTIPLEX=y -CONFIG_HAVE_OPROFILE=y -CONFIG_OPROFILE_NMI_TIMER=y -CONFIG_KPROBES=y -CONFIG_JUMP_LABEL=y -# CONFIG_STATIC_KEYS_SELFTEST is not set -CONFIG_OPTPROBES=y -CONFIG_KPROBES_ON_FTRACE=y -CONFIG_UPROBES=y -CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y -CONFIG_ARCH_USE_BUILTIN_BSWAP=y -CONFIG_KRETPROBES=y -CONFIG_USER_RETURN_NOTIFIER=y -CONFIG_HAVE_IOREMAP_PROT=y -CONFIG_HAVE_KPROBES=y -CONFIG_HAVE_KRETPROBES=y -CONFIG_HAVE_OPTPROBES=y -CONFIG_HAVE_KPROBES_ON_FTRACE=y -CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y -CONFIG_HAVE_NMI=y -CONFIG_HAVE_ARCH_TRACEHOOK=y -CONFIG_HAVE_DMA_CONTIGUOUS=y -CONFIG_GENERIC_SMP_IDLE_THREAD=y -CONFIG_ARCH_HAS_FORTIFY_SOURCE=y -CONFIG_ARCH_HAS_SET_MEMORY=y -CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y -CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y -CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y -CONFIG_HAVE_RSEQ=y -CONFIG_HAVE_CLK=y -CONFIG_HAVE_HW_BREAKPOINT=y -CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y -CONFIG_HAVE_USER_RETURN_NOTIFIER=y -CONFIG_HAVE_PERF_EVENTS_NMI=y -CONFIG_HAVE_HARDLOCKUP_DETECTOR_PERF=y -CONFIG_HAVE_PERF_REGS=y -CONFIG_HAVE_PERF_USER_STACK_DUMP=y -CONFIG_HAVE_ARCH_JUMP_LABEL=y -CONFIG_HAVE_RCU_TABLE_FREE=y -CONFIG_HAVE_RCU_TABLE_INVALIDATE=y -CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y -CONFIG_HAVE_CMPXCHG_LOCAL=y -CONFIG_HAVE_CMPXCHG_DOUBLE=y -CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y -CONFIG_ARCH_WANT_OLD_COMPAT_IPC=y -CONFIG_HAVE_ARCH_SECCOMP_FILTER=y -CONFIG_SECCOMP_FILTER=y -CONFIG_HAVE_STACKPROTECTOR=y -CONFIG_CC_HAS_STACKPROTECTOR_NONE=y -CONFIG_STACKPROTECTOR=y -CONFIG_STACKPROTECTOR_STRONG=y -CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y -CONFIG_HAVE_CONTEXT_TRACKING=y -CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y -CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y -CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y -CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD=y -CONFIG_HAVE_ARCH_HUGE_VMAP=y -CONFIG_HAVE_ARCH_SOFT_DIRTY=y -CONFIG_HAVE_MOD_ARCH_SPECIFIC=y -CONFIG_MODULES_USE_ELF_RELA=y -CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK=y -CONFIG_ARCH_HAS_ELF_RANDOMIZE=y -CONFIG_HAVE_ARCH_MMAP_RND_BITS=y -CONFIG_HAVE_EXIT_THREAD=y -CONFIG_ARCH_MMAP_RND_BITS=28 -CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y -CONFIG_ARCH_MMAP_RND_COMPAT_BITS=8 -CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES=y -CONFIG_HAVE_COPY_THREAD_TLS=y -CONFIG_HAVE_STACK_VALIDATION=y -CONFIG_HAVE_RELIABLE_STACKTRACE=y -CONFIG_OLD_SIGSUSPEND3=y -CONFIG_COMPAT_OLD_SIGACTION=y -CONFIG_COMPAT_32BIT_TIME=y -CONFIG_HAVE_ARCH_VMAP_STACK=y -CONFIG_VMAP_STACK=y -CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y -CONFIG_STRICT_KERNEL_RWX=y -CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y -CONFIG_STRICT_MODULE_RWX=y -CONFIG_ARCH_HAS_REFCOUNT=y -# CONFIG_REFCOUNT_FULL is not set -CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y - -# -# GCOV-based kernel profiling -# -# CONFIG_GCOV_KERNEL is not set -CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y -CONFIG_PLUGIN_HOSTCC="" -CONFIG_HAVE_GCC_PLUGINS=y -CONFIG_RT_MUTEXES=y -CONFIG_BASE_SMALL=0 -CONFIG_MODULES=y -CONFIG_MODULE_FORCE_LOAD=y -CONFIG_MODULE_UNLOAD=y -CONFIG_MODULE_FORCE_UNLOAD=y -# CONFIG_MODVERSIONS is not set -# CONFIG_MODULE_SRCVERSION_ALL is not set -# CONFIG_MODULE_SIG is not set -# CONFIG_MODULE_COMPRESS is not set -CONFIG_MODULES_TREE_LOOKUP=y -CONFIG_BLOCK=y -CONFIG_BLK_SCSI_REQUEST=y -CONFIG_BLK_DEV_BSG=y -CONFIG_BLK_DEV_BSGLIB=y -CONFIG_BLK_DEV_INTEGRITY=y -# CONFIG_BLK_DEV_ZONED is not set -CONFIG_BLK_DEV_THROTTLING=y -# CONFIG_BLK_DEV_THROTTLING_LOW is not set -CONFIG_BLK_CMDLINE_PARSER=y -# CONFIG_BLK_WBT is not set -# CONFIG_BLK_CGROUP_IOLATENCY is not set -CONFIG_BLK_DEBUG_FS=y -# CONFIG_BLK_SED_OPAL is not set - -# -# Partition Types -# -CONFIG_PARTITION_ADVANCED=y -# CONFIG_ACORN_PARTITION is not set -# CONFIG_AIX_PARTITION is not set -CONFIG_OSF_PARTITION=y -CONFIG_AMIGA_PARTITION=y -# CONFIG_ATARI_PARTITION is not set -CONFIG_MAC_PARTITION=y -CONFIG_MSDOS_PARTITION=y -CONFIG_BSD_DISKLABEL=y -CONFIG_MINIX_SUBPARTITION=y -CONFIG_SOLARIS_X86_PARTITION=y -CONFIG_UNIXWARE_DISKLABEL=y -# CONFIG_LDM_PARTITION is not set -CONFIG_SGI_PARTITION=y -# CONFIG_ULTRIX_PARTITION is not set -CONFIG_SUN_PARTITION=y -CONFIG_KARMA_PARTITION=y -CONFIG_EFI_PARTITION=y -# CONFIG_SYSV68_PARTITION is not set -CONFIG_CMDLINE_PARTITION=y -CONFIG_BLOCK_COMPAT=y -CONFIG_BLK_MQ_PCI=y -CONFIG_BLK_MQ_VIRTIO=y -CONFIG_BLK_MQ_RDMA=y - -# -# IO Schedulers -# -CONFIG_IOSCHED_NOOP=y -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y -CONFIG_CFQ_GROUP_IOSCHED=y -CONFIG_DEFAULT_DEADLINE=y -# CONFIG_DEFAULT_CFQ is not set -# CONFIG_DEFAULT_NOOP is not set -CONFIG_DEFAULT_IOSCHED="deadline" -CONFIG_MQ_IOSCHED_DEADLINE=y -CONFIG_MQ_IOSCHED_KYBER=y -# CONFIG_IOSCHED_BFQ is not set -CONFIG_PREEMPT_NOTIFIERS=y -CONFIG_PADATA=y -CONFIG_ASN1=y -CONFIG_INLINE_SPIN_UNLOCK_IRQ=y -CONFIG_INLINE_READ_UNLOCK=y -CONFIG_INLINE_READ_UNLOCK_IRQ=y -CONFIG_INLINE_WRITE_UNLOCK=y -CONFIG_INLINE_WRITE_UNLOCK_IRQ=y -CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y -CONFIG_MUTEX_SPIN_ON_OWNER=y -CONFIG_RWSEM_SPIN_ON_OWNER=y -CONFIG_LOCK_SPIN_ON_OWNER=y -CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y -CONFIG_QUEUED_SPINLOCKS=y -CONFIG_ARCH_USE_QUEUED_RWLOCKS=y -CONFIG_QUEUED_RWLOCKS=y -CONFIG_ARCH_HAS_SYNC_CORE_BEFORE_USERMODE=y -CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y -CONFIG_FREEZER=y - -# -# Executable file formats -# -CONFIG_BINFMT_ELF=y -CONFIG_COMPAT_BINFMT_ELF=y -CONFIG_ELFCORE=y -CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y -CONFIG_BINFMT_SCRIPT=y -CONFIG_BINFMT_MISC=m -CONFIG_COREDUMP=y - -# -# Memory Management options -# -CONFIG_SELECT_MEMORY_MODEL=y -CONFIG_SPARSEMEM_MANUAL=y -CONFIG_SPARSEMEM=y -CONFIG_NEED_MULTIPLE_NODES=y -CONFIG_HAVE_MEMORY_PRESENT=y -CONFIG_SPARSEMEM_EXTREME=y -CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y -CONFIG_SPARSEMEM_VMEMMAP=y -CONFIG_HAVE_MEMBLOCK=y -CONFIG_HAVE_MEMBLOCK_NODE_MAP=y -CONFIG_ARCH_DISCARD_MEMBLOCK=y -CONFIG_MEMORY_ISOLATION=y -CONFIG_HAVE_BOOTMEM_INFO_NODE=y -CONFIG_MEMORY_HOTPLUG=y -CONFIG_MEMORY_HOTPLUG_SPARSE=y -# CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE is not set -CONFIG_MEMORY_HOTREMOVE=y -CONFIG_SPLIT_PTLOCK_CPUS=4 -CONFIG_MEMORY_BALLOON=y -CONFIG_BALLOON_COMPACTION=y -CONFIG_COMPACTION=y -CONFIG_MIGRATION=y -CONFIG_PHYS_ADDR_T_64BIT=y -CONFIG_BOUNCE=y -CONFIG_VIRT_TO_BUS=y -CONFIG_MMU_NOTIFIER=y -CONFIG_KSM=y -CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 -CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y -CONFIG_MEMORY_FAILURE=y -CONFIG_TRANSPARENT_HUGEPAGE=y -CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y -# CONFIG_TRANSPARENT_HUGEPAGE_MADVISE is not set -CONFIG_ARCH_WANTS_THP_SWAP=y -CONFIG_THP_SWAP=y -CONFIG_TRANSPARENT_HUGE_PAGECACHE=y -CONFIG_CLEANCACHE=y -CONFIG_FRONTSWAP=y -# CONFIG_CMA is not set -# CONFIG_ZSWAP is not set -CONFIG_ZPOOL=y -# CONFIG_ZBUD is not set -# CONFIG_Z3FOLD is not set -# CONFIG_ZSMALLOC is not set -CONFIG_GENERIC_EARLY_IOREMAP=y -# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set -# CONFIG_IDLE_PAGE_TRACKING is not set -CONFIG_ARCH_HAS_ZONE_DEVICE=y -CONFIG_ZONE_DEVICE=y -CONFIG_ARCH_HAS_HMM=y -CONFIG_DEV_PAGEMAP_OPS=y -# CONFIG_HMM_MIRROR is not set -# CONFIG_DEVICE_PRIVATE is not set -# CONFIG_DEVICE_PUBLIC is not set -CONFIG_FRAME_VECTOR=y -CONFIG_ARCH_USES_HIGH_VMA_FLAGS=y -CONFIG_ARCH_HAS_PKEYS=y -# CONFIG_PERCPU_STATS is not set -# CONFIG_GUP_BENCHMARK is not set -CONFIG_ARCH_HAS_PTE_SPECIAL=y -CONFIG_NET=y -CONFIG_COMPAT_NETLINK_MESSAGES=y -CONFIG_NET_INGRESS=y -CONFIG_NET_EGRESS=y - -# -# Networking options -# -CONFIG_PACKET=y -CONFIG_PACKET_DIAG=m -CONFIG_UNIX=y -CONFIG_UNIX_DIAG=m -# CONFIG_TLS is not set -CONFIG_XFRM=y -CONFIG_XFRM_ALGO=y -CONFIG_XFRM_USER=y -# CONFIG_XFRM_INTERFACE is not set -CONFIG_XFRM_SUB_POLICY=y -CONFIG_XFRM_MIGRATE=y -CONFIG_XFRM_STATISTICS=y -CONFIG_XFRM_IPCOMP=m -CONFIG_NET_KEY=m -CONFIG_NET_KEY_MIGRATE=y -# CONFIG_SMC is not set -# CONFIG_XDP_SOCKETS is not set -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_IP_FIB_TRIE_STATS=y -CONFIG_IP_MULTIPLE_TABLES=y -CONFIG_IP_ROUTE_MULTIPATH=y -CONFIG_IP_ROUTE_VERBOSE=y -CONFIG_IP_ROUTE_CLASSID=y -# CONFIG_IP_PNP is not set -CONFIG_NET_IPIP=m -CONFIG_NET_IPGRE_DEMUX=m -CONFIG_NET_IP_TUNNEL=m -CONFIG_NET_IPGRE=m -CONFIG_NET_IPGRE_BROADCAST=y -CONFIG_IP_MROUTE_COMMON=y -CONFIG_IP_MROUTE=y -CONFIG_IP_MROUTE_MULTIPLE_TABLES=y -CONFIG_IP_PIMSM_V1=y -CONFIG_IP_PIMSM_V2=y -CONFIG_SYN_COOKIES=y -CONFIG_NET_IPVTI=m -CONFIG_NET_UDP_TUNNEL=m -# CONFIG_NET_FOU is not set -# CONFIG_NET_FOU_IP_TUNNELS is not set -CONFIG_INET_AH=m -CONFIG_INET_ESP=m -# CONFIG_INET_ESP_OFFLOAD is not set -CONFIG_INET_IPCOMP=m -CONFIG_INET_XFRM_TUNNEL=m -CONFIG_INET_TUNNEL=m -CONFIG_INET_XFRM_MODE_TRANSPORT=m -CONFIG_INET_XFRM_MODE_TUNNEL=m -CONFIG_INET_XFRM_MODE_BEET=m -CONFIG_INET_DIAG=m -CONFIG_INET_TCP_DIAG=m -CONFIG_INET_UDP_DIAG=m -# CONFIG_INET_RAW_DIAG is not set -# CONFIG_INET_DIAG_DESTROY is not set -CONFIG_TCP_CONG_ADVANCED=y -CONFIG_TCP_CONG_BIC=m -CONFIG_TCP_CONG_CUBIC=y -CONFIG_TCP_CONG_WESTWOOD=m -CONFIG_TCP_CONG_HTCP=m -CONFIG_TCP_CONG_HSTCP=m -CONFIG_TCP_CONG_HYBLA=m -CONFIG_TCP_CONG_VEGAS=m -CONFIG_TCP_CONG_NV=m -CONFIG_TCP_CONG_SCALABLE=m -CONFIG_TCP_CONG_LP=m -CONFIG_TCP_CONG_VENO=m -CONFIG_TCP_CONG_YEAH=m -CONFIG_TCP_CONG_ILLINOIS=m -# CONFIG_TCP_CONG_DCTCP is not set -# CONFIG_TCP_CONG_CDG is not set -# CONFIG_TCP_CONG_BBR is not set -CONFIG_DEFAULT_CUBIC=y -# CONFIG_DEFAULT_RENO is not set -CONFIG_DEFAULT_TCP_CONG="cubic" -CONFIG_TCP_MD5SIG=y -CONFIG_IPV6=y -CONFIG_IPV6_ROUTER_PREF=y -CONFIG_IPV6_ROUTE_INFO=y -CONFIG_IPV6_OPTIMISTIC_DAD=y -CONFIG_INET6_AH=m -CONFIG_INET6_ESP=m -# CONFIG_INET6_ESP_OFFLOAD is not set -CONFIG_INET6_IPCOMP=m -CONFIG_IPV6_MIP6=y -CONFIG_IPV6_ILA=m -CONFIG_INET6_XFRM_TUNNEL=m -CONFIG_INET6_TUNNEL=m -CONFIG_INET6_XFRM_MODE_TRANSPORT=m -CONFIG_INET6_XFRM_MODE_TUNNEL=m -CONFIG_INET6_XFRM_MODE_BEET=m -CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m -CONFIG_IPV6_VTI=m -CONFIG_IPV6_SIT=m -CONFIG_IPV6_SIT_6RD=y -CONFIG_IPV6_NDISC_NODETYPE=y -CONFIG_IPV6_TUNNEL=m -CONFIG_IPV6_GRE=m -CONFIG_IPV6_MULTIPLE_TABLES=y -CONFIG_IPV6_SUBTREES=y -CONFIG_IPV6_MROUTE=y -CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y -CONFIG_IPV6_PIMSM_V2=y -# CONFIG_IPV6_SEG6_LWTUNNEL is not set -# CONFIG_IPV6_SEG6_HMAC is not set -CONFIG_NETLABEL=y -CONFIG_NETWORK_SECMARK=y -CONFIG_NET_PTP_CLASSIFY=y -CONFIG_NETWORK_PHY_TIMESTAMPING=y -CONFIG_NETFILTER=y -CONFIG_NETFILTER_ADVANCED=y -CONFIG_BRIDGE_NETFILTER=m - -# -# Core Netfilter Configuration -# -CONFIG_NETFILTER_INGRESS=y -CONFIG_NETFILTER_NETLINK=m -CONFIG_NETFILTER_FAMILY_BRIDGE=y -CONFIG_NETFILTER_FAMILY_ARP=y -CONFIG_NETFILTER_NETLINK_ACCT=m -CONFIG_NETFILTER_NETLINK_QUEUE=m -CONFIG_NETFILTER_NETLINK_LOG=m -CONFIG_NETFILTER_NETLINK_OSF=m -CONFIG_NF_CONNTRACK=m -CONFIG_NF_LOG_COMMON=m -# CONFIG_NF_LOG_NETDEV is not set -CONFIG_NETFILTER_CONNCOUNT=m -CONFIG_NF_CONNTRACK_MARK=y -CONFIG_NF_CONNTRACK_SECMARK=y -CONFIG_NF_CONNTRACK_ZONES=y -CONFIG_NF_CONNTRACK_PROCFS=y -CONFIG_NF_CONNTRACK_EVENTS=y -# CONFIG_NF_CONNTRACK_TIMEOUT is not set -CONFIG_NF_CONNTRACK_TIMESTAMP=y -CONFIG_NF_CONNTRACK_LABELS=y -CONFIG_NF_CT_PROTO_DCCP=y -CONFIG_NF_CT_PROTO_GRE=m -CONFIG_NF_CT_PROTO_SCTP=y -CONFIG_NF_CT_PROTO_UDPLITE=y -CONFIG_NF_CONNTRACK_AMANDA=m -CONFIG_NF_CONNTRACK_FTP=m -CONFIG_NF_CONNTRACK_H323=m -CONFIG_NF_CONNTRACK_IRC=m -CONFIG_NF_CONNTRACK_BROADCAST=m -CONFIG_NF_CONNTRACK_NETBIOS_NS=m -CONFIG_NF_CONNTRACK_SNMP=m -CONFIG_NF_CONNTRACK_PPTP=m -CONFIG_NF_CONNTRACK_SANE=m -CONFIG_NF_CONNTRACK_SIP=m -CONFIG_NF_CONNTRACK_TFTP=m -CONFIG_NF_CT_NETLINK=m -# CONFIG_NETFILTER_NETLINK_GLUE_CT is not set -CONFIG_NF_NAT=m -CONFIG_NF_NAT_NEEDED=y -CONFIG_NF_NAT_PROTO_DCCP=y -CONFIG_NF_NAT_PROTO_UDPLITE=y -CONFIG_NF_NAT_PROTO_SCTP=y -CONFIG_NF_NAT_AMANDA=m -CONFIG_NF_NAT_FTP=m -CONFIG_NF_NAT_IRC=m -CONFIG_NF_NAT_SIP=m -CONFIG_NF_NAT_TFTP=m -CONFIG_NF_NAT_REDIRECT=y -CONFIG_NF_TABLES=m -# CONFIG_NF_TABLES_SET is not set -# CONFIG_NF_TABLES_INET is not set -# CONFIG_NF_TABLES_NETDEV is not set -# CONFIG_NFT_NUMGEN is not set -CONFIG_NFT_CT=m -CONFIG_NFT_COUNTER=m -# CONFIG_NFT_CONNLIMIT is not set -CONFIG_NFT_LOG=m -CONFIG_NFT_LIMIT=m -# CONFIG_NFT_MASQ is not set -# CONFIG_NFT_REDIR is not set -CONFIG_NFT_NAT=m -# CONFIG_NFT_TUNNEL is not set -# CONFIG_NFT_OBJREF is not set -CONFIG_NFT_QUEUE=m -# CONFIG_NFT_QUOTA is not set -CONFIG_NFT_REJECT=m -CONFIG_NFT_COMPAT=m -CONFIG_NFT_HASH=m -# CONFIG_NFT_SOCKET is not set -# CONFIG_NFT_OSF is not set -# CONFIG_NFT_TPROXY is not set -# CONFIG_NF_FLOW_TABLE is not set -CONFIG_NETFILTER_XTABLES=y - -# -# Xtables combined modules -# -CONFIG_NETFILTER_XT_MARK=m -CONFIG_NETFILTER_XT_CONNMARK=m -CONFIG_NETFILTER_XT_SET=m - -# -# Xtables targets -# -CONFIG_NETFILTER_XT_TARGET_AUDIT=m -CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m -CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m -CONFIG_NETFILTER_XT_TARGET_CONNMARK=m -CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m -CONFIG_NETFILTER_XT_TARGET_CT=m -CONFIG_NETFILTER_XT_TARGET_DSCP=m -CONFIG_NETFILTER_XT_TARGET_HL=m -CONFIG_NETFILTER_XT_TARGET_HMARK=m -CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m -CONFIG_NETFILTER_XT_TARGET_LED=m -CONFIG_NETFILTER_XT_TARGET_LOG=m -CONFIG_NETFILTER_XT_TARGET_MARK=m -CONFIG_NETFILTER_XT_NAT=m -CONFIG_NETFILTER_XT_TARGET_NETMAP=m -CONFIG_NETFILTER_XT_TARGET_NFLOG=m -CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m -CONFIG_NETFILTER_XT_TARGET_RATEEST=m -CONFIG_NETFILTER_XT_TARGET_REDIRECT=m -CONFIG_NETFILTER_XT_TARGET_TEE=m -CONFIG_NETFILTER_XT_TARGET_TPROXY=m -CONFIG_NETFILTER_XT_TARGET_TRACE=m -CONFIG_NETFILTER_XT_TARGET_SECMARK=m -CONFIG_NETFILTER_XT_TARGET_TCPMSS=m -CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m - -# -# Xtables matches -# -CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m -CONFIG_NETFILTER_XT_MATCH_BPF=m -CONFIG_NETFILTER_XT_MATCH_CGROUP=m -CONFIG_NETFILTER_XT_MATCH_CLUSTER=m -CONFIG_NETFILTER_XT_MATCH_COMMENT=m -CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m -CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m -CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m -CONFIG_NETFILTER_XT_MATCH_CONNMARK=m -CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m -CONFIG_NETFILTER_XT_MATCH_CPU=m -CONFIG_NETFILTER_XT_MATCH_DCCP=m -CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m -CONFIG_NETFILTER_XT_MATCH_DSCP=m -CONFIG_NETFILTER_XT_MATCH_ECN=m -CONFIG_NETFILTER_XT_MATCH_ESP=m -CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m -CONFIG_NETFILTER_XT_MATCH_HELPER=m -CONFIG_NETFILTER_XT_MATCH_HL=m -CONFIG_NETFILTER_XT_MATCH_IPCOMP=m -CONFIG_NETFILTER_XT_MATCH_IPRANGE=m -CONFIG_NETFILTER_XT_MATCH_IPVS=m -CONFIG_NETFILTER_XT_MATCH_L2TP=m -CONFIG_NETFILTER_XT_MATCH_LENGTH=m -CONFIG_NETFILTER_XT_MATCH_LIMIT=m -CONFIG_NETFILTER_XT_MATCH_MAC=m -CONFIG_NETFILTER_XT_MATCH_MARK=m -CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m -CONFIG_NETFILTER_XT_MATCH_NFACCT=m -CONFIG_NETFILTER_XT_MATCH_OSF=m -CONFIG_NETFILTER_XT_MATCH_OWNER=m -CONFIG_NETFILTER_XT_MATCH_POLICY=m -CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m -CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m -CONFIG_NETFILTER_XT_MATCH_QUOTA=m -CONFIG_NETFILTER_XT_MATCH_RATEEST=m -CONFIG_NETFILTER_XT_MATCH_REALM=m -CONFIG_NETFILTER_XT_MATCH_RECENT=m -CONFIG_NETFILTER_XT_MATCH_SCTP=m -# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set -CONFIG_NETFILTER_XT_MATCH_STATE=m -CONFIG_NETFILTER_XT_MATCH_STATISTIC=m -CONFIG_NETFILTER_XT_MATCH_STRING=m -CONFIG_NETFILTER_XT_MATCH_TCPMSS=m -CONFIG_NETFILTER_XT_MATCH_TIME=m -CONFIG_NETFILTER_XT_MATCH_U32=m -CONFIG_IP_SET=m -CONFIG_IP_SET_MAX=256 -CONFIG_IP_SET_BITMAP_IP=m -CONFIG_IP_SET_BITMAP_IPMAC=m -CONFIG_IP_SET_BITMAP_PORT=m -CONFIG_IP_SET_HASH_IP=m -CONFIG_IP_SET_HASH_IPMARK=m -CONFIG_IP_SET_HASH_IPPORT=m -CONFIG_IP_SET_HASH_IPPORTIP=m -CONFIG_IP_SET_HASH_IPPORTNET=m -# CONFIG_IP_SET_HASH_IPMAC is not set -# CONFIG_IP_SET_HASH_MAC is not set -CONFIG_IP_SET_HASH_NETPORTNET=m -CONFIG_IP_SET_HASH_NET=m -CONFIG_IP_SET_HASH_NETNET=m -CONFIG_IP_SET_HASH_NETPORT=m -CONFIG_IP_SET_HASH_NETIFACE=m -CONFIG_IP_SET_LIST_SET=m -CONFIG_IP_VS=m -CONFIG_IP_VS_IPV6=y -# CONFIG_IP_VS_DEBUG is not set -CONFIG_IP_VS_TAB_BITS=12 - -# -# IPVS transport protocol load balancing support -# -CONFIG_IP_VS_PROTO_TCP=y -CONFIG_IP_VS_PROTO_UDP=y -CONFIG_IP_VS_PROTO_AH_ESP=y -CONFIG_IP_VS_PROTO_ESP=y -CONFIG_IP_VS_PROTO_AH=y -CONFIG_IP_VS_PROTO_SCTP=y - -# -# IPVS scheduler -# -CONFIG_IP_VS_RR=m -CONFIG_IP_VS_WRR=m -CONFIG_IP_VS_LC=m -CONFIG_IP_VS_WLC=m -# CONFIG_IP_VS_FO is not set -CONFIG_IP_VS_OVF=m -CONFIG_IP_VS_LBLC=m -CONFIG_IP_VS_LBLCR=m -CONFIG_IP_VS_DH=m -CONFIG_IP_VS_SH=m -# CONFIG_IP_VS_MH is not set -CONFIG_IP_VS_SED=m -CONFIG_IP_VS_NQ=m - -# -# IPVS SH scheduler -# -CONFIG_IP_VS_SH_TAB_BITS=8 - -# -# IPVS MH scheduler -# -CONFIG_IP_VS_MH_TAB_INDEX=12 - -# -# IPVS application helper -# -CONFIG_IP_VS_FTP=m -CONFIG_IP_VS_NFCT=y -CONFIG_IP_VS_PE_SIP=m - -# -# IP: Netfilter Configuration -# -CONFIG_NF_DEFRAG_IPV4=m -# CONFIG_NF_SOCKET_IPV4 is not set -CONFIG_NF_TPROXY_IPV4=m -# CONFIG_NF_TABLES_IPV4 is not set -# CONFIG_NF_TABLES_ARP is not set -CONFIG_NF_DUP_IPV4=m -CONFIG_NF_LOG_ARP=m -CONFIG_NF_LOG_IPV4=m -CONFIG_NF_REJECT_IPV4=y -CONFIG_NF_NAT_IPV4=m -CONFIG_NF_NAT_MASQUERADE_IPV4=y -CONFIG_NF_NAT_SNMP_BASIC=m -CONFIG_NF_NAT_PROTO_GRE=m -CONFIG_NF_NAT_PPTP=m -CONFIG_NF_NAT_H323=m -CONFIG_IP_NF_IPTABLES=y -CONFIG_IP_NF_MATCH_AH=m -CONFIG_IP_NF_MATCH_ECN=m -CONFIG_IP_NF_MATCH_RPFILTER=m -CONFIG_IP_NF_MATCH_TTL=m -CONFIG_IP_NF_FILTER=y -CONFIG_IP_NF_TARGET_REJECT=y -# CONFIG_IP_NF_TARGET_SYNPROXY is not set -CONFIG_IP_NF_NAT=m -CONFIG_IP_NF_TARGET_MASQUERADE=m -CONFIG_IP_NF_TARGET_NETMAP=m -CONFIG_IP_NF_TARGET_REDIRECT=m -CONFIG_IP_NF_MANGLE=m -CONFIG_IP_NF_TARGET_CLUSTERIP=m -CONFIG_IP_NF_TARGET_ECN=m -CONFIG_IP_NF_TARGET_TTL=m -CONFIG_IP_NF_RAW=m -CONFIG_IP_NF_SECURITY=m -CONFIG_IP_NF_ARPTABLES=m -CONFIG_IP_NF_ARPFILTER=m -CONFIG_IP_NF_ARP_MANGLE=m - -# -# IPv6: Netfilter Configuration -# -# CONFIG_NF_SOCKET_IPV6 is not set -CONFIG_NF_TPROXY_IPV6=m -# CONFIG_NF_TABLES_IPV6 is not set -CONFIG_NF_DUP_IPV6=m -CONFIG_NF_REJECT_IPV6=m -CONFIG_NF_LOG_IPV6=m -CONFIG_NF_NAT_IPV6=m -CONFIG_NF_NAT_MASQUERADE_IPV6=y -CONFIG_IP6_NF_IPTABLES=m -CONFIG_IP6_NF_MATCH_AH=m -CONFIG_IP6_NF_MATCH_EUI64=m -CONFIG_IP6_NF_MATCH_FRAG=m -CONFIG_IP6_NF_MATCH_OPTS=m -CONFIG_IP6_NF_MATCH_HL=m -CONFIG_IP6_NF_MATCH_IPV6HEADER=m -CONFIG_IP6_NF_MATCH_MH=m -CONFIG_IP6_NF_MATCH_RPFILTER=m -CONFIG_IP6_NF_MATCH_RT=m -# CONFIG_IP6_NF_MATCH_SRH is not set -CONFIG_IP6_NF_TARGET_HL=m -CONFIG_IP6_NF_FILTER=m -CONFIG_IP6_NF_TARGET_REJECT=m -# CONFIG_IP6_NF_TARGET_SYNPROXY is not set -CONFIG_IP6_NF_MANGLE=m -CONFIG_IP6_NF_RAW=m -CONFIG_IP6_NF_SECURITY=m -CONFIG_IP6_NF_NAT=m -CONFIG_IP6_NF_TARGET_MASQUERADE=m -CONFIG_IP6_NF_TARGET_NPT=m -CONFIG_NF_DEFRAG_IPV6=m -# CONFIG_NF_TABLES_BRIDGE is not set -CONFIG_BRIDGE_NF_EBTABLES=m -CONFIG_BRIDGE_EBT_BROUTE=m -CONFIG_BRIDGE_EBT_T_FILTER=m -CONFIG_BRIDGE_EBT_T_NAT=m -CONFIG_BRIDGE_EBT_802_3=m -CONFIG_BRIDGE_EBT_AMONG=m -CONFIG_BRIDGE_EBT_ARP=m -CONFIG_BRIDGE_EBT_IP=m -CONFIG_BRIDGE_EBT_IP6=m -CONFIG_BRIDGE_EBT_LIMIT=m -CONFIG_BRIDGE_EBT_MARK=m -CONFIG_BRIDGE_EBT_PKTTYPE=m -CONFIG_BRIDGE_EBT_STP=m -CONFIG_BRIDGE_EBT_VLAN=m -CONFIG_BRIDGE_EBT_ARPREPLY=m -CONFIG_BRIDGE_EBT_DNAT=m -CONFIG_BRIDGE_EBT_MARK_T=m -CONFIG_BRIDGE_EBT_REDIRECT=m -CONFIG_BRIDGE_EBT_SNAT=m -CONFIG_BRIDGE_EBT_LOG=m -CONFIG_BRIDGE_EBT_NFLOG=m -# CONFIG_BPFILTER is not set -CONFIG_IP_DCCP=m -CONFIG_INET_DCCP_DIAG=m - -# -# DCCP CCIDs Configuration -# -# CONFIG_IP_DCCP_CCID2_DEBUG is not set -CONFIG_IP_DCCP_CCID3=y -# CONFIG_IP_DCCP_CCID3_DEBUG is not set -CONFIG_IP_DCCP_TFRC_LIB=y -CONFIG_IP_SCTP=m -# CONFIG_SCTP_DBG_OBJCNT is not set -CONFIG_SCTP_DEFAULT_COOKIE_HMAC_MD5=y -# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1 is not set -# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_NONE is not set -CONFIG_SCTP_COOKIE_HMAC_MD5=y -CONFIG_SCTP_COOKIE_HMAC_SHA1=y -CONFIG_INET_SCTP_DIAG=m -CONFIG_RDS=m -CONFIG_RDS_RDMA=m -CONFIG_RDS_TCP=m -# CONFIG_RDS_DEBUG is not set -# CONFIG_TIPC is not set -CONFIG_ATM=m -CONFIG_ATM_CLIP=m -# CONFIG_ATM_CLIP_NO_ICMP is not set -CONFIG_ATM_LANE=m -# CONFIG_ATM_MPOA is not set -CONFIG_ATM_BR2684=m -# CONFIG_ATM_BR2684_IPFILTER is not set -CONFIG_L2TP=m -CONFIG_L2TP_DEBUGFS=m -CONFIG_L2TP_V3=y -CONFIG_L2TP_IP=m -CONFIG_L2TP_ETH=m -CONFIG_STP=m -CONFIG_GARP=m -CONFIG_MRP=m -CONFIG_BRIDGE=m -CONFIG_BRIDGE_IGMP_SNOOPING=y -CONFIG_BRIDGE_VLAN_FILTERING=y -CONFIG_HAVE_NET_DSA=y -CONFIG_NET_DSA=m -CONFIG_NET_DSA_LEGACY=y -CONFIG_NET_DSA_TAG_BRCM=y -CONFIG_NET_DSA_TAG_BRCM_PREPEND=y -CONFIG_NET_DSA_TAG_DSA=y -CONFIG_NET_DSA_TAG_EDSA=y -CONFIG_NET_DSA_TAG_TRAILER=y -CONFIG_NET_DSA_TAG_QCA=y -CONFIG_VLAN_8021Q=m -CONFIG_VLAN_8021Q_GVRP=y -CONFIG_VLAN_8021Q_MVRP=y -# CONFIG_DECNET is not set -CONFIG_LLC=m -# CONFIG_LLC2 is not set -CONFIG_ATALK=m -CONFIG_DEV_APPLETALK=m -CONFIG_IPDDP=m -CONFIG_IPDDP_ENCAP=y -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_PHONET is not set -CONFIG_6LOWPAN=m -# CONFIG_6LOWPAN_DEBUGFS is not set -CONFIG_6LOWPAN_NHC=m -CONFIG_6LOWPAN_NHC_DEST=m -CONFIG_6LOWPAN_NHC_FRAGMENT=m -CONFIG_6LOWPAN_NHC_HOP=m -CONFIG_6LOWPAN_NHC_IPV6=m -CONFIG_6LOWPAN_NHC_MOBILITY=m -CONFIG_6LOWPAN_NHC_ROUTING=m -CONFIG_6LOWPAN_NHC_UDP=m -# CONFIG_6LOWPAN_GHC_EXT_HDR_HOP is not set -# CONFIG_6LOWPAN_GHC_UDP is not set -# CONFIG_6LOWPAN_GHC_ICMPV6 is not set -# CONFIG_6LOWPAN_GHC_EXT_HDR_DEST is not set -# CONFIG_6LOWPAN_GHC_EXT_HDR_FRAG is not set -# CONFIG_6LOWPAN_GHC_EXT_HDR_ROUTE is not set -CONFIG_IEEE802154=m -# CONFIG_IEEE802154_NL802154_EXPERIMENTAL is not set -CONFIG_IEEE802154_SOCKET=m -CONFIG_IEEE802154_6LOWPAN=m -CONFIG_MAC802154=m -CONFIG_NET_SCHED=y - -# -# Queueing/Scheduling -# -CONFIG_NET_SCH_CBQ=m -CONFIG_NET_SCH_HTB=m -CONFIG_NET_SCH_HFSC=m -CONFIG_NET_SCH_ATM=m -CONFIG_NET_SCH_PRIO=m -CONFIG_NET_SCH_MULTIQ=m -CONFIG_NET_SCH_RED=m -CONFIG_NET_SCH_SFB=m -CONFIG_NET_SCH_SFQ=m -CONFIG_NET_SCH_TEQL=m -CONFIG_NET_SCH_TBF=m -# CONFIG_NET_SCH_CBS is not set -# CONFIG_NET_SCH_ETF is not set -CONFIG_NET_SCH_GRED=m -CONFIG_NET_SCH_DSMARK=m -CONFIG_NET_SCH_NETEM=m -CONFIG_NET_SCH_DRR=m -CONFIG_NET_SCH_MQPRIO=m -# CONFIG_NET_SCH_SKBPRIO is not set -CONFIG_NET_SCH_CHOKE=m -CONFIG_NET_SCH_QFQ=m -CONFIG_NET_SCH_CODEL=m -CONFIG_NET_SCH_FQ_CODEL=m -# CONFIG_NET_SCH_CAKE is not set -# CONFIG_NET_SCH_FQ is not set -CONFIG_NET_SCH_HHF=m -CONFIG_NET_SCH_PIE=m -CONFIG_NET_SCH_INGRESS=m -CONFIG_NET_SCH_PLUG=m -# CONFIG_NET_SCH_DEFAULT is not set - -# -# Classification -# -CONFIG_NET_CLS=y -CONFIG_NET_CLS_BASIC=m -CONFIG_NET_CLS_TCINDEX=m -CONFIG_NET_CLS_ROUTE4=m -CONFIG_NET_CLS_FW=m -CONFIG_NET_CLS_U32=m -CONFIG_CLS_U32_PERF=y -CONFIG_CLS_U32_MARK=y -CONFIG_NET_CLS_RSVP=m -CONFIG_NET_CLS_RSVP6=m -CONFIG_NET_CLS_FLOW=m -CONFIG_NET_CLS_CGROUP=y -CONFIG_NET_CLS_BPF=m -# CONFIG_NET_CLS_FLOWER is not set -CONFIG_NET_CLS_MATCHALL=m -CONFIG_NET_EMATCH=y -CONFIG_NET_EMATCH_STACK=32 -CONFIG_NET_EMATCH_CMP=m -CONFIG_NET_EMATCH_NBYTE=m -CONFIG_NET_EMATCH_U32=m -CONFIG_NET_EMATCH_META=m -CONFIG_NET_EMATCH_TEXT=m -CONFIG_NET_EMATCH_IPSET=m -# CONFIG_NET_EMATCH_IPT is not set -CONFIG_NET_CLS_ACT=y -CONFIG_NET_ACT_POLICE=m -CONFIG_NET_ACT_GACT=m -CONFIG_GACT_PROB=y -CONFIG_NET_ACT_MIRRED=m -# CONFIG_NET_ACT_SAMPLE is not set -CONFIG_NET_ACT_IPT=m -CONFIG_NET_ACT_NAT=m -CONFIG_NET_ACT_PEDIT=m -CONFIG_NET_ACT_SIMP=m -CONFIG_NET_ACT_SKBEDIT=m -CONFIG_NET_ACT_CSUM=m -# CONFIG_NET_ACT_VLAN is not set -CONFIG_NET_ACT_BPF=m -CONFIG_NET_ACT_CONNMARK=m -# CONFIG_NET_ACT_SKBMOD is not set -# CONFIG_NET_ACT_IFE is not set -# CONFIG_NET_ACT_TUNNEL_KEY is not set -CONFIG_NET_CLS_IND=y -CONFIG_NET_SCH_FIFO=y -CONFIG_DCB=y -CONFIG_DNS_RESOLVER=y -CONFIG_BATMAN_ADV=m -# CONFIG_BATMAN_ADV_BATMAN_V is not set -CONFIG_BATMAN_ADV_BLA=y -CONFIG_BATMAN_ADV_DAT=y -# CONFIG_BATMAN_ADV_NC is not set -# CONFIG_BATMAN_ADV_MCAST is not set -CONFIG_BATMAN_ADV_DEBUGFS=y -# CONFIG_BATMAN_ADV_DEBUG is not set -CONFIG_OPENVSWITCH=m -CONFIG_OPENVSWITCH_GRE=m -CONFIG_OPENVSWITCH_VXLAN=m -CONFIG_OPENVSWITCH_GENEVE=m -CONFIG_VSOCKETS=m -CONFIG_VSOCKETS_DIAG=m -CONFIG_VMWARE_VMCI_VSOCKETS=m -CONFIG_VIRTIO_VSOCKETS=m -CONFIG_VIRTIO_VSOCKETS_COMMON=m -# CONFIG_HYPERV_VSOCKETS is not set -CONFIG_NETLINK_DIAG=m -CONFIG_MPLS=y -CONFIG_NET_MPLS_GSO=m -CONFIG_MPLS_ROUTING=m -CONFIG_MPLS_IPTUNNEL=m -CONFIG_NET_NSH=m -CONFIG_HSR=m -CONFIG_NET_SWITCHDEV=y -CONFIG_NET_L3_MASTER_DEV=y -# CONFIG_NET_NCSI is not set -CONFIG_RPS=y -CONFIG_RFS_ACCEL=y -CONFIG_XPS=y -CONFIG_CGROUP_NET_PRIO=y -CONFIG_CGROUP_NET_CLASSID=y -CONFIG_NET_RX_BUSY_POLL=y -CONFIG_BQL=y -CONFIG_BPF_JIT=y -# CONFIG_BPF_STREAM_PARSER is not set -CONFIG_NET_FLOW_LIMIT=y - -# -# Network testing -# -CONFIG_NET_PKTGEN=m -CONFIG_NET_DROP_MONITOR=y -CONFIG_HAMRADIO=y - -# -# Packet Radio protocols -# -CONFIG_AX25=m -CONFIG_AX25_DAMA_SLAVE=y -CONFIG_NETROM=m -CONFIG_ROSE=m - -# -# AX.25 network device drivers -# -CONFIG_MKISS=m -CONFIG_6PACK=m -CONFIG_BPQETHER=m -CONFIG_BAYCOM_SER_FDX=m -CONFIG_BAYCOM_SER_HDX=m -CONFIG_BAYCOM_PAR=m -CONFIG_YAM=m -# CONFIG_CAN is not set -CONFIG_BT=m -CONFIG_BT_BREDR=y -CONFIG_BT_RFCOMM=m -CONFIG_BT_RFCOMM_TTY=y -CONFIG_BT_BNEP=m -CONFIG_BT_BNEP_MC_FILTER=y -CONFIG_BT_BNEP_PROTO_FILTER=y -CONFIG_BT_CMTP=m -CONFIG_BT_HIDP=m -CONFIG_BT_HS=y -CONFIG_BT_LE=y -CONFIG_BT_6LOWPAN=m -# CONFIG_BT_LEDS is not set -CONFIG_BT_DEBUGFS=y - -# -# Bluetooth device drivers -# -CONFIG_BT_INTEL=m -CONFIG_BT_BCM=m -CONFIG_BT_RTL=m -CONFIG_BT_HCIBTUSB=m -# CONFIG_BT_HCIBTUSB_AUTOSUSPEND is not set -CONFIG_BT_HCIBTUSB_BCM=y -CONFIG_BT_HCIBTUSB_RTL=y -CONFIG_BT_HCIBTSDIO=m -CONFIG_BT_HCIUART=m -CONFIG_BT_HCIUART_H4=y -CONFIG_BT_HCIUART_BCSP=y -CONFIG_BT_HCIUART_ATH3K=y -CONFIG_BT_HCIUART_INTEL=y -# CONFIG_BT_HCIUART_AG6XX is not set -# CONFIG_BT_HCIUART_MRVL is not set -CONFIG_BT_HCIBCM203X=m -CONFIG_BT_HCIBPA10X=m -CONFIG_BT_HCIBFUSB=m -CONFIG_BT_HCIDTL1=m -CONFIG_BT_HCIBT3C=m -CONFIG_BT_HCIBLUECARD=m -CONFIG_BT_HCIVHCI=m -CONFIG_BT_MRVL=m -CONFIG_BT_MRVL_SDIO=m -CONFIG_BT_ATH3K=m -CONFIG_BT_WILINK=m -CONFIG_BT_HCIRSI=m -# CONFIG_AF_RXRPC is not set -# CONFIG_AF_KCM is not set -CONFIG_FIB_RULES=y -CONFIG_WIRELESS=y -CONFIG_WIRELESS_EXT=y -CONFIG_WEXT_CORE=y -CONFIG_WEXT_PROC=y -CONFIG_WEXT_SPY=y -CONFIG_WEXT_PRIV=y -CONFIG_CFG80211=m -# CONFIG_NL80211_TESTMODE is not set -# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set -CONFIG_CFG80211_REQUIRE_SIGNED_REGDB=y -CONFIG_CFG80211_USE_KERNEL_REGDB_KEYS=y -# CONFIG_CFG80211_DEFAULT_PS is not set -CONFIG_CFG80211_DEBUGFS=y -CONFIG_CFG80211_CRDA_SUPPORT=y -CONFIG_CFG80211_WEXT=y -CONFIG_CFG80211_WEXT_EXPORT=y -CONFIG_LIB80211=m -CONFIG_LIB80211_CRYPT_WEP=m -CONFIG_LIB80211_CRYPT_CCMP=m -CONFIG_LIB80211_CRYPT_TKIP=m -# CONFIG_LIB80211_DEBUG is not set -CONFIG_MAC80211=m -CONFIG_MAC80211_HAS_RC=y -CONFIG_MAC80211_RC_MINSTREL=y -CONFIG_MAC80211_RC_MINSTREL_HT=y -CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y -CONFIG_MAC80211_RC_DEFAULT="minstrel_ht" -CONFIG_MAC80211_MESH=y -CONFIG_MAC80211_LEDS=y -CONFIG_MAC80211_DEBUGFS=y -CONFIG_MAC80211_MESSAGE_TRACING=y -# CONFIG_MAC80211_DEBUG_MENU is not set -CONFIG_MAC80211_STA_HASH_MAX_SIZE=0 -CONFIG_WIMAX=m -CONFIG_WIMAX_DEBUG_LEVEL=8 -CONFIG_RFKILL=m -CONFIG_RFKILL_LEDS=y -CONFIG_RFKILL_INPUT=y -CONFIG_RFKILL_GPIO=m -CONFIG_NET_9P=m -CONFIG_NET_9P_VIRTIO=m -# CONFIG_NET_9P_XEN is not set -CONFIG_NET_9P_RDMA=m -# CONFIG_NET_9P_DEBUG is not set -# CONFIG_CAIF is not set -CONFIG_CEPH_LIB=m -# CONFIG_CEPH_LIB_PRETTYDEBUG is not set -# CONFIG_CEPH_LIB_USE_DNS_RESOLVER is not set -CONFIG_NFC=m -CONFIG_NFC_DIGITAL=m -CONFIG_NFC_NCI=m -# CONFIG_NFC_NCI_UART is not set -CONFIG_NFC_HCI=m -CONFIG_NFC_SHDLC=y - -# -# Near Field Communication (NFC) devices -# -CONFIG_NFC_MEI_PHY=m -# CONFIG_NFC_SIM is not set -CONFIG_NFC_PORT100=m -CONFIG_NFC_FDP=m -CONFIG_NFC_FDP_I2C=m -CONFIG_NFC_PN544=m -CONFIG_NFC_PN544_I2C=m -CONFIG_NFC_PN544_MEI=m -# CONFIG_NFC_PN533_USB is not set -# CONFIG_NFC_PN533_I2C is not set -CONFIG_NFC_MICROREAD=m -CONFIG_NFC_MICROREAD_I2C=m -CONFIG_NFC_MICROREAD_MEI=m -CONFIG_NFC_MRVL=m -CONFIG_NFC_MRVL_USB=m -CONFIG_NFC_MRVL_I2C=m -CONFIG_NFC_ST21NFCA=m -CONFIG_NFC_ST21NFCA_I2C=m -# CONFIG_NFC_ST_NCI_I2C is not set -# CONFIG_NFC_NXP_NCI is not set -CONFIG_NFC_S3FWRN5=m -CONFIG_NFC_S3FWRN5_I2C=m -# CONFIG_PSAMPLE is not set -# CONFIG_NET_IFE is not set -CONFIG_LWTUNNEL=y -CONFIG_LWTUNNEL_BPF=y -CONFIG_DST_CACHE=y -CONFIG_GRO_CELLS=y -# CONFIG_NET_DEVLINK is not set -CONFIG_MAY_USE_DEVLINK=y -CONFIG_FAILOVER=m -CONFIG_HAVE_EBPF_JIT=y - -# -# Device Drivers -# - -# -# Generic Driver Options -# -CONFIG_UEVENT_HELPER=y -CONFIG_UEVENT_HELPER_PATH="" -CONFIG_DEVTMPFS=y -CONFIG_DEVTMPFS_MOUNT=y -CONFIG_STANDALONE=y -CONFIG_PREVENT_FIRMWARE_BUILD=y - -# -# Firmware loader -# -CONFIG_FW_LOADER=y -CONFIG_EXTRA_FIRMWARE="" -CONFIG_FW_LOADER_USER_HELPER=y -CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y -CONFIG_WANT_DEV_COREDUMP=y -CONFIG_ALLOW_DEV_COREDUMP=y -CONFIG_DEV_COREDUMP=y -# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set -CONFIG_SYS_HYPERVISOR=y -CONFIG_GENERIC_CPU_AUTOPROBE=y -CONFIG_GENERIC_CPU_VULNERABILITIES=y -CONFIG_REGMAP=y -CONFIG_REGMAP_I2C=m -CONFIG_REGMAP_MMIO=y -CONFIG_REGMAP_IRQ=y -CONFIG_DMA_SHARED_BUFFER=y -# CONFIG_DMA_FENCE_TRACE is not set - -# -# Bus devices -# -CONFIG_CONNECTOR=y -CONFIG_PROC_EVENTS=y -# CONFIG_GNSS is not set -CONFIG_MTD=m -# CONFIG_MTD_TESTS is not set -# CONFIG_MTD_REDBOOT_PARTS is not set -# CONFIG_MTD_CMDLINE_PARTS is not set -# CONFIG_MTD_AR7_PARTS is not set - -# -# Partition parsers -# - -# -# User Modules And Translation Layers -# -# CONFIG_MTD_BLOCK is not set -# CONFIG_MTD_BLOCK_RO is not set -# 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 -CONFIG_MTD_PARTITIONED_MASTER=y - -# -# RAM/ROM/Flash chip drivers -# -# CONFIG_MTD_CFI is not set -# CONFIG_MTD_JEDECPROBE is not set -CONFIG_MTD_MAP_BANK_WIDTH_1=y -CONFIG_MTD_MAP_BANK_WIDTH_2=y -CONFIG_MTD_MAP_BANK_WIDTH_4=y -CONFIG_MTD_CFI_I1=y -CONFIG_MTD_CFI_I2=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_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_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_ONENAND is not set -# CONFIG_MTD_NAND is not set - -# -# LPDDR & LPDDR2 PCM memory drivers -# -# CONFIG_MTD_LPDDR is not set -CONFIG_MTD_SPI_NOR=m -# CONFIG_MTD_MT81xx_NOR is not set -CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=y -# CONFIG_SPI_INTEL_SPI_PCI is not set -# CONFIG_SPI_INTEL_SPI_PLATFORM is not set -CONFIG_MTD_UBI=m -CONFIG_MTD_UBI_WL_THRESHOLD=4096 -CONFIG_MTD_UBI_BEB_LIMIT=20 -# CONFIG_MTD_UBI_FASTMAP is not set -# CONFIG_MTD_UBI_GLUEBI is not set -# CONFIG_MTD_UBI_BLOCK is not set -# CONFIG_OF is not set -CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y -CONFIG_PARPORT=m -CONFIG_PARPORT_PC=m -CONFIG_PARPORT_SERIAL=m -# CONFIG_PARPORT_PC_FIFO is not set -# CONFIG_PARPORT_PC_SUPERIO is not set -CONFIG_PARPORT_PC_PCMCIA=m -# CONFIG_PARPORT_AX88796 is not set -CONFIG_PARPORT_1284=y -CONFIG_PARPORT_NOT_PC=y -CONFIG_PNP=y -# CONFIG_PNP_DEBUG_MESSAGES is not set - -# -# Protocols -# -CONFIG_PNPACPI=y -CONFIG_BLK_DEV=y -# CONFIG_BLK_DEV_NULL_BLK is not set -CONFIG_BLK_DEV_FD=m -CONFIG_CDROM=y -# CONFIG_PARIDE is not set -CONFIG_BLK_DEV_PCIESSD_MTIP32XX=m -CONFIG_BLK_DEV_DAC960=m -CONFIG_BLK_DEV_UMEM=m -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 -CONFIG_BLK_DEV_CRYPTOLOOP=m -CONFIG_BLK_DEV_DRBD=m -# CONFIG_DRBD_FAULT_INJECTION is not set -CONFIG_BLK_DEV_NBD=m -CONFIG_BLK_DEV_SKD=m -CONFIG_BLK_DEV_SX8=m -CONFIG_BLK_DEV_RAM=m -CONFIG_BLK_DEV_RAM_COUNT=16 -CONFIG_BLK_DEV_RAM_SIZE=16384 -CONFIG_CDROM_PKTCDVD=m -CONFIG_CDROM_PKTCDVD_BUFFERS=8 -# CONFIG_CDROM_PKTCDVD_WCACHE is not set -CONFIG_ATA_OVER_ETH=m -CONFIG_XEN_BLKDEV_FRONTEND=m -CONFIG_XEN_BLKDEV_BACKEND=m -CONFIG_VIRTIO_BLK=m -# CONFIG_VIRTIO_BLK_SCSI is not set -CONFIG_BLK_DEV_RBD=m -CONFIG_BLK_DEV_RSXX=m - -# -# NVME Support -# -CONFIG_NVME_CORE=m -CONFIG_BLK_DEV_NVME=m -# CONFIG_NVME_MULTIPATH is not set -CONFIG_NVME_FABRICS=m -CONFIG_NVME_RDMA=m -# CONFIG_NVME_FC is not set -CONFIG_NVME_TARGET=m -CONFIG_NVME_TARGET_LOOP=m -CONFIG_NVME_TARGET_RDMA=m -# CONFIG_NVME_TARGET_FC is not set - -# -# Misc devices -# -CONFIG_SENSORS_LIS3LV02D=m -# CONFIG_AD525X_DPOT is not set -CONFIG_DUMMY_IRQ=m -# CONFIG_IBM_ASM is not set -# CONFIG_PHANTOM is not set -CONFIG_SGI_IOC4=m -CONFIG_TIFM_CORE=m -CONFIG_TIFM_7XX1=m -# CONFIG_ICS932S401 is not set -CONFIG_ENCLOSURE_SERVICES=m -CONFIG_HP_ILO=m -CONFIG_APDS9802ALS=m -CONFIG_ISL29003=m -CONFIG_ISL29020=m -CONFIG_SENSORS_TSL2550=m -CONFIG_SENSORS_BH1770=m -CONFIG_SENSORS_APDS990X=m -# CONFIG_HMC6352 is not set -# CONFIG_DS1682 is not set -CONFIG_VMWARE_BALLOON=m -# CONFIG_USB_SWITCH_FSA9480 is not set -# CONFIG_SRAM is not set -# CONFIG_PCI_ENDPOINT_TEST is not set -# CONFIG_C2PORT is not set - -# -# EEPROM support -# -CONFIG_EEPROM_AT24=m -CONFIG_EEPROM_LEGACY=m -CONFIG_EEPROM_MAX6875=m -CONFIG_EEPROM_93CX6=m -# CONFIG_EEPROM_IDT_89HPESX is not set -CONFIG_CB710_CORE=m -# CONFIG_CB710_DEBUG is not set -CONFIG_CB710_DEBUG_ASSUMPTIONS=y - -# -# Texas Instruments shared transport line discipline -# -CONFIG_TI_ST=m -CONFIG_SENSORS_LIS3_I2C=m - -# -# Altera FPGA firmware download module (requires I2C) -# -CONFIG_ALTERA_STAPL=m -CONFIG_INTEL_MEI=y -CONFIG_INTEL_MEI_ME=m -CONFIG_INTEL_MEI_TXE=m -CONFIG_VMWARE_VMCI=m - -# -# Intel MIC & related support -# - -# -# Intel MIC Bus Driver -# -CONFIG_INTEL_MIC_BUS=m - -# -# SCIF Bus Driver -# -# CONFIG_SCIF_BUS is not set - -# -# VOP Bus Driver -# -# CONFIG_VOP_BUS is not set - -# -# Intel MIC Host Driver -# - -# -# Intel MIC Card Driver -# - -# -# SCIF Driver -# - -# -# Intel MIC Coprocessor State Management (COSM) Drivers -# - -# -# VOP Driver -# -CONFIG_GENWQE=m -CONFIG_GENWQE_PLATFORM_ERROR_RECOVERY=1 -# CONFIG_ECHO is not set -# CONFIG_MISC_RTSX_PCI is not set -# CONFIG_MISC_RTSX_USB is not set -CONFIG_HAVE_IDE=y -# CONFIG_IDE is not set - -# -# SCSI device support -# -CONFIG_SCSI_MOD=y -CONFIG_RAID_ATTRS=m -CONFIG_SCSI=y -CONFIG_SCSI_DMA=y -CONFIG_SCSI_NETLINK=y -# CONFIG_SCSI_MQ_DEFAULT is not set -CONFIG_SCSI_PROC_FS=y - -# -# SCSI support type (disk, tape, CD-ROM) -# -CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_ST=m -CONFIG_CHR_DEV_OSST=m -CONFIG_BLK_DEV_SR=y -CONFIG_BLK_DEV_SR_VENDOR=y -CONFIG_CHR_DEV_SG=y -CONFIG_CHR_DEV_SCH=m -CONFIG_SCSI_ENCLOSURE=m -CONFIG_SCSI_CONSTANTS=y -CONFIG_SCSI_LOGGING=y -CONFIG_SCSI_SCAN_ASYNC=y - -# -# SCSI Transports -# -CONFIG_SCSI_SPI_ATTRS=m -CONFIG_SCSI_FC_ATTRS=m -CONFIG_SCSI_ISCSI_ATTRS=m -CONFIG_SCSI_SAS_ATTRS=m -CONFIG_SCSI_SAS_LIBSAS=m -CONFIG_SCSI_SAS_ATA=y -CONFIG_SCSI_SAS_HOST_SMP=y -CONFIG_SCSI_SRP_ATTRS=m -CONFIG_SCSI_LOWLEVEL=y -CONFIG_ISCSI_TCP=m -CONFIG_ISCSI_BOOT_SYSFS=m -CONFIG_SCSI_CXGB3_ISCSI=m -CONFIG_SCSI_CXGB4_ISCSI=m -CONFIG_SCSI_BNX2_ISCSI=m -CONFIG_SCSI_BNX2X_FCOE=m -CONFIG_BE2ISCSI=m -CONFIG_BLK_DEV_3W_XXXX_RAID=m -CONFIG_SCSI_HPSA=m -CONFIG_SCSI_3W_9XXX=m -CONFIG_SCSI_3W_SAS=m -CONFIG_SCSI_ACARD=m -CONFIG_SCSI_AACRAID=m -CONFIG_SCSI_AIC7XXX=m -CONFIG_AIC7XXX_CMDS_PER_DEVICE=4 -CONFIG_AIC7XXX_RESET_DELAY_MS=15000 -# CONFIG_AIC7XXX_DEBUG_ENABLE is not set -CONFIG_AIC7XXX_DEBUG_MASK=0 -# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set -CONFIG_SCSI_AIC79XX=m -CONFIG_AIC79XX_CMDS_PER_DEVICE=4 -CONFIG_AIC79XX_RESET_DELAY_MS=15000 -# CONFIG_AIC79XX_DEBUG_ENABLE is not set -CONFIG_AIC79XX_DEBUG_MASK=0 -# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set -CONFIG_SCSI_AIC94XX=m -# CONFIG_AIC94XX_DEBUG is not set -CONFIG_SCSI_MVSAS=m -# CONFIG_SCSI_MVSAS_DEBUG is not set -CONFIG_SCSI_MVSAS_TASKLET=y -CONFIG_SCSI_MVUMI=m -# CONFIG_SCSI_DPT_I2O is not set -CONFIG_SCSI_ADVANSYS=m -CONFIG_SCSI_ARCMSR=m -# CONFIG_SCSI_ESAS2R is not set -CONFIG_MEGARAID_NEWGEN=y -CONFIG_MEGARAID_MM=m -CONFIG_MEGARAID_MAILBOX=m -CONFIG_MEGARAID_LEGACY=m -CONFIG_MEGARAID_SAS=m -CONFIG_SCSI_MPT3SAS=m -CONFIG_SCSI_MPT2SAS_MAX_SGE=128 -CONFIG_SCSI_MPT3SAS_MAX_SGE=128 -CONFIG_SCSI_MPT2SAS=m -# CONFIG_SCSI_SMARTPQI is not set -CONFIG_SCSI_UFSHCD=m -CONFIG_SCSI_UFSHCD_PCI=m -CONFIG_SCSI_UFS_DWC_TC_PCI=m -CONFIG_SCSI_UFSHCD_PLATFORM=m -CONFIG_SCSI_UFS_DWC_TC_PLATFORM=m -CONFIG_SCSI_HPTIOP=m -CONFIG_SCSI_BUSLOGIC=m -# CONFIG_SCSI_FLASHPOINT is not set -CONFIG_VMWARE_PVSCSI=m -# CONFIG_XEN_SCSI_FRONTEND is not set -CONFIG_HYPERV_STORAGE=m -CONFIG_LIBFC=m -CONFIG_LIBFCOE=m -CONFIG_FCOE=m -CONFIG_FCOE_FNIC=m -# CONFIG_SCSI_SNIC is not set -# CONFIG_SCSI_DMX3191D is not set -CONFIG_SCSI_GDTH=m -CONFIG_SCSI_ISCI=m -CONFIG_SCSI_IPS=m -CONFIG_SCSI_INITIO=m -CONFIG_SCSI_INIA100=m -# CONFIG_SCSI_PPA is not set -# CONFIG_SCSI_IMM is not set -CONFIG_SCSI_STEX=m -CONFIG_SCSI_SYM53C8XX_2=m -CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 -CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 -CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 -CONFIG_SCSI_SYM53C8XX_MMIO=y -# CONFIG_SCSI_IPR is not set -CONFIG_SCSI_QLOGIC_1280=m -CONFIG_SCSI_QLA_FC=m -CONFIG_TCM_QLA2XXX=m -# CONFIG_TCM_QLA2XXX_DEBUG is not set -CONFIG_SCSI_QLA_ISCSI=m -# CONFIG_QEDI is not set -# CONFIG_QEDF is not set -CONFIG_SCSI_LPFC=m -# CONFIG_SCSI_LPFC_DEBUG_FS is not set -CONFIG_SCSI_DC395x=m -# CONFIG_SCSI_AM53C974 is not set -# CONFIG_SCSI_WD719X is not set -CONFIG_SCSI_DEBUG=m -CONFIG_SCSI_PMCRAID=m -CONFIG_SCSI_PM8001=m -CONFIG_SCSI_BFA_FC=m -CONFIG_SCSI_VIRTIO=m -CONFIG_SCSI_CHELSIO_FCOE=m -# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set -CONFIG_SCSI_DH=y -CONFIG_SCSI_DH_RDAC=m -CONFIG_SCSI_DH_HP_SW=m -CONFIG_SCSI_DH_EMC=m -CONFIG_SCSI_DH_ALUA=m -CONFIG_SCSI_OSD_INITIATOR=m -CONFIG_SCSI_OSD_ULD=m -CONFIG_SCSI_OSD_DPRINT_SENSE=1 -# CONFIG_SCSI_OSD_DEBUG is not set -CONFIG_ATA=y -CONFIG_ATA_VERBOSE_ERROR=y -CONFIG_ATA_ACPI=y -CONFIG_SATA_ZPODD=y -CONFIG_SATA_PMP=y - -# -# Controllers with non-SFF native interface -# -CONFIG_SATA_AHCI=y -CONFIG_SATA_MOBILE_LPM_POLICY=0 -CONFIG_SATA_AHCI_PLATFORM=m -CONFIG_SATA_INIC162X=m -CONFIG_SATA_ACARD_AHCI=m -CONFIG_SATA_SIL24=m -CONFIG_ATA_SFF=y - -# -# SFF controllers with custom DMA interface -# -CONFIG_PDC_ADMA=m -CONFIG_SATA_QSTOR=m -CONFIG_SATA_SX4=m -CONFIG_ATA_BMDMA=y - -# -# SATA SFF controllers with BMDMA -# -CONFIG_ATA_PIIX=y -# CONFIG_SATA_DWC is not set -CONFIG_SATA_MV=m -CONFIG_SATA_NV=m -CONFIG_SATA_PROMISE=m -CONFIG_SATA_SIL=m -CONFIG_SATA_SIS=m -CONFIG_SATA_SVW=m -CONFIG_SATA_ULI=m -CONFIG_SATA_VIA=m -CONFIG_SATA_VITESSE=m - -# -# PATA SFF controllers with BMDMA -# -CONFIG_PATA_ALI=m -CONFIG_PATA_AMD=m -CONFIG_PATA_ARTOP=m -CONFIG_PATA_ATIIXP=m -CONFIG_PATA_ATP867X=m -CONFIG_PATA_CMD64X=m -CONFIG_PATA_CYPRESS=m -CONFIG_PATA_EFAR=m -CONFIG_PATA_HPT366=m -CONFIG_PATA_HPT37X=m -CONFIG_PATA_HPT3X2N=m -CONFIG_PATA_HPT3X3=m -# CONFIG_PATA_HPT3X3_DMA is not set -CONFIG_PATA_IT8213=m -CONFIG_PATA_IT821X=m -CONFIG_PATA_JMICRON=m -CONFIG_PATA_MARVELL=m -CONFIG_PATA_NETCELL=m -CONFIG_PATA_NINJA32=m -CONFIG_PATA_NS87415=m -CONFIG_PATA_OLDPIIX=m -CONFIG_PATA_OPTIDMA=m -CONFIG_PATA_PDC2027X=m -CONFIG_PATA_PDC_OLD=m -# CONFIG_PATA_RADISYS is not set -CONFIG_PATA_RDC=m -CONFIG_PATA_SCH=m -CONFIG_PATA_SERVERWORKS=m -CONFIG_PATA_SIL680=m -CONFIG_PATA_SIS=m -CONFIG_PATA_TOSHIBA=m -CONFIG_PATA_TRIFLEX=m -CONFIG_PATA_VIA=m -CONFIG_PATA_WINBOND=m - -# -# PIO-only SFF controllers -# -CONFIG_PATA_CMD640_PCI=m -CONFIG_PATA_MPIIX=m -CONFIG_PATA_NS87410=m -CONFIG_PATA_OPTI=m -CONFIG_PATA_PCMCIA=m -# CONFIG_PATA_RZ1000 is not set - -# -# Generic fallback / legacy drivers -# -CONFIG_PATA_ACPI=m -CONFIG_ATA_GENERIC=m -# CONFIG_PATA_LEGACY is not set -CONFIG_MD=y -CONFIG_BLK_DEV_MD=y -CONFIG_MD_AUTODETECT=y -CONFIG_MD_LINEAR=m -CONFIG_MD_RAID0=m -CONFIG_MD_RAID1=m -CONFIG_MD_RAID10=m -CONFIG_MD_RAID456=m -CONFIG_MD_MULTIPATH=m -CONFIG_MD_FAULTY=m -CONFIG_MD_CLUSTER=m -CONFIG_BCACHE=m -# CONFIG_BCACHE_DEBUG is not set -# CONFIG_BCACHE_CLOSURES_DEBUG is not set -CONFIG_BLK_DEV_DM_BUILTIN=y -CONFIG_BLK_DEV_DM=y -CONFIG_DM_MQ_DEFAULT=y -CONFIG_DM_DEBUG=y -CONFIG_DM_BUFIO=y -# CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING is not set -CONFIG_DM_BIO_PRISON=m -CONFIG_DM_PERSISTENT_DATA=m -# CONFIG_DM_UNSTRIPED is not set -CONFIG_DM_CRYPT=m -CONFIG_DM_SNAPSHOT=y -CONFIG_DM_THIN_PROVISIONING=m -CONFIG_DM_CACHE=m -CONFIG_DM_CACHE_SMQ=m -# CONFIG_DM_WRITECACHE is not set -CONFIG_DM_ERA=m -CONFIG_DM_MIRROR=y -CONFIG_DM_LOG_USERSPACE=m -CONFIG_DM_RAID=m -CONFIG_DM_ZERO=y -CONFIG_DM_MULTIPATH=m -CONFIG_DM_MULTIPATH_QL=m -CONFIG_DM_MULTIPATH_ST=m -# CONFIG_DM_DELAY is not set -CONFIG_DM_UEVENT=y -CONFIG_DM_FLAKEY=m -CONFIG_DM_VERITY=m -# CONFIG_DM_VERITY_FEC is not set -# CONFIG_DM_SWITCH is not set -CONFIG_DM_LOG_WRITES=m -# CONFIG_DM_INTEGRITY is not set -CONFIG_TARGET_CORE=m -CONFIG_TCM_IBLOCK=m -CONFIG_TCM_FILEIO=m -CONFIG_TCM_PSCSI=m -CONFIG_TCM_USER2=m -CONFIG_LOOPBACK_TARGET=m -CONFIG_TCM_FC=m -CONFIG_ISCSI_TARGET=m -# CONFIG_ISCSI_TARGET_CXGB4 is not set -CONFIG_SBP_TARGET=m -CONFIG_FUSION=y -CONFIG_FUSION_SPI=m -CONFIG_FUSION_FC=m -CONFIG_FUSION_SAS=m -CONFIG_FUSION_MAX_SGE=40 -CONFIG_FUSION_CTL=m -CONFIG_FUSION_LAN=m -CONFIG_FUSION_LOGGING=y - -# -# IEEE 1394 (FireWire) support -# -CONFIG_FIREWIRE=m -CONFIG_FIREWIRE_OHCI=m -CONFIG_FIREWIRE_SBP2=m -CONFIG_FIREWIRE_NET=m -CONFIG_FIREWIRE_NOSY=m -CONFIG_MACINTOSH_DRIVERS=y -CONFIG_MAC_EMUMOUSEBTN=y -CONFIG_NETDEVICES=y -CONFIG_MII=m -CONFIG_NET_CORE=y -CONFIG_BONDING=m -CONFIG_DUMMY=m -CONFIG_EQUALIZER=m -CONFIG_NET_FC=y -CONFIG_IFB=m -CONFIG_NET_TEAM=m -CONFIG_NET_TEAM_MODE_BROADCAST=m -CONFIG_NET_TEAM_MODE_ROUNDROBIN=m -CONFIG_NET_TEAM_MODE_RANDOM=m -CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m -CONFIG_NET_TEAM_MODE_LOADBALANCE=m -CONFIG_MACVLAN=m -CONFIG_MACVTAP=m -CONFIG_IPVLAN=y -# CONFIG_IPVTAP is not set -CONFIG_VXLAN=m -CONFIG_GENEVE=m -# CONFIG_GTP is not set -# CONFIG_MACSEC is not set -CONFIG_NETCONSOLE=m -CONFIG_NETCONSOLE_DYNAMIC=y -CONFIG_NETPOLL=y -CONFIG_NET_POLL_CONTROLLER=y -CONFIG_TUN=m -CONFIG_TAP=m -# CONFIG_TUN_VNET_CROSS_LE is not set -CONFIG_VETH=m -CONFIG_VIRTIO_NET=m -# CONFIG_NLMON is not set -# CONFIG_NET_VRF is not set -# CONFIG_VSOCKMON is not set -CONFIG_SUNGEM_PHY=m -# CONFIG_ARCNET is not set -CONFIG_ATM_DRIVERS=y -# CONFIG_ATM_DUMMY is not set -CONFIG_ATM_TCP=m -# CONFIG_ATM_LANAI is not set -CONFIG_ATM_ENI=m -# CONFIG_ATM_ENI_DEBUG is not set -# CONFIG_ATM_ENI_TUNE_BURST is not set -CONFIG_ATM_FIRESTREAM=m -# CONFIG_ATM_ZATM is not set -CONFIG_ATM_NICSTAR=m -# CONFIG_ATM_NICSTAR_USE_SUNI is not set -# CONFIG_ATM_NICSTAR_USE_IDT77105 is not set -# CONFIG_ATM_IDT77252 is not set -# CONFIG_ATM_AMBASSADOR is not set -# CONFIG_ATM_HORIZON is not set -# CONFIG_ATM_IA is not set -# CONFIG_ATM_FORE200E is not set -CONFIG_ATM_HE=m -# CONFIG_ATM_HE_USE_SUNI is not set -CONFIG_ATM_SOLOS=m - -# -# CAIF transport drivers -# - -# -# Distributed Switch Architecture drivers -# -CONFIG_B53=m -CONFIG_B53_MDIO_DRIVER=m -CONFIG_B53_MMAP_DRIVER=m -CONFIG_B53_SRAB_DRIVER=m -# CONFIG_NET_DSA_BCM_SF2 is not set -# CONFIG_NET_DSA_LOOP is not set -# CONFIG_NET_DSA_MT7530 is not set -CONFIG_NET_DSA_MV88E6060=m -# CONFIG_MICROCHIP_KSZ is not set -CONFIG_NET_DSA_MV88E6XXX=m -CONFIG_NET_DSA_MV88E6XXX_GLOBAL2=y -# CONFIG_NET_DSA_MV88E6XXX_PTP is not set -CONFIG_NET_DSA_QCA8K=m -# CONFIG_NET_DSA_REALTEK_SMI is not set -# CONFIG_NET_DSA_SMSC_LAN9303_I2C is not set -# CONFIG_NET_DSA_SMSC_LAN9303_MDIO is not set -CONFIG_ETHERNET=y -CONFIG_MDIO=m -CONFIG_NET_VENDOR_3COM=y -CONFIG_PCMCIA_3C574=m -CONFIG_PCMCIA_3C589=m -CONFIG_VORTEX=m -CONFIG_TYPHOON=m -CONFIG_NET_VENDOR_ADAPTEC=y -CONFIG_ADAPTEC_STARFIRE=m -CONFIG_NET_VENDOR_AGERE=y -# CONFIG_ET131X is not set -CONFIG_NET_VENDOR_ALACRITECH=y -# CONFIG_SLICOSS is not set -CONFIG_NET_VENDOR_ALTEON=y -CONFIG_ACENIC=m -# CONFIG_ACENIC_OMIT_TIGON_I is not set -CONFIG_ALTERA_TSE=m -CONFIG_NET_VENDOR_AMAZON=y -CONFIG_ENA_ETHERNET=m -CONFIG_NET_VENDOR_AMD=y -CONFIG_AMD8111_ETH=m -CONFIG_PCNET32=m -CONFIG_PCMCIA_NMCLAN=m -# CONFIG_AMD_XGBE is not set -CONFIG_NET_VENDOR_AQUANTIA=y -# CONFIG_AQTION is not set -CONFIG_NET_VENDOR_ARC=y -CONFIG_NET_VENDOR_ATHEROS=y -CONFIG_ATL2=m -CONFIG_ATL1=m -CONFIG_ATL1E=m -CONFIG_ATL1C=m -CONFIG_ALX=m -# CONFIG_NET_VENDOR_AURORA is not set -CONFIG_NET_VENDOR_BROADCOM=y -CONFIG_B44=m -CONFIG_B44_PCI_AUTOSELECT=y -CONFIG_B44_PCICORE_AUTOSELECT=y -CONFIG_B44_PCI=y -# CONFIG_BCMGENET is not set -CONFIG_BNX2=m -CONFIG_CNIC=m -CONFIG_TIGON3=m -CONFIG_TIGON3_HWMON=y -CONFIG_BNX2X=m -CONFIG_BNX2X_SRIOV=y -# CONFIG_SYSTEMPORT is not set -CONFIG_BNXT=m -CONFIG_BNXT_SRIOV=y -CONFIG_BNXT_FLOWER_OFFLOAD=y -# CONFIG_BNXT_DCB is not set -CONFIG_BNXT_HWMON=y -CONFIG_NET_VENDOR_BROCADE=y -CONFIG_BNA=m -CONFIG_NET_VENDOR_CADENCE=y -CONFIG_MACB=m -CONFIG_MACB_USE_HWSTAMP=y -# CONFIG_MACB_PCI is not set -CONFIG_NET_VENDOR_CAVIUM=y -# CONFIG_THUNDER_NIC_PF is not set -# CONFIG_THUNDER_NIC_VF is not set -# CONFIG_THUNDER_NIC_BGX is not set -CONFIG_THUNDER_NIC_RGX=m -CONFIG_CAVIUM_PTP=y -# CONFIG_LIQUIDIO is not set -# CONFIG_LIQUIDIO_VF is not set -CONFIG_NET_VENDOR_CHELSIO=y -CONFIG_CHELSIO_T1=m -CONFIG_CHELSIO_T1_1G=y -CONFIG_CHELSIO_T3=m -CONFIG_CHELSIO_T4=m -CONFIG_CHELSIO_T4_DCB=y -CONFIG_CHELSIO_T4_FCOE=y -CONFIG_CHELSIO_T4VF=m -CONFIG_CHELSIO_LIB=m -CONFIG_NET_VENDOR_CISCO=y -CONFIG_ENIC=m -CONFIG_NET_VENDOR_CORTINA=y -CONFIG_CX_ECAT=m -CONFIG_DNET=m -CONFIG_NET_VENDOR_DEC=y -CONFIG_NET_TULIP=y -CONFIG_DE2104X=m -CONFIG_DE2104X_DSL=0 -CONFIG_TULIP=m -# CONFIG_TULIP_MWI is not set -CONFIG_TULIP_MMIO=y -# CONFIG_TULIP_NAPI is not set -CONFIG_DE4X5=m -CONFIG_WINBOND_840=m -CONFIG_DM9102=m -CONFIG_ULI526X=m -CONFIG_PCMCIA_XIRCOM=m -CONFIG_NET_VENDOR_DLINK=y -CONFIG_DL2K=m -CONFIG_SUNDANCE=m -# CONFIG_SUNDANCE_MMIO is not set -CONFIG_NET_VENDOR_EMULEX=y -CONFIG_BE2NET=m -CONFIG_BE2NET_HWMON=y -CONFIG_BE2NET_BE2=y -CONFIG_BE2NET_BE3=y -CONFIG_BE2NET_LANCER=y -CONFIG_BE2NET_SKYHAWK=y -CONFIG_NET_VENDOR_EZCHIP=y -# CONFIG_NET_VENDOR_FUJITSU is not set -# CONFIG_NET_VENDOR_HP is not set -CONFIG_NET_VENDOR_HUAWEI=y -# CONFIG_HINIC is not set -# CONFIG_NET_VENDOR_I825XX is not set -CONFIG_NET_VENDOR_INTEL=y -CONFIG_E100=m -CONFIG_E1000=m -CONFIG_E1000E=m -CONFIG_E1000E_HWTS=y -CONFIG_IGB=m -CONFIG_IGB_HWMON=y -CONFIG_IGB_DCA=y -CONFIG_IGBVF=m -CONFIG_IXGB=m -CONFIG_IXGBE=m -CONFIG_IXGBE_HWMON=y -CONFIG_IXGBE_DCA=y -CONFIG_IXGBE_DCB=y -CONFIG_IXGBEVF=m -CONFIG_I40E=m -CONFIG_I40E_DCB=y -CONFIG_I40EVF=m -# CONFIG_ICE is not set -# CONFIG_FM10K is not set -CONFIG_JME=m -CONFIG_NET_VENDOR_MARVELL=y -CONFIG_MVMDIO=m -CONFIG_SKGE=m -# CONFIG_SKGE_DEBUG is not set -CONFIG_SKGE_GENESIS=y -CONFIG_SKY2=m -# CONFIG_SKY2_DEBUG is not set -CONFIG_NET_VENDOR_MELLANOX=y -CONFIG_MLX4_EN=m -CONFIG_MLX4_EN_DCB=y -CONFIG_MLX4_CORE=m -CONFIG_MLX4_DEBUG=y -CONFIG_MLX4_CORE_GEN2=y -# CONFIG_MLX5_CORE is not set -CONFIG_MLXSW_CORE=m -CONFIG_MLXSW_CORE_HWMON=y -CONFIG_MLXSW_CORE_THERMAL=y -CONFIG_MLXSW_PCI=m -CONFIG_MLXSW_I2C=m -CONFIG_MLXSW_SWITCHIB=m -CONFIG_MLXSW_SWITCHX2=m -CONFIG_MLXSW_SPECTRUM=m -CONFIG_MLXSW_SPECTRUM_DCB=y -CONFIG_MLXSW_MINIMAL=m -CONFIG_MLXFW=m -CONFIG_NET_VENDOR_MICREL=y -# CONFIG_KS8842 is not set -# CONFIG_KS8851_MLL is not set -CONFIG_KSZ884X_PCI=m -CONFIG_NET_VENDOR_MICROSEMI=y -# CONFIG_MSCC_OCELOT_SWITCH is not set -CONFIG_NET_VENDOR_MYRI=y -CONFIG_MYRI10GE=m -CONFIG_MYRI10GE_DCA=y -CONFIG_FEALNX=m -CONFIG_NET_VENDOR_NATSEMI=y -CONFIG_NATSEMI=m -CONFIG_NS83820=m -CONFIG_NET_VENDOR_NETERION=y -CONFIG_S2IO=m -CONFIG_VXGE=m -# CONFIG_VXGE_DEBUG_TRACE_ALL is not set -CONFIG_NET_VENDOR_NETRONOME=y -# CONFIG_NFP is not set -CONFIG_NET_VENDOR_NI=y -CONFIG_NET_VENDOR_8390=y -CONFIG_PCMCIA_AXNET=m -CONFIG_NE2K_PCI=m -CONFIG_PCMCIA_PCNET=m -CONFIG_NET_VENDOR_NVIDIA=y -CONFIG_FORCEDETH=m -CONFIG_NET_VENDOR_OKI=y -CONFIG_ETHOC=m -CONFIG_NET_VENDOR_PACKET_ENGINES=y -CONFIG_HAMACHI=m -CONFIG_YELLOWFIN=m -CONFIG_NET_VENDOR_QLOGIC=y -CONFIG_QLA3XXX=m -CONFIG_QLCNIC=m -CONFIG_QLCNIC_SRIOV=y -CONFIG_QLCNIC_DCB=y -CONFIG_QLCNIC_HWMON=y -CONFIG_QLGE=m -CONFIG_NETXEN_NIC=m -CONFIG_QED=m -CONFIG_QED_LL2=y -CONFIG_QED_SRIOV=y -CONFIG_QEDE=m -CONFIG_QED_RDMA=y -CONFIG_QED_OOO=y -CONFIG_NET_VENDOR_QUALCOMM=y -CONFIG_QCOM_EMAC=m -# CONFIG_RMNET is not set -CONFIG_NET_VENDOR_RDC=y -CONFIG_R6040=m -CONFIG_NET_VENDOR_REALTEK=y -CONFIG_ATP=m -CONFIG_8139CP=m -CONFIG_8139TOO=m -# CONFIG_8139TOO_PIO is not set -# CONFIG_8139TOO_TUNE_TWISTER is not set -CONFIG_8139TOO_8129=y -# CONFIG_8139_OLD_RX_RESET is not set -CONFIG_R8169=m -CONFIG_NET_VENDOR_RENESAS=y -CONFIG_NET_VENDOR_ROCKER=y -CONFIG_ROCKER=m -CONFIG_NET_VENDOR_SAMSUNG=y -CONFIG_SXGBE_ETH=m -# CONFIG_NET_VENDOR_SEEQ is not set -CONFIG_NET_VENDOR_SOLARFLARE=y -CONFIG_SFC=m -# CONFIG_SFC_MTD is not set -CONFIG_SFC_MCDI_MON=y -CONFIG_SFC_SRIOV=y -CONFIG_SFC_MCDI_LOGGING=y -# CONFIG_SFC_FALCON is not set -CONFIG_NET_VENDOR_SILAN=y -CONFIG_SC92031=m -CONFIG_NET_VENDOR_SIS=y -CONFIG_SIS900=m -CONFIG_SIS190=m -CONFIG_NET_VENDOR_SMSC=y -CONFIG_PCMCIA_SMC91C92=m -CONFIG_EPIC100=m -CONFIG_SMSC911X=m -CONFIG_SMSC9420=m -CONFIG_NET_VENDOR_SOCIONEXT=y -CONFIG_NET_VENDOR_STMICRO=y -CONFIG_STMMAC_ETH=m -# CONFIG_STMMAC_PLATFORM is not set -# CONFIG_STMMAC_PCI is not set -CONFIG_NET_VENDOR_SUN=y -CONFIG_HAPPYMEAL=m -CONFIG_SUNGEM=m -CONFIG_CASSINI=m -CONFIG_NIU=m -CONFIG_NET_VENDOR_SYNOPSYS=y -# CONFIG_DWC_XLGMAC is not set -CONFIG_NET_VENDOR_TEHUTI=y -CONFIG_TEHUTI=m -CONFIG_NET_VENDOR_TI=y -CONFIG_TI_CPSW_ALE=m -CONFIG_TLAN=m -CONFIG_NET_VENDOR_VIA=y -CONFIG_VIA_RHINE=m -CONFIG_VIA_RHINE_MMIO=y -CONFIG_VIA_VELOCITY=m -CONFIG_NET_VENDOR_WIZNET=y -CONFIG_WIZNET_W5100=m -CONFIG_WIZNET_W5300=m -# CONFIG_WIZNET_BUS_DIRECT is not set -# CONFIG_WIZNET_BUS_INDIRECT is not set -CONFIG_WIZNET_BUS_ANY=y -CONFIG_NET_VENDOR_XIRCOM=y -CONFIG_PCMCIA_XIRC2PS=m -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -# CONFIG_NET_SB1000 is not set -CONFIG_MDIO_DEVICE=y -CONFIG_MDIO_BUS=y -# CONFIG_MDIO_BCM_UNIMAC is not set -CONFIG_MDIO_BITBANG=m -CONFIG_MDIO_CAVIUM=m -CONFIG_MDIO_GPIO=m -# CONFIG_MDIO_MSCC_MIIM is not set -CONFIG_MDIO_THUNDER=m -CONFIG_PHYLINK=m -CONFIG_PHYLIB=y -CONFIG_SWPHY=y -# CONFIG_LED_TRIGGER_PHY is not set - -# -# MII PHY device drivers -# -# CONFIG_SFP is not set -CONFIG_AMD_PHY=m -CONFIG_AQUANTIA_PHY=m -# CONFIG_ASIX_PHY is not set -CONFIG_AT803X_PHY=m -CONFIG_BCM7XXX_PHY=m -CONFIG_BCM87XX_PHY=m -CONFIG_BCM_NET_PHYLIB=m -CONFIG_BROADCOM_PHY=m -CONFIG_CICADA_PHY=m -# CONFIG_CORTINA_PHY is not set -CONFIG_DAVICOM_PHY=m -# CONFIG_DP83822_PHY is not set -# CONFIG_DP83TC811_PHY is not set -CONFIG_DP83848_PHY=m -# CONFIG_DP83867_PHY is not set -CONFIG_FIXED_PHY=y -CONFIG_ICPLUS_PHY=m -CONFIG_INTEL_XWAY_PHY=m -CONFIG_LSI_ET1011C_PHY=m -CONFIG_LXT_PHY=m -CONFIG_MARVELL_PHY=m -# CONFIG_MARVELL_10G_PHY is not set -CONFIG_MICREL_PHY=m -CONFIG_MICROCHIP_PHY=m -# CONFIG_MICROCHIP_T1_PHY is not set -CONFIG_MICROSEMI_PHY=m -CONFIG_NATIONAL_PHY=m -CONFIG_QSEMI_PHY=m -CONFIG_REALTEK_PHY=m -# CONFIG_RENESAS_PHY is not set -# CONFIG_ROCKCHIP_PHY is not set -CONFIG_SMSC_PHY=m -CONFIG_STE10XP=m -CONFIG_TERANETICS_PHY=m -CONFIG_VITESSE_PHY=m -CONFIG_XILINX_GMII2RGMII=m -# CONFIG_PLIP is not set -CONFIG_PPP=m -CONFIG_PPP_BSDCOMP=m -CONFIG_PPP_DEFLATE=m -CONFIG_PPP_FILTER=y -CONFIG_PPP_MPPE=m -CONFIG_PPP_MULTILINK=y -CONFIG_PPPOATM=m -CONFIG_PPPOE=m -CONFIG_PPTP=m -CONFIG_PPPOL2TP=m -CONFIG_PPP_ASYNC=m -CONFIG_PPP_SYNC_TTY=m -CONFIG_SLIP=m -CONFIG_SLHC=m -CONFIG_SLIP_COMPRESSED=y -CONFIG_SLIP_SMART=y -# CONFIG_SLIP_MODE_SLIP6 is not set -CONFIG_USB_NET_DRIVERS=m -CONFIG_USB_CATC=m -CONFIG_USB_KAWETH=m -CONFIG_USB_PEGASUS=m -CONFIG_USB_RTL8150=m -CONFIG_USB_RTL8152=m -CONFIG_USB_LAN78XX=m -CONFIG_USB_USBNET=m -CONFIG_USB_NET_AX8817X=m -CONFIG_USB_NET_AX88179_178A=m -CONFIG_USB_NET_CDCETHER=m -CONFIG_USB_NET_CDC_EEM=m -CONFIG_USB_NET_CDC_NCM=m -CONFIG_USB_NET_HUAWEI_CDC_NCM=m -CONFIG_USB_NET_CDC_MBIM=m -CONFIG_USB_NET_DM9601=m -CONFIG_USB_NET_SR9700=m -CONFIG_USB_NET_SR9800=m -CONFIG_USB_NET_SMSC75XX=m -CONFIG_USB_NET_SMSC95XX=m -CONFIG_USB_NET_GL620A=m -CONFIG_USB_NET_NET1080=m -CONFIG_USB_NET_PLUSB=m -CONFIG_USB_NET_MCS7830=m -CONFIG_USB_NET_RNDIS_HOST=m -CONFIG_USB_NET_CDC_SUBSET_ENABLE=m -CONFIG_USB_NET_CDC_SUBSET=m -CONFIG_USB_ALI_M5632=y -CONFIG_USB_AN2720=y -CONFIG_USB_BELKIN=y -CONFIG_USB_ARMLINUX=y -CONFIG_USB_EPSON2888=y -CONFIG_USB_KC2190=y -CONFIG_USB_NET_ZAURUS=m -CONFIG_USB_NET_CX82310_ETH=m -CONFIG_USB_NET_KALMIA=m -CONFIG_USB_NET_QMI_WWAN=m -CONFIG_USB_HSO=m -CONFIG_USB_NET_INT51X1=m -CONFIG_USB_IPHETH=m -CONFIG_USB_SIERRA_NET=m -CONFIG_USB_VL600=m -CONFIG_USB_NET_CH9200=m -CONFIG_WLAN=y -CONFIG_WLAN_VENDOR_ADMTEK=y -# CONFIG_ADM8211 is not set -CONFIG_ATH_COMMON=m -CONFIG_WLAN_VENDOR_ATH=y -# CONFIG_ATH_DEBUG is not set -CONFIG_ATH5K=m -CONFIG_ATH5K_DEBUG=y -# CONFIG_ATH5K_TRACER is not set -CONFIG_ATH5K_PCI=y -CONFIG_ATH9K_HW=m -CONFIG_ATH9K_COMMON=m -CONFIG_ATH9K_COMMON_DEBUG=y -CONFIG_ATH9K_BTCOEX_SUPPORT=y -CONFIG_ATH9K=m -CONFIG_ATH9K_PCI=y -CONFIG_ATH9K_AHB=y -CONFIG_ATH9K_DEBUGFS=y -# CONFIG_ATH9K_STATION_STATISTICS is not set -# CONFIG_ATH9K_DYNACK is not set -CONFIG_ATH9K_WOW=y -CONFIG_ATH9K_RFKILL=y -# CONFIG_ATH9K_CHANNEL_CONTEXT is not set -CONFIG_ATH9K_PCOEM=y -CONFIG_ATH9K_HTC=m -# CONFIG_ATH9K_HTC_DEBUGFS is not set -CONFIG_ATH9K_HWRNG=y -# CONFIG_ATH9K_COMMON_SPECTRAL is not set -CONFIG_CARL9170=m -CONFIG_CARL9170_LEDS=y -# CONFIG_CARL9170_DEBUGFS is not set -CONFIG_CARL9170_WPC=y -CONFIG_CARL9170_HWRNG=y -CONFIG_ATH6KL=m -CONFIG_ATH6KL_SDIO=m -CONFIG_ATH6KL_USB=m -# CONFIG_ATH6KL_DEBUG is not set -# CONFIG_ATH6KL_TRACING is not set -CONFIG_AR5523=m -CONFIG_WIL6210=m -CONFIG_WIL6210_ISR_COR=y -CONFIG_WIL6210_TRACING=y -CONFIG_WIL6210_DEBUGFS=y -CONFIG_ATH10K=m -CONFIG_ATH10K_CE=y -CONFIG_ATH10K_PCI=m -# CONFIG_ATH10K_SDIO is not set -# CONFIG_ATH10K_USB is not set -CONFIG_ATH10K_DEBUG=y -# CONFIG_ATH10K_DEBUGFS is not set -# CONFIG_ATH10K_TRACING is not set -CONFIG_WCN36XX=m -# CONFIG_WCN36XX_DEBUGFS is not set -CONFIG_WLAN_VENDOR_ATMEL=y -# CONFIG_ATMEL is not set -CONFIG_AT76C50X_USB=m -CONFIG_WLAN_VENDOR_BROADCOM=y -CONFIG_B43=m -CONFIG_B43_BCMA=y -CONFIG_B43_SSB=y -CONFIG_B43_BUSES_BCMA_AND_SSB=y -# CONFIG_B43_BUSES_BCMA is not set -# CONFIG_B43_BUSES_SSB is not set -CONFIG_B43_PCI_AUTOSELECT=y -CONFIG_B43_PCICORE_AUTOSELECT=y -CONFIG_B43_SDIO=y -CONFIG_B43_BCMA_PIO=y -CONFIG_B43_PIO=y -CONFIG_B43_PHY_G=y -CONFIG_B43_PHY_N=y -CONFIG_B43_PHY_LP=y -CONFIG_B43_PHY_HT=y -CONFIG_B43_LEDS=y -CONFIG_B43_HWRNG=y -CONFIG_B43_DEBUG=y -CONFIG_B43LEGACY=m -CONFIG_B43LEGACY_PCI_AUTOSELECT=y -CONFIG_B43LEGACY_PCICORE_AUTOSELECT=y -CONFIG_B43LEGACY_LEDS=y -CONFIG_B43LEGACY_HWRNG=y -CONFIG_B43LEGACY_DEBUG=y -CONFIG_B43LEGACY_DMA=y -CONFIG_B43LEGACY_PIO=y -CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y -# CONFIG_B43LEGACY_DMA_MODE is not set -# CONFIG_B43LEGACY_PIO_MODE is not set -CONFIG_BRCMUTIL=m -CONFIG_BRCMSMAC=m -CONFIG_BRCMFMAC=m -CONFIG_BRCMFMAC_PROTO_BCDC=y -CONFIG_BRCMFMAC_PROTO_MSGBUF=y -CONFIG_BRCMFMAC_SDIO=y -CONFIG_BRCMFMAC_USB=y -CONFIG_BRCMFMAC_PCIE=y -# CONFIG_BRCM_TRACING is not set -# CONFIG_BRCMDBG is not set -CONFIG_WLAN_VENDOR_CISCO=y -# CONFIG_AIRO is not set -# CONFIG_AIRO_CS is not set -CONFIG_WLAN_VENDOR_INTEL=y -CONFIG_IPW2100=m -CONFIG_IPW2100_MONITOR=y -# CONFIG_IPW2100_DEBUG is not set -CONFIG_IPW2200=m -CONFIG_IPW2200_MONITOR=y -CONFIG_IPW2200_RADIOTAP=y -CONFIG_IPW2200_PROMISCUOUS=y -CONFIG_IPW2200_QOS=y -# CONFIG_IPW2200_DEBUG is not set -CONFIG_LIBIPW=m -# CONFIG_LIBIPW_DEBUG is not set -CONFIG_IWLEGACY=m -CONFIG_IWL4965=m -CONFIG_IWL3945=m - -# -# iwl3945 / iwl4965 Debugging Options -# -CONFIG_IWLEGACY_DEBUG=y -CONFIG_IWLEGACY_DEBUGFS=y -CONFIG_IWLWIFI=m -CONFIG_IWLWIFI_LEDS=y -CONFIG_IWLDVM=m -CONFIG_IWLMVM=m -CONFIG_IWLWIFI_OPMODE_MODULAR=y -# CONFIG_IWLWIFI_BCAST_FILTERING is not set - -# -# Debugging Options -# -CONFIG_IWLWIFI_DEBUG=y -CONFIG_IWLWIFI_DEBUGFS=y -CONFIG_IWLWIFI_DEVICE_TRACING=y -CONFIG_WLAN_VENDOR_INTERSIL=y -# CONFIG_HOSTAP is not set -# CONFIG_HERMES is not set -CONFIG_P54_COMMON=m -CONFIG_P54_USB=m -CONFIG_P54_PCI=m -CONFIG_P54_LEDS=y -# CONFIG_PRISM54 is not set -CONFIG_WLAN_VENDOR_MARVELL=y -CONFIG_LIBERTAS=m -CONFIG_LIBERTAS_USB=m -CONFIG_LIBERTAS_CS=m -CONFIG_LIBERTAS_SDIO=m -# CONFIG_LIBERTAS_DEBUG is not set -CONFIG_LIBERTAS_MESH=y -# CONFIG_LIBERTAS_THINFIRM is not set -CONFIG_MWIFIEX=m -CONFIG_MWIFIEX_SDIO=m -CONFIG_MWIFIEX_PCIE=m -CONFIG_MWIFIEX_USB=m -CONFIG_MWL8K=m -CONFIG_WLAN_VENDOR_MEDIATEK=y -CONFIG_MT7601U=m -# CONFIG_MT76x0U is not set -# CONFIG_MT76x2E is not set -# CONFIG_MT76x2U is not set -CONFIG_WLAN_VENDOR_RALINK=y -CONFIG_RT2X00=m -CONFIG_RT2400PCI=m -CONFIG_RT2500PCI=m -CONFIG_RT61PCI=m -CONFIG_RT2800PCI=m -CONFIG_RT2800PCI_RT33XX=y -CONFIG_RT2800PCI_RT35XX=y -CONFIG_RT2800PCI_RT53XX=y -CONFIG_RT2800PCI_RT3290=y -CONFIG_RT2500USB=m -CONFIG_RT73USB=m -CONFIG_RT2800USB=m -CONFIG_RT2800USB_RT33XX=y -CONFIG_RT2800USB_RT35XX=y -# CONFIG_RT2800USB_RT3573 is not set -CONFIG_RT2800USB_RT53XX=y -CONFIG_RT2800USB_RT55XX=y -CONFIG_RT2800USB_UNKNOWN=y -CONFIG_RT2800_LIB=m -CONFIG_RT2800_LIB_MMIO=m -CONFIG_RT2X00_LIB_MMIO=m -CONFIG_RT2X00_LIB_PCI=m -CONFIG_RT2X00_LIB_USB=m -CONFIG_RT2X00_LIB=m -CONFIG_RT2X00_LIB_FIRMWARE=y -CONFIG_RT2X00_LIB_CRYPTO=y -CONFIG_RT2X00_LIB_LEDS=y -CONFIG_RT2X00_LIB_DEBUGFS=y -# CONFIG_RT2X00_DEBUG is not set -CONFIG_WLAN_VENDOR_REALTEK=y -CONFIG_RTL8180=m -CONFIG_RTL8187=m -CONFIG_RTL8187_LEDS=y -CONFIG_RTL_CARDS=m -CONFIG_RTL8192CE=m -CONFIG_RTL8192SE=m -CONFIG_RTL8192DE=m -CONFIG_RTL8723AE=m -CONFIG_RTL8723BE=m -CONFIG_RTL8188EE=m -CONFIG_RTL8192EE=m -CONFIG_RTL8821AE=m -CONFIG_RTL8192CU=m -CONFIG_RTLWIFI=m -CONFIG_RTLWIFI_PCI=m -CONFIG_RTLWIFI_USB=m -# CONFIG_RTLWIFI_DEBUG is not set -CONFIG_RTL8192C_COMMON=m -CONFIG_RTL8723_COMMON=m -CONFIG_RTLBTCOEXIST=m -CONFIG_RTL8XXXU=m -# CONFIG_RTL8XXXU_UNTESTED is not set -CONFIG_WLAN_VENDOR_RSI=y -CONFIG_RSI_91X=m -CONFIG_RSI_DEBUGFS=y -CONFIG_RSI_SDIO=m -CONFIG_RSI_USB=m -CONFIG_RSI_COEX=y -CONFIG_WLAN_VENDOR_ST=y -CONFIG_CW1200=m -CONFIG_CW1200_WLAN_SDIO=m -CONFIG_WLAN_VENDOR_TI=y -# CONFIG_WL1251 is not set -# CONFIG_WL12XX is not set -# CONFIG_WL18XX is not set -# CONFIG_WLCORE is not set -CONFIG_WLAN_VENDOR_ZYDAS=y -# CONFIG_USB_ZD1201 is not set -CONFIG_ZD1211RW=m -# CONFIG_ZD1211RW_DEBUG is not set -CONFIG_WLAN_VENDOR_QUANTENNA=y -# CONFIG_QTNFMAC_PEARL_PCIE is not set -# CONFIG_PCMCIA_RAYCS is not set -# CONFIG_PCMCIA_WL3501 is not set -CONFIG_MAC80211_HWSIM=m -CONFIG_USB_NET_RNDIS_WLAN=m - -# -# WiMAX Wireless Broadband devices -# -CONFIG_WIMAX_I2400M=m -CONFIG_WIMAX_I2400M_USB=m -CONFIG_WIMAX_I2400M_DEBUG_LEVEL=8 -# CONFIG_WAN is not set -CONFIG_IEEE802154_DRIVERS=m -CONFIG_IEEE802154_FAKELB=m -# CONFIG_IEEE802154_ATUSB is not set -# CONFIG_IEEE802154_HWSIM is not set -CONFIG_XEN_NETDEV_FRONTEND=m -CONFIG_XEN_NETDEV_BACKEND=m -CONFIG_VMXNET3=m -CONFIG_FUJITSU_ES=m -# CONFIG_THUNDERBOLT_NET is not set -CONFIG_HYPERV_NET=m -# CONFIG_NETDEVSIM is not set -CONFIG_NET_FAILOVER=m -CONFIG_ISDN=y -CONFIG_ISDN_I4L=m -CONFIG_ISDN_PPP=y -CONFIG_ISDN_PPP_VJ=y -CONFIG_ISDN_MPP=y -CONFIG_IPPP_FILTER=y -# CONFIG_ISDN_PPP_BSDCOMP is not set -CONFIG_ISDN_AUDIO=y -CONFIG_ISDN_TTY_FAX=y - -# -# ISDN feature submodules -# -CONFIG_ISDN_DIVERSION=m - -# -# ISDN4Linux hardware drivers -# - -# -# Passive cards -# -CONFIG_ISDN_DRV_HISAX=m - -# -# D-channel protocol features -# -CONFIG_HISAX_EURO=y -CONFIG_DE_AOC=y -CONFIG_HISAX_NO_SENDCOMPLETE=y -CONFIG_HISAX_NO_LLC=y -CONFIG_HISAX_NO_KEYPAD=y -CONFIG_HISAX_1TR6=y -CONFIG_HISAX_NI1=y -CONFIG_HISAX_MAX_CARDS=8 - -# -# HiSax supported cards -# -CONFIG_HISAX_16_3=y -CONFIG_HISAX_TELESPCI=y -CONFIG_HISAX_S0BOX=y -CONFIG_HISAX_FRITZPCI=y -CONFIG_HISAX_AVM_A1_PCMCIA=y -CONFIG_HISAX_ELSA=y -CONFIG_HISAX_DIEHLDIVA=y -CONFIG_HISAX_SEDLBAUER=y -CONFIG_HISAX_NETJET=y -CONFIG_HISAX_NETJET_U=y -CONFIG_HISAX_NICCY=y -CONFIG_HISAX_BKM_A4T=y -CONFIG_HISAX_SCT_QUADRO=y -CONFIG_HISAX_GAZEL=y -CONFIG_HISAX_HFC_PCI=y -CONFIG_HISAX_W6692=y -CONFIG_HISAX_HFC_SX=y -CONFIG_HISAX_ENTERNOW_PCI=y -# CONFIG_HISAX_DEBUG is not set - -# -# HiSax PCMCIA card service modules -# -CONFIG_HISAX_SEDLBAUER_CS=m -CONFIG_HISAX_ELSA_CS=m -CONFIG_HISAX_AVM_A1_CS=m -CONFIG_HISAX_TELES_CS=m - -# -# HiSax sub driver modules -# -CONFIG_HISAX_ST5481=m -# CONFIG_HISAX_HFCUSB is not set -CONFIG_HISAX_HFC4S8S=m -CONFIG_HISAX_FRITZ_PCIPNP=m -CONFIG_ISDN_CAPI=m -# CONFIG_CAPI_TRACE is not set -CONFIG_ISDN_CAPI_CAPI20=m -CONFIG_ISDN_CAPI_MIDDLEWARE=y -CONFIG_ISDN_CAPI_CAPIDRV=m -# CONFIG_ISDN_CAPI_CAPIDRV_VERBOSE is not set - -# -# CAPI hardware drivers -# -CONFIG_CAPI_AVM=y -CONFIG_ISDN_DRV_AVMB1_B1PCI=m -CONFIG_ISDN_DRV_AVMB1_B1PCIV4=y -CONFIG_ISDN_DRV_AVMB1_B1PCMCIA=m -CONFIG_ISDN_DRV_AVMB1_AVM_CS=m -CONFIG_ISDN_DRV_AVMB1_T1PCI=m -CONFIG_ISDN_DRV_AVMB1_C4=m -CONFIG_CAPI_EICON=y -CONFIG_ISDN_DIVAS=m -CONFIG_ISDN_DIVAS_BRIPCI=y -CONFIG_ISDN_DIVAS_PRIPCI=y -CONFIG_ISDN_DIVAS_DIVACAPI=m -CONFIG_ISDN_DIVAS_USERIDI=m -CONFIG_ISDN_DIVAS_MAINT=m -CONFIG_ISDN_DRV_GIGASET=m -CONFIG_GIGASET_CAPI=y -CONFIG_GIGASET_BASE=m -CONFIG_GIGASET_M105=m -CONFIG_GIGASET_M101=m -# CONFIG_GIGASET_DEBUG is not set -CONFIG_HYSDN=m -CONFIG_HYSDN_CAPI=y -CONFIG_MISDN=m -CONFIG_MISDN_DSP=m -CONFIG_MISDN_L1OIP=m - -# -# mISDN hardware drivers -# -CONFIG_MISDN_HFCPCI=m -CONFIG_MISDN_HFCMULTI=m -CONFIG_MISDN_HFCUSB=m -CONFIG_MISDN_AVMFRITZ=m -CONFIG_MISDN_SPEEDFAX=m -CONFIG_MISDN_INFINEON=m -CONFIG_MISDN_W6692=m -CONFIG_MISDN_NETJET=m -CONFIG_MISDN_IPAC=m -CONFIG_MISDN_ISAR=m -CONFIG_ISDN_HDLC=m -# CONFIG_NVM is not set - -# -# Input device support -# -CONFIG_INPUT=y -CONFIG_INPUT_LEDS=y -CONFIG_INPUT_FF_MEMLESS=y -CONFIG_INPUT_POLLDEV=m -CONFIG_INPUT_SPARSEKMAP=m -CONFIG_INPUT_MATRIXKMAP=m - -# -# Userland interfaces -# -CONFIG_INPUT_MOUSEDEV=y -# CONFIG_INPUT_MOUSEDEV_PSAUX is not set -CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 -CONFIG_INPUT_JOYDEV=m -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_DLINK_DIR685 is not set -# CONFIG_KEYBOARD_LKKBD is not set -CONFIG_KEYBOARD_GPIO=m -CONFIG_KEYBOARD_GPIO_POLLED=m -# CONFIG_KEYBOARD_TCA6416 is not set -# CONFIG_KEYBOARD_TCA8418 is not set -CONFIG_KEYBOARD_MATRIX=m -# CONFIG_KEYBOARD_LM8323 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=m -# CONFIG_KEYBOARD_STOWAWAY is not set -# CONFIG_KEYBOARD_SUNKBD is not set -# CONFIG_KEYBOARD_TM2_TOUCHKEY is not set -# CONFIG_KEYBOARD_XTKBD is not set -CONFIG_KEYBOARD_CROS_EC=m -# CONFIG_KEYBOARD_MTK_PMIC is not set -CONFIG_INPUT_MOUSE=y -CONFIG_MOUSE_PS2=y -CONFIG_MOUSE_PS2_ALPS=y -CONFIG_MOUSE_PS2_BYD=y -CONFIG_MOUSE_PS2_LOGIPS2PP=y -CONFIG_MOUSE_PS2_SYNAPTICS=y -CONFIG_MOUSE_PS2_CYPRESS=y -CONFIG_MOUSE_PS2_LIFEBOOK=y -CONFIG_MOUSE_PS2_TRACKPOINT=y -CONFIG_MOUSE_PS2_ELANTECH=y -CONFIG_MOUSE_PS2_SENTELIC=y -# CONFIG_MOUSE_PS2_TOUCHKIT is not set -CONFIG_MOUSE_PS2_FOCALTECH=y -CONFIG_MOUSE_PS2_VMMOUSE=y -CONFIG_MOUSE_SERIAL=m -CONFIG_MOUSE_APPLETOUCH=m -CONFIG_MOUSE_BCM5974=m -CONFIG_MOUSE_CYAPA=m -# CONFIG_MOUSE_ELAN_I2C is not set -CONFIG_MOUSE_VSXXXAA=m -CONFIG_MOUSE_GPIO=m -CONFIG_MOUSE_SYNAPTICS_I2C=m -CONFIG_MOUSE_SYNAPTICS_USB=m -CONFIG_INPUT_JOYSTICK=y -CONFIG_JOYSTICK_ANALOG=m -CONFIG_JOYSTICK_A3D=m -CONFIG_JOYSTICK_ADI=m -CONFIG_JOYSTICK_COBRA=m -CONFIG_JOYSTICK_GF2K=m -CONFIG_JOYSTICK_GRIP=m -CONFIG_JOYSTICK_GRIP_MP=m -CONFIG_JOYSTICK_GUILLEMOT=m -CONFIG_JOYSTICK_INTERACT=m -CONFIG_JOYSTICK_SIDEWINDER=m -CONFIG_JOYSTICK_TMDC=m -CONFIG_JOYSTICK_IFORCE=m -CONFIG_JOYSTICK_IFORCE_USB=y -CONFIG_JOYSTICK_IFORCE_232=y -CONFIG_JOYSTICK_WARRIOR=m -CONFIG_JOYSTICK_MAGELLAN=m -CONFIG_JOYSTICK_SPACEORB=m -CONFIG_JOYSTICK_SPACEBALL=m -CONFIG_JOYSTICK_STINGER=m -CONFIG_JOYSTICK_TWIDJOY=m -CONFIG_JOYSTICK_ZHENHUA=m -CONFIG_JOYSTICK_DB9=m -CONFIG_JOYSTICK_GAMECON=m -CONFIG_JOYSTICK_TURBOGRAFX=m -# CONFIG_JOYSTICK_AS5011 is not set -CONFIG_JOYSTICK_JOYDUMP=m -CONFIG_JOYSTICK_XPAD=m -CONFIG_JOYSTICK_XPAD_FF=y -CONFIG_JOYSTICK_XPAD_LEDS=y -CONFIG_JOYSTICK_WALKERA0701=m -# CONFIG_JOYSTICK_PXRC is not set -CONFIG_INPUT_TABLET=y -CONFIG_TABLET_USB_ACECAD=m -CONFIG_TABLET_USB_AIPTEK=m -CONFIG_TABLET_USB_GTCO=m -CONFIG_TABLET_USB_HANWANG=m -CONFIG_TABLET_USB_KBTAB=m -CONFIG_TABLET_USB_PEGASUS=m -CONFIG_TABLET_SERIAL_WACOM4=m -CONFIG_INPUT_TOUCHSCREEN=y -CONFIG_TOUCHSCREEN_PROPERTIES=y -CONFIG_TOUCHSCREEN_AD7879=m -CONFIG_TOUCHSCREEN_AD7879_I2C=m -CONFIG_TOUCHSCREEN_ATMEL_MXT=m -CONFIG_TOUCHSCREEN_ATMEL_MXT_T37=y -CONFIG_TOUCHSCREEN_AUO_PIXCIR=m -CONFIG_TOUCHSCREEN_BU21013=m -# CONFIG_TOUCHSCREEN_BU21029 is not set -# CONFIG_TOUCHSCREEN_CHIPONE_ICN8505 is not set -CONFIG_TOUCHSCREEN_CY8CTMG110=m -CONFIG_TOUCHSCREEN_CYTTSP_CORE=m -CONFIG_TOUCHSCREEN_CYTTSP_I2C=m -CONFIG_TOUCHSCREEN_CYTTSP4_CORE=m -CONFIG_TOUCHSCREEN_CYTTSP4_I2C=m -CONFIG_TOUCHSCREEN_DYNAPRO=m -CONFIG_TOUCHSCREEN_HAMPSHIRE=m -CONFIG_TOUCHSCREEN_EETI=m -# CONFIG_TOUCHSCREEN_EGALAX_SERIAL is not set -# CONFIG_TOUCHSCREEN_EXC3000 is not set -CONFIG_TOUCHSCREEN_FUJITSU=m -# CONFIG_TOUCHSCREEN_GOODIX is not set -# CONFIG_TOUCHSCREEN_HIDEEP is not set -CONFIG_TOUCHSCREEN_ILI210X=m -# CONFIG_TOUCHSCREEN_S6SY761 is not set -CONFIG_TOUCHSCREEN_GUNZE=m -CONFIG_TOUCHSCREEN_EKTF2127=m -# CONFIG_TOUCHSCREEN_ELAN is not set -CONFIG_TOUCHSCREEN_ELO=m -CONFIG_TOUCHSCREEN_WACOM_W8001=m -CONFIG_TOUCHSCREEN_WACOM_I2C=m -CONFIG_TOUCHSCREEN_MAX11801=m -CONFIG_TOUCHSCREEN_MCS5000=m -CONFIG_TOUCHSCREEN_MMS114=m -# CONFIG_TOUCHSCREEN_MELFAS_MIP4 is not set -CONFIG_TOUCHSCREEN_MTOUCH=m -CONFIG_TOUCHSCREEN_INEXIO=m -CONFIG_TOUCHSCREEN_MK712=m -CONFIG_TOUCHSCREEN_PENMOUNT=m -CONFIG_TOUCHSCREEN_EDT_FT5X06=m -CONFIG_TOUCHSCREEN_TOUCHRIGHT=m -CONFIG_TOUCHSCREEN_TOUCHWIN=m -CONFIG_TOUCHSCREEN_TI_AM335X_TSC=m -CONFIG_TOUCHSCREEN_UCB1400=m -CONFIG_TOUCHSCREEN_PIXCIR=m -# CONFIG_TOUCHSCREEN_WDT87XX_I2C is not set -CONFIG_TOUCHSCREEN_WM97XX=m -CONFIG_TOUCHSCREEN_WM9705=y -CONFIG_TOUCHSCREEN_WM9712=y -CONFIG_TOUCHSCREEN_WM9713=y -CONFIG_TOUCHSCREEN_USB_COMPOSITE=m -CONFIG_TOUCHSCREEN_USB_EGALAX=y -CONFIG_TOUCHSCREEN_USB_PANJIT=y -CONFIG_TOUCHSCREEN_USB_3M=y -CONFIG_TOUCHSCREEN_USB_ITM=y -CONFIG_TOUCHSCREEN_USB_ETURBO=y -CONFIG_TOUCHSCREEN_USB_GUNZE=y -CONFIG_TOUCHSCREEN_USB_DMC_TSC10=y -CONFIG_TOUCHSCREEN_USB_IRTOUCH=y -CONFIG_TOUCHSCREEN_USB_IDEALTEK=y -CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH=y -CONFIG_TOUCHSCREEN_USB_GOTOP=y -CONFIG_TOUCHSCREEN_USB_JASTEC=y -CONFIG_TOUCHSCREEN_USB_ELO=y -CONFIG_TOUCHSCREEN_USB_E2I=y -CONFIG_TOUCHSCREEN_USB_ZYTRONIC=y -CONFIG_TOUCHSCREEN_USB_ETT_TC45USB=y -CONFIG_TOUCHSCREEN_USB_NEXIO=y -CONFIG_TOUCHSCREEN_USB_EASYTOUCH=y -CONFIG_TOUCHSCREEN_TOUCHIT213=m -CONFIG_TOUCHSCREEN_TSC_SERIO=m -CONFIG_TOUCHSCREEN_TSC200X_CORE=m -CONFIG_TOUCHSCREEN_TSC2004=m -CONFIG_TOUCHSCREEN_TSC2007=m -CONFIG_TOUCHSCREEN_RM_TS=m -CONFIG_TOUCHSCREEN_SILEAD=m -CONFIG_TOUCHSCREEN_SIS_I2C=m -CONFIG_TOUCHSCREEN_ST1232=m -# CONFIG_TOUCHSCREEN_STMFTS is not set -CONFIG_TOUCHSCREEN_SUR40=m -CONFIG_TOUCHSCREEN_SX8654=m -CONFIG_TOUCHSCREEN_TPS6507X=m -# CONFIG_TOUCHSCREEN_ZET6223 is not set -CONFIG_TOUCHSCREEN_ZFORCE=m -CONFIG_TOUCHSCREEN_ROHM_BU21023=m -CONFIG_INPUT_MISC=y -# CONFIG_INPUT_AD714X is not set -# CONFIG_INPUT_BMA150 is not set -CONFIG_INPUT_E3X0_BUTTON=m -CONFIG_INPUT_PCSPKR=m -CONFIG_INPUT_MMA8450=m -CONFIG_INPUT_APANEL=m -CONFIG_INPUT_GP2A=m -CONFIG_INPUT_GPIO_BEEPER=m -CONFIG_INPUT_GPIO_DECODER=m -CONFIG_INPUT_ATLAS_BTNS=m -CONFIG_INPUT_ATI_REMOTE2=m -CONFIG_INPUT_KEYSPAN_REMOTE=m -CONFIG_INPUT_KXTJ9=m -# CONFIG_INPUT_KXTJ9_POLLED_MODE is not set -CONFIG_INPUT_POWERMATE=m -CONFIG_INPUT_YEALINK=m -CONFIG_INPUT_CM109=m -CONFIG_INPUT_RETU_PWRBUTTON=m -CONFIG_INPUT_UINPUT=m -# CONFIG_INPUT_PCF8574 is not set -CONFIG_INPUT_PWM_BEEPER=m -# CONFIG_INPUT_PWM_VIBRA is not set -CONFIG_INPUT_GPIO_ROTARY_ENCODER=m -# CONFIG_INPUT_ADXL34X is not set -CONFIG_INPUT_IMS_PCU=m -CONFIG_INPUT_CMA3000=m -CONFIG_INPUT_CMA3000_I2C=m -CONFIG_INPUT_XEN_KBDDEV_FRONTEND=y -CONFIG_INPUT_IDEAPAD_SLIDEBAR=m -CONFIG_INPUT_SOC_BUTTON_ARRAY=m -CONFIG_INPUT_DRV260X_HAPTICS=m -# CONFIG_INPUT_DRV2665_HAPTICS is not set -# CONFIG_INPUT_DRV2667_HAPTICS is not set -CONFIG_RMI4_CORE=m -# CONFIG_RMI4_I2C is not set -# CONFIG_RMI4_SMB is not set -CONFIG_RMI4_F03=y -CONFIG_RMI4_F03_SERIO=m -CONFIG_RMI4_2D_SENSOR=y -CONFIG_RMI4_F11=y -CONFIG_RMI4_F12=y -CONFIG_RMI4_F30=y -# CONFIG_RMI4_F34 is not set -# CONFIG_RMI4_F54 is not set -# CONFIG_RMI4_F55 is not set - -# -# Hardware I/O ports -# -CONFIG_SERIO=y -CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y -CONFIG_SERIO_I8042=y -CONFIG_SERIO_SERPORT=y -CONFIG_SERIO_CT82C710=m -CONFIG_SERIO_PARKBD=m -CONFIG_SERIO_PCIPS2=m -CONFIG_SERIO_LIBPS2=y -CONFIG_SERIO_RAW=m -CONFIG_SERIO_ALTERA_PS2=m -CONFIG_SERIO_PS2MULT=m -CONFIG_SERIO_ARC_PS2=m -CONFIG_HYPERV_KEYBOARD=m -# CONFIG_SERIO_GPIO_PS2 is not set -CONFIG_USERIO=m -CONFIG_GAMEPORT=m -CONFIG_GAMEPORT_NS558=m -CONFIG_GAMEPORT_L4=m -CONFIG_GAMEPORT_EMU10K1=m -CONFIG_GAMEPORT_FM801=m - -# -# Character devices -# -CONFIG_TTY=y -CONFIG_VT=y -CONFIG_CONSOLE_TRANSLATIONS=y -CONFIG_VT_CONSOLE=y -CONFIG_VT_CONSOLE_SLEEP=y -CONFIG_HW_CONSOLE=y -CONFIG_VT_HW_CONSOLE_BINDING=y -CONFIG_UNIX98_PTYS=y -# CONFIG_LEGACY_PTYS is not set -CONFIG_SERIAL_NONSTANDARD=y -CONFIG_ROCKETPORT=m -CONFIG_CYCLADES=m -# CONFIG_CYZ_INTR is not set -# CONFIG_MOXA_INTELLIO is not set -# CONFIG_MOXA_SMARTIO is not set -CONFIG_SYNCLINK=m -CONFIG_SYNCLINKMP=m -CONFIG_SYNCLINK_GT=m -CONFIG_NOZOMI=m -# CONFIG_ISI is not set -CONFIG_N_HDLC=m -CONFIG_N_GSM=m -# CONFIG_TRACE_SINK is not set -CONFIG_LDISC_AUTOLOAD=y -CONFIG_DEVMEM=y -# CONFIG_DEVKMEM is not set - -# -# Serial drivers -# -CONFIG_SERIAL_EARLYCON=y -CONFIG_SERIAL_8250=y -# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set -CONFIG_SERIAL_8250_PNP=y -# CONFIG_SERIAL_8250_FINTEK is not set -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_DMA=y -CONFIG_SERIAL_8250_PCI=y -CONFIG_SERIAL_8250_EXAR=y -CONFIG_SERIAL_8250_CS=m -CONFIG_SERIAL_8250_NR_UARTS=32 -CONFIG_SERIAL_8250_RUNTIME_UARTS=4 -CONFIG_SERIAL_8250_EXTENDED=y -CONFIG_SERIAL_8250_MANY_PORTS=y -CONFIG_SERIAL_8250_SHARE_IRQ=y -# CONFIG_SERIAL_8250_DETECT_IRQ is not set -CONFIG_SERIAL_8250_RSA=y -CONFIG_SERIAL_8250_DW=m -# CONFIG_SERIAL_8250_RT288X is not set -CONFIG_SERIAL_8250_LPSS=y -CONFIG_SERIAL_8250_MID=y -# CONFIG_SERIAL_8250_MOXA is not set - -# -# Non-8250 serial port support -# -CONFIG_SERIAL_UARTLITE=m -CONFIG_SERIAL_UARTLITE_NR_UARTS=1 -CONFIG_SERIAL_CORE=y -CONFIG_SERIAL_CORE_CONSOLE=y -CONFIG_SERIAL_JSM=m -CONFIG_SERIAL_SCCNXP=m -CONFIG_SERIAL_SC16IS7XX_CORE=m -CONFIG_SERIAL_SC16IS7XX=m -CONFIG_SERIAL_SC16IS7XX_I2C=y -CONFIG_SERIAL_ALTERA_JTAGUART=m -CONFIG_SERIAL_ALTERA_UART=m -CONFIG_SERIAL_ALTERA_UART_MAXPORTS=4 -CONFIG_SERIAL_ALTERA_UART_BAUDRATE=115200 -CONFIG_SERIAL_ARC=m -CONFIG_SERIAL_ARC_NR_PORTS=1 -CONFIG_SERIAL_RP2=m -CONFIG_SERIAL_RP2_NR_UARTS=32 -CONFIG_SERIAL_FSL_LPUART=m -# CONFIG_SERIAL_DEV_BUS is not set -CONFIG_PRINTER=m -CONFIG_LP_CONSOLE=y -CONFIG_PPDEV=m -CONFIG_HVC_DRIVER=y -CONFIG_HVC_IRQ=y -CONFIG_HVC_XEN=y -CONFIG_HVC_XEN_FRONTEND=y -CONFIG_VIRTIO_CONSOLE=y -CONFIG_IPMI_HANDLER=m -CONFIG_IPMI_DMI_DECODE=y -# CONFIG_IPMI_PANIC_EVENT is not set -CONFIG_IPMI_DEVICE_INTERFACE=m -CONFIG_IPMI_SI=m -# CONFIG_IPMI_SSIF is not set -CONFIG_IPMI_WATCHDOG=m -CONFIG_IPMI_POWEROFF=m -CONFIG_HW_RANDOM=y -CONFIG_HW_RANDOM_TIMERIOMEM=m -CONFIG_HW_RANDOM_INTEL=m -CONFIG_HW_RANDOM_AMD=m -CONFIG_HW_RANDOM_VIA=m -CONFIG_HW_RANDOM_VIRTIO=m -CONFIG_NVRAM=y -# CONFIG_APPLICOM is not set - -# -# PCMCIA character devices -# -# CONFIG_SYNCLINK_CS is not set -CONFIG_CARDMAN_4000=m -CONFIG_CARDMAN_4040=m -# CONFIG_SCR24X is not set -CONFIG_IPWIRELESS=m -CONFIG_MWAVE=m -CONFIG_RAW_DRIVER=y -CONFIG_MAX_RAW_DEVS=8192 -CONFIG_HPET=y -# CONFIG_HPET_MMAP is not set -CONFIG_HANGCHECK_TIMER=m -CONFIG_TCG_TPM=m -CONFIG_HW_RANDOM_TPM=y -CONFIG_TCG_TIS_CORE=m -CONFIG_TCG_TIS=m -CONFIG_TCG_TIS_I2C_ATMEL=m -CONFIG_TCG_TIS_I2C_INFINEON=m -CONFIG_TCG_TIS_I2C_NUVOTON=m -CONFIG_TCG_NSC=m -CONFIG_TCG_ATMEL=m -CONFIG_TCG_INFINEON=m -CONFIG_TCG_XEN=m -CONFIG_TCG_CRB=m -CONFIG_TCG_VTPM_PROXY=m -CONFIG_TCG_TIS_ST33ZP24=m -CONFIG_TCG_TIS_ST33ZP24_I2C=m -CONFIG_TELCLOCK=m -CONFIG_DEVPORT=y -CONFIG_XILLYBUS=m -# CONFIG_XILLYBUS_PCIE is not set -# CONFIG_RANDOM_TRUST_CPU is not set - -# -# I2C support -# -CONFIG_I2C=m -CONFIG_I2C_BOARDINFO=y -CONFIG_I2C_COMPAT=y -CONFIG_I2C_CHARDEV=m -CONFIG_I2C_MUX=m - -# -# Multiplexer I2C Chip support -# -CONFIG_I2C_MUX_GPIO=m -# CONFIG_I2C_MUX_LTC4306 is not set -CONFIG_I2C_MUX_PCA9541=m -CONFIG_I2C_MUX_PCA954x=m -CONFIG_I2C_MUX_REG=m -# CONFIG_I2C_MUX_MLXCPLD is not set -CONFIG_I2C_HELPER_AUTO=y -CONFIG_I2C_SMBUS=m -CONFIG_I2C_ALGOBIT=m -CONFIG_I2C_ALGOPCA=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=m -CONFIG_I2C_AMD756_S4882=m -CONFIG_I2C_AMD8111=m -CONFIG_I2C_I801=m -CONFIG_I2C_ISCH=m -CONFIG_I2C_ISMT=m -CONFIG_I2C_PIIX4=m -CONFIG_I2C_NFORCE2=m -CONFIG_I2C_NFORCE2_S4985=m -# CONFIG_I2C_SIS5595 is not set -# CONFIG_I2C_SIS630 is not set -CONFIG_I2C_SIS96X=m -CONFIG_I2C_VIA=m -CONFIG_I2C_VIAPRO=m - -# -# ACPI drivers -# -CONFIG_I2C_SCMI=m - -# -# I2C system bus drivers (mostly embedded / system-on-chip) -# -CONFIG_I2C_CBUS_GPIO=m -CONFIG_I2C_DESIGNWARE_CORE=m -CONFIG_I2C_DESIGNWARE_PLATFORM=m -# CONFIG_I2C_DESIGNWARE_SLAVE is not set -# CONFIG_I2C_DESIGNWARE_PCI is not set -# CONFIG_I2C_DESIGNWARE_BAYTRAIL is not set -CONFIG_I2C_EMEV2=m -CONFIG_I2C_GPIO=m -# CONFIG_I2C_GPIO_FAULT_INJECTOR is not set -# CONFIG_I2C_OCORES is not set -CONFIG_I2C_PCA_PLATFORM=m -CONFIG_I2C_SIMTEC=m -# CONFIG_I2C_XILINX is not set - -# -# External I2C/SMBus adapter drivers -# -CONFIG_I2C_DIOLAN_U2C=m -CONFIG_I2C_PARPORT=m -CONFIG_I2C_PARPORT_LIGHT=m -CONFIG_I2C_ROBOTFUZZ_OSIF=m -# CONFIG_I2C_TAOS_EVM is not set -CONFIG_I2C_TINY_USB=m -CONFIG_I2C_VIPERBOARD=m - -# -# Other I2C/SMBus bus drivers -# -# CONFIG_I2C_MLXCPLD is not set -CONFIG_I2C_CROS_EC_TUNNEL=m -CONFIG_I2C_STUB=m -CONFIG_I2C_SLAVE=y -# CONFIG_I2C_SLAVE_EEPROM 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 is not set -CONFIG_SPMI=m -# CONFIG_HSI is not set -CONFIG_PPS=y -# CONFIG_PPS_DEBUG is not set - -# -# PPS clients support -# -# CONFIG_PPS_CLIENT_KTIMER is not set -CONFIG_PPS_CLIENT_LDISC=m -CONFIG_PPS_CLIENT_PARPORT=m -CONFIG_PPS_CLIENT_GPIO=m - -# -# PPS generators support -# - -# -# PTP clock support -# -CONFIG_PTP_1588_CLOCK=y -CONFIG_DP83640_PHY=m -CONFIG_PTP_1588_CLOCK_KVM=m -CONFIG_PINCTRL=y -CONFIG_PINMUX=y -CONFIG_PINCONF=y -CONFIG_GENERIC_PINCONF=y -CONFIG_PINCTRL_AMD=y -# CONFIG_PINCTRL_MCP23S08 is not set -CONFIG_PINCTRL_BAYTRAIL=y -CONFIG_PINCTRL_CHERRYVIEW=m -CONFIG_PINCTRL_INTEL=m -CONFIG_PINCTRL_BROXTON=m -# CONFIG_PINCTRL_CANNONLAKE is not set -# CONFIG_PINCTRL_CEDARFORK is not set -# CONFIG_PINCTRL_DENVERTON is not set -# CONFIG_PINCTRL_GEMINILAKE is not set -# CONFIG_PINCTRL_ICELAKE is not set -# CONFIG_PINCTRL_LEWISBURG is not set -CONFIG_PINCTRL_SUNRISEPOINT=m -CONFIG_GPIOLIB=y -CONFIG_GPIOLIB_FASTPATH_LIMIT=512 -CONFIG_GPIO_ACPI=y -CONFIG_GPIOLIB_IRQCHIP=y -CONFIG_GPIO_SYSFS=y -CONFIG_GPIO_GENERIC=y -CONFIG_GPIO_MAX730X=m - -# -# Memory mapped GPIO drivers -# -CONFIG_GPIO_AMDPT=m -CONFIG_GPIO_DWAPB=m -# CONFIG_GPIO_EXAR is not set -CONFIG_GPIO_GENERIC_PLATFORM=y -CONFIG_GPIO_ICH=m -CONFIG_GPIO_LYNXPOINT=m -# CONFIG_GPIO_MB86S7X is not set -CONFIG_GPIO_MOCKUP=m -CONFIG_GPIO_VX855=m - -# -# Port-mapped I/O GPIO drivers -# -CONFIG_GPIO_F7188X=m -CONFIG_GPIO_IT87=m -CONFIG_GPIO_SCH=m -CONFIG_GPIO_SCH311X=m -# CONFIG_GPIO_WINBOND is not set -# CONFIG_GPIO_WS16C48 is not set - -# -# I2C GPIO expanders -# -CONFIG_GPIO_ADP5588=m -CONFIG_GPIO_MAX7300=m -CONFIG_GPIO_MAX732X=m -CONFIG_GPIO_PCA953X=m -CONFIG_GPIO_PCF857X=m -# CONFIG_GPIO_TPIC2810 is not set - -# -# MFD GPIO expanders -# -CONFIG_GPIO_LP3943=m -CONFIG_GPIO_LP873X=m -CONFIG_GPIO_UCB1400=m - -# -# PCI GPIO expanders -# -CONFIG_GPIO_AMD8111=m -CONFIG_GPIO_ML_IOH=m -# CONFIG_GPIO_PCI_IDIO_16 is not set -# CONFIG_GPIO_PCIE_IDIO_24 is not set -CONFIG_GPIO_RDC321X=m - -# -# USB GPIO expanders -# -CONFIG_GPIO_VIPERBOARD=m -CONFIG_W1=m -CONFIG_W1_CON=y - -# -# 1-wire Bus Masters -# -# CONFIG_W1_MASTER_MATROX is not set -CONFIG_W1_MASTER_DS2490=m -CONFIG_W1_MASTER_DS2482=m -CONFIG_W1_MASTER_DS1WM=m -CONFIG_W1_MASTER_GPIO=m - -# -# 1-wire Slaves -# -CONFIG_W1_SLAVE_THERM=m -CONFIG_W1_SLAVE_SMEM=m -# CONFIG_W1_SLAVE_DS2405 is not set -CONFIG_W1_SLAVE_DS2408=m -CONFIG_W1_SLAVE_DS2408_READBACK=y -CONFIG_W1_SLAVE_DS2413=m -CONFIG_W1_SLAVE_DS2406=m -CONFIG_W1_SLAVE_DS2423=m -# CONFIG_W1_SLAVE_DS2805 is not set -CONFIG_W1_SLAVE_DS2431=m -CONFIG_W1_SLAVE_DS2433=m -CONFIG_W1_SLAVE_DS2433_CRC=y -# CONFIG_W1_SLAVE_DS2438 is not set -CONFIG_W1_SLAVE_DS2780=m -CONFIG_W1_SLAVE_DS2781=m -CONFIG_W1_SLAVE_DS28E04=m -# CONFIG_W1_SLAVE_DS28E17 is not set -CONFIG_POWER_AVS=y -# CONFIG_POWER_RESET 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_CHARGER_ADP5061 is not set -# CONFIG_BATTERY_DS2760 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_CHARGER_SBS is not set -# CONFIG_MANAGER_SBS is not set -CONFIG_BATTERY_BQ27XXX=m -CONFIG_BATTERY_BQ27XXX_I2C=m -CONFIG_BATTERY_BQ27XXX_HDQ=m -# CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM is not set -# CONFIG_BATTERY_MAX17040 is not set -# CONFIG_BATTERY_MAX17042 is not set -# CONFIG_BATTERY_MAX1721X is not set -# CONFIG_CHARGER_ISP1704 is not set -# CONFIG_CHARGER_MAX8903 is not set -# CONFIG_CHARGER_LP8727 is not set -CONFIG_CHARGER_GPIO=m -# CONFIG_CHARGER_LTC3651 is not set -CONFIG_CHARGER_MAX14577=m -CONFIG_CHARGER_BQ2415X=m -CONFIG_CHARGER_BQ24190=m -# CONFIG_CHARGER_BQ24257 is not set -CONFIG_CHARGER_BQ24735=m -# CONFIG_CHARGER_BQ25890 is not set -CONFIG_CHARGER_SMB347=m -CONFIG_BATTERY_GAUGE_LTC2941=m -# CONFIG_CHARGER_RT9455 is not set -# CONFIG_CHARGER_CROS_USBPD is not set -CONFIG_HWMON=y -CONFIG_HWMON_VID=m -# CONFIG_HWMON_DEBUG_CHIP is not set - -# -# Native drivers -# -CONFIG_SENSORS_ABITUGURU=m -CONFIG_SENSORS_ABITUGURU3=m -CONFIG_SENSORS_AD7414=m -CONFIG_SENSORS_AD7418=m -CONFIG_SENSORS_ADM1021=m -CONFIG_SENSORS_ADM1025=m -CONFIG_SENSORS_ADM1026=m -CONFIG_SENSORS_ADM1029=m -CONFIG_SENSORS_ADM1031=m -CONFIG_SENSORS_ADM9240=m -CONFIG_SENSORS_ADT7X10=m -CONFIG_SENSORS_ADT7410=m -CONFIG_SENSORS_ADT7411=m -CONFIG_SENSORS_ADT7462=m -CONFIG_SENSORS_ADT7470=m -CONFIG_SENSORS_ADT7475=m -CONFIG_SENSORS_ASC7621=m -CONFIG_SENSORS_K8TEMP=m -CONFIG_SENSORS_K10TEMP=m -CONFIG_SENSORS_FAM15H_POWER=m -CONFIG_SENSORS_APPLESMC=m -CONFIG_SENSORS_ASB100=m -# CONFIG_SENSORS_ASPEED is not set -CONFIG_SENSORS_ATXP1=m -CONFIG_SENSORS_DS620=m -CONFIG_SENSORS_DS1621=m -CONFIG_SENSORS_DELL_SMM=m -CONFIG_SENSORS_I5K_AMB=m -CONFIG_SENSORS_F71805F=m -CONFIG_SENSORS_F71882FG=m -CONFIG_SENSORS_F75375S=m -CONFIG_SENSORS_FSCHMD=m -CONFIG_SENSORS_FTSTEUTATES=m -CONFIG_SENSORS_GL518SM=m -CONFIG_SENSORS_GL520SM=m -CONFIG_SENSORS_G760A=m -CONFIG_SENSORS_G762=m -CONFIG_SENSORS_HIH6130=m -CONFIG_SENSORS_IBMAEM=m -CONFIG_SENSORS_IBMPEX=m -# CONFIG_SENSORS_I5500 is not set -CONFIG_SENSORS_CORETEMP=m -CONFIG_SENSORS_IT87=m -# CONFIG_SENSORS_JC42 is not set -CONFIG_SENSORS_POWR1220=m -CONFIG_SENSORS_LINEAGE=m -CONFIG_SENSORS_LTC2945=m -# CONFIG_SENSORS_LTC2990 is not set -CONFIG_SENSORS_LTC4151=m -CONFIG_SENSORS_LTC4215=m -CONFIG_SENSORS_LTC4222=m -CONFIG_SENSORS_LTC4245=m -CONFIG_SENSORS_LTC4260=m -CONFIG_SENSORS_LTC4261=m -CONFIG_SENSORS_MAX16065=m -CONFIG_SENSORS_MAX1619=m -CONFIG_SENSORS_MAX1668=m -CONFIG_SENSORS_MAX197=m -# CONFIG_SENSORS_MAX6621 is not set -CONFIG_SENSORS_MAX6639=m -CONFIG_SENSORS_MAX6642=m -CONFIG_SENSORS_MAX6650=m -CONFIG_SENSORS_MAX6697=m -CONFIG_SENSORS_MAX31790=m -CONFIG_SENSORS_MCP3021=m -# CONFIG_SENSORS_TC654 is not set -CONFIG_SENSORS_LM63=m -CONFIG_SENSORS_LM73=m -CONFIG_SENSORS_LM75=m -CONFIG_SENSORS_LM77=m -CONFIG_SENSORS_LM78=m -CONFIG_SENSORS_LM80=m -CONFIG_SENSORS_LM83=m -CONFIG_SENSORS_LM85=m -CONFIG_SENSORS_LM87=m -CONFIG_SENSORS_LM90=m -CONFIG_SENSORS_LM92=m -CONFIG_SENSORS_LM93=m -CONFIG_SENSORS_LM95234=m -CONFIG_SENSORS_LM95241=m -CONFIG_SENSORS_LM95245=m -CONFIG_SENSORS_PC87360=m -CONFIG_SENSORS_PC87427=m -CONFIG_SENSORS_NTC_THERMISTOR=m -CONFIG_SENSORS_NCT6683=m -CONFIG_SENSORS_NCT6775=m -# CONFIG_SENSORS_NCT7802 is not set -CONFIG_SENSORS_NCT7904=m -# CONFIG_SENSORS_NPCM7XX is not set -CONFIG_SENSORS_PCF8591=m -CONFIG_PMBUS=m -CONFIG_SENSORS_PMBUS=m -CONFIG_SENSORS_ADM1275=m -# CONFIG_SENSORS_IBM_CFFPS is not set -# CONFIG_SENSORS_IR35221 is not set -CONFIG_SENSORS_LM25066=m -CONFIG_SENSORS_LTC2978=m -# CONFIG_SENSORS_LTC3815 is not set -CONFIG_SENSORS_MAX16064=m -CONFIG_SENSORS_MAX20751=m -# CONFIG_SENSORS_MAX31785 is not set -CONFIG_SENSORS_MAX34440=m -CONFIG_SENSORS_MAX8688=m -CONFIG_SENSORS_TPS40422=m -# CONFIG_SENSORS_TPS53679 is not set -CONFIG_SENSORS_UCD9000=m -CONFIG_SENSORS_UCD9200=m -CONFIG_SENSORS_ZL6100=m -CONFIG_SENSORS_SHT15=m -CONFIG_SENSORS_SHT21=m -CONFIG_SENSORS_SHT3x=m -CONFIG_SENSORS_SHTC1=m -CONFIG_SENSORS_SIS5595=m -CONFIG_SENSORS_DME1737=m -CONFIG_SENSORS_EMC1403=m -# CONFIG_SENSORS_EMC2103 is not set -CONFIG_SENSORS_EMC6W201=m -CONFIG_SENSORS_SMSC47M1=m -CONFIG_SENSORS_SMSC47M192=m -CONFIG_SENSORS_SMSC47B397=m -CONFIG_SENSORS_SCH56XX_COMMON=m -CONFIG_SENSORS_SCH5627=m -CONFIG_SENSORS_SCH5636=m -# CONFIG_SENSORS_STTS751 is not set -# CONFIG_SENSORS_SMM665 is not set -CONFIG_SENSORS_ADC128D818=m -CONFIG_SENSORS_ADS1015=m -CONFIG_SENSORS_ADS7828=m -CONFIG_SENSORS_AMC6821=m -CONFIG_SENSORS_INA209=m -CONFIG_SENSORS_INA2XX=m -CONFIG_SENSORS_INA3221=m -# CONFIG_SENSORS_TC74 is not set -CONFIG_SENSORS_THMC50=m -CONFIG_SENSORS_TMP102=m -CONFIG_SENSORS_TMP103=m -# CONFIG_SENSORS_TMP108 is not set -CONFIG_SENSORS_TMP401=m -CONFIG_SENSORS_TMP421=m -CONFIG_SENSORS_VIA_CPUTEMP=m -CONFIG_SENSORS_VIA686A=m -CONFIG_SENSORS_VT1211=m -CONFIG_SENSORS_VT8231=m -# CONFIG_SENSORS_W83773G is not set -CONFIG_SENSORS_W83781D=m -CONFIG_SENSORS_W83791D=m -CONFIG_SENSORS_W83792D=m -CONFIG_SENSORS_W83793=m -CONFIG_SENSORS_W83795=m -# CONFIG_SENSORS_W83795_FANCTRL is not set -CONFIG_SENSORS_W83L785TS=m -CONFIG_SENSORS_W83L786NG=m -CONFIG_SENSORS_W83627HF=m -CONFIG_SENSORS_W83627EHF=m -# CONFIG_SENSORS_XGENE is not set - -# -# ACPI drivers -# -CONFIG_SENSORS_ACPI_POWER=m -CONFIG_SENSORS_ATK0110=m -CONFIG_THERMAL=y -# CONFIG_THERMAL_STATISTICS is not set -CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 -CONFIG_THERMAL_HWMON=y -CONFIG_THERMAL_WRITABLE_TRIPS=y -CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y -# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set -# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set -# CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR is not set -CONFIG_THERMAL_GOV_FAIR_SHARE=y -CONFIG_THERMAL_GOV_STEP_WISE=y -CONFIG_THERMAL_GOV_BANG_BANG=y -CONFIG_THERMAL_GOV_USER_SPACE=y -# CONFIG_THERMAL_GOV_POWER_ALLOCATOR is not set -# CONFIG_CLOCK_THERMAL is not set -# CONFIG_DEVFREQ_THERMAL is not set -# CONFIG_THERMAL_EMULATION is not set -# CONFIG_INTEL_POWERCLAMP is not set -CONFIG_X86_PKG_TEMP_THERMAL=m -CONFIG_INTEL_SOC_DTS_IOSF_CORE=m -CONFIG_INTEL_SOC_DTS_THERMAL=m - -# -# ACPI INT340X thermal drivers -# -# CONFIG_INT340X_THERMAL is not set -CONFIG_INTEL_PCH_THERMAL=m -CONFIG_WATCHDOG=y -CONFIG_WATCHDOG_CORE=y -# CONFIG_WATCHDOG_NOWAYOUT is not set -CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED=y -# CONFIG_WATCHDOG_SYSFS is not set - -# -# Watchdog Device Drivers -# -CONFIG_SOFT_WATCHDOG=m -# CONFIG_SOFT_WATCHDOG_PRETIMEOUT is not set -CONFIG_WDAT_WDT=m -# CONFIG_XILINX_WATCHDOG is not set -# CONFIG_ZIIRAVE_WATCHDOG is not set -CONFIG_CADENCE_WATCHDOG=m -CONFIG_DW_WATCHDOG=m -# CONFIG_MAX63XX_WATCHDOG is not set -CONFIG_RETU_WATCHDOG=m -# CONFIG_ACQUIRE_WDT is not set -# CONFIG_ADVANTECH_WDT is not set -CONFIG_ALIM1535_WDT=m -CONFIG_ALIM7101_WDT=m -# CONFIG_EBC_C384_WDT is not set -CONFIG_F71808E_WDT=m -# CONFIG_SP5100_TCO is not set -CONFIG_SBC_FITPC2_WATCHDOG=m -# CONFIG_EUROTECH_WDT is not set -CONFIG_IB700_WDT=m -CONFIG_IBMASR=m -# CONFIG_WAFER_WDT is not set -CONFIG_I6300ESB_WDT=m -CONFIG_IE6XX_WDT=m -CONFIG_ITCO_WDT=m -CONFIG_ITCO_VENDOR_SUPPORT=y -CONFIG_IT8712F_WDT=m -CONFIG_IT87_WDT=m -CONFIG_HP_WATCHDOG=m -CONFIG_HPWDT_NMI_DECODING=y -# CONFIG_SC1200_WDT is not set -# CONFIG_PC87413_WDT is not set -CONFIG_NV_TCO=m -# CONFIG_60XX_WDT is not set -# CONFIG_CPU5_WDT is not set -CONFIG_SMSC_SCH311X_WDT=m -# CONFIG_SMSC37B787_WDT is not set -CONFIG_VIA_WDT=m -CONFIG_W83627HF_WDT=m -CONFIG_W83877F_WDT=m -CONFIG_W83977F_WDT=m -CONFIG_MACHZ_WDT=m -# CONFIG_SBC_EPX_C3_WATCHDOG is not set -# CONFIG_INTEL_MEI_WDT is not set -# CONFIG_NI903X_WDT is not set -# CONFIG_NIC7018_WDT is not set -CONFIG_MEN_A21_WDT=m -CONFIG_XEN_WDT=m - -# -# PCI-based Watchdog Cards -# -CONFIG_PCIPCWATCHDOG=m -CONFIG_WDTPCI=m - -# -# USB-based Watchdog Cards -# -CONFIG_USBPCWATCHDOG=m - -# -# Watchdog Pretimeout Governors -# -CONFIG_WATCHDOG_PRETIMEOUT_GOV=y -# CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_NOOP is not set -CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_PANIC=y -CONFIG_WATCHDOG_PRETIMEOUT_GOV_NOOP=m -CONFIG_WATCHDOG_PRETIMEOUT_GOV_PANIC=y -CONFIG_SSB_POSSIBLE=y -CONFIG_SSB=m -CONFIG_SSB_SPROM=y -CONFIG_SSB_BLOCKIO=y -CONFIG_SSB_PCIHOST_POSSIBLE=y -CONFIG_SSB_PCIHOST=y -CONFIG_SSB_B43_PCI_BRIDGE=y -CONFIG_SSB_PCMCIAHOST_POSSIBLE=y -CONFIG_SSB_PCMCIAHOST=y -CONFIG_SSB_SDIOHOST_POSSIBLE=y -CONFIG_SSB_SDIOHOST=y -CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y -CONFIG_SSB_DRIVER_PCICORE=y -CONFIG_SSB_DRIVER_GPIO=y -CONFIG_BCMA_POSSIBLE=y -CONFIG_BCMA=m -CONFIG_BCMA_BLOCKIO=y -CONFIG_BCMA_HOST_PCI_POSSIBLE=y -CONFIG_BCMA_HOST_PCI=y -# CONFIG_BCMA_HOST_SOC is not set -CONFIG_BCMA_DRIVER_PCI=y -CONFIG_BCMA_DRIVER_GMAC_CMN=y -CONFIG_BCMA_DRIVER_GPIO=y -# CONFIG_BCMA_DEBUG is not set - -# -# Multifunction device drivers -# -CONFIG_MFD_CORE=m -CONFIG_MFD_BCM590XX=m -# CONFIG_MFD_BD9571MWV is not set -# CONFIG_MFD_AXP20X_I2C is not set -CONFIG_MFD_CROS_EC=m -# CONFIG_MFD_CROS_EC_CHARDEV is not set -# CONFIG_MFD_MADERA is not set -# CONFIG_MFD_DA9062 is not set -# CONFIG_MFD_DA9063 is not set -# CONFIG_MFD_DA9150 is not set -# CONFIG_MFD_DLN2 is not set -# CONFIG_MFD_MC13XXX_I2C is not set -# CONFIG_HTC_PASIC3 is not set -CONFIG_MFD_INTEL_QUARK_I2C_GPIO=m -CONFIG_LPC_ICH=m -CONFIG_LPC_SCH=m -# CONFIG_INTEL_SOC_PMIC_CHTDC_TI is not set -CONFIG_MFD_INTEL_LPSS=m -CONFIG_MFD_INTEL_LPSS_ACPI=m -CONFIG_MFD_INTEL_LPSS_PCI=m -# CONFIG_MFD_JANZ_CMODIO is not set -# CONFIG_MFD_KEMPLD is not set -# CONFIG_MFD_88PM800 is not set -# CONFIG_MFD_88PM805 is not set -CONFIG_MFD_MAX14577=m -# CONFIG_MFD_MAX77693 is not set -# CONFIG_MFD_MAX8907 is not set -CONFIG_MFD_MT6397=m -# CONFIG_MFD_MENF21BMC is not set -CONFIG_MFD_VIPERBOARD=m -CONFIG_MFD_RETU=m -# CONFIG_MFD_PCF50633 is not set -CONFIG_UCB1400_CORE=m -CONFIG_MFD_RDC321X=m -# CONFIG_MFD_RT5033 is not set -CONFIG_MFD_SI476X_CORE=m -CONFIG_MFD_SM501=m -CONFIG_MFD_SM501_GPIO=y -CONFIG_MFD_SKY81452=m -# CONFIG_ABX500_CORE is not set -CONFIG_MFD_SYSCON=y -CONFIG_MFD_TI_AM335X_TSCADC=m -CONFIG_MFD_LP3943=m -# CONFIG_MFD_TI_LMU is not set -# CONFIG_TPS6105X is not set -CONFIG_TPS65010=m -# CONFIG_TPS6507X is not set -# CONFIG_MFD_TPS65086 is not set -CONFIG_MFD_TI_LP873X=m -# CONFIG_MFD_TPS65912_I2C is not set -CONFIG_MFD_WL1273_CORE=m -# CONFIG_MFD_LM3533 is not set -CONFIG_MFD_VX855=m -# CONFIG_MFD_ARIZONA_I2C is not set -# CONFIG_MFD_WM8994 is not set -# CONFIG_REGULATOR is not set -CONFIG_RC_CORE=m -CONFIG_RC_MAP=m -# CONFIG_LIRC is not set -CONFIG_RC_DECODERS=y -CONFIG_IR_NEC_DECODER=m -CONFIG_IR_RC5_DECODER=m -CONFIG_IR_RC6_DECODER=m -CONFIG_IR_JVC_DECODER=m -CONFIG_IR_SONY_DECODER=m -CONFIG_IR_SANYO_DECODER=m -CONFIG_IR_SHARP_DECODER=m -CONFIG_IR_MCE_KBD_DECODER=m -CONFIG_IR_XMP_DECODER=m -# CONFIG_IR_IMON_DECODER is not set -CONFIG_RC_DEVICES=y -CONFIG_RC_ATI_REMOTE=m -CONFIG_IR_ENE=m -CONFIG_IR_IMON=m -# CONFIG_IR_IMON_RAW is not set -CONFIG_IR_MCEUSB=m -CONFIG_IR_ITE_CIR=m -CONFIG_IR_FINTEK=m -CONFIG_IR_NUVOTON=m -CONFIG_IR_REDRAT3=m -CONFIG_IR_STREAMZAP=m -CONFIG_IR_WINBOND_CIR=m -# CONFIG_IR_IGORPLUGUSB is not set -CONFIG_IR_IGUANA=m -CONFIG_IR_TTUSBIR=m -CONFIG_RC_LOOPBACK=m -# CONFIG_IR_SERIAL is not set -# CONFIG_IR_SIR is not set -CONFIG_MEDIA_SUPPORT=m - -# -# Multimedia core support -# -CONFIG_MEDIA_CAMERA_SUPPORT=y -CONFIG_MEDIA_ANALOG_TV_SUPPORT=y -CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y -CONFIG_MEDIA_RADIO_SUPPORT=y -CONFIG_MEDIA_SDR_SUPPORT=y -# CONFIG_MEDIA_CEC_SUPPORT is not set -CONFIG_MEDIA_CONTROLLER=y -# CONFIG_MEDIA_CONTROLLER_DVB is not set -CONFIG_VIDEO_DEV=m -CONFIG_VIDEO_V4L2_SUBDEV_API=y -CONFIG_VIDEO_V4L2=m -# CONFIG_VIDEO_ADV_DEBUG is not set -# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set -CONFIG_VIDEO_PCI_SKELETON=m -CONFIG_VIDEO_TUNER=m -CONFIG_V4L2_MEM2MEM_DEV=m -# CONFIG_V4L2_FLASH_LED_CLASS is not set -CONFIG_V4L2_FWNODE=m -CONFIG_VIDEOBUF_GEN=m -CONFIG_VIDEOBUF_DMA_SG=m -CONFIG_VIDEOBUF_VMALLOC=m -CONFIG_DVB_CORE=m -# CONFIG_DVB_MMAP is not set -CONFIG_DVB_NET=y -CONFIG_TTPCI_EEPROM=m -CONFIG_DVB_MAX_ADAPTERS=8 -CONFIG_DVB_DYNAMIC_MINORS=y -# CONFIG_DVB_DEMUX_SECTION_LOSS_LOG is not set -# CONFIG_DVB_ULE_DEBUG is not set - -# -# Media drivers -# -CONFIG_MEDIA_USB_SUPPORT=y - -# -# Webcam devices -# -CONFIG_USB_VIDEO_CLASS=m -CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y -CONFIG_USB_GSPCA=m -CONFIG_USB_M5602=m -CONFIG_USB_STV06XX=m -CONFIG_USB_GL860=m -CONFIG_USB_GSPCA_BENQ=m -CONFIG_USB_GSPCA_CONEX=m -CONFIG_USB_GSPCA_CPIA1=m -CONFIG_USB_GSPCA_DTCS033=m -CONFIG_USB_GSPCA_ETOMS=m -CONFIG_USB_GSPCA_FINEPIX=m -CONFIG_USB_GSPCA_JEILINJ=m -CONFIG_USB_GSPCA_JL2005BCD=m -CONFIG_USB_GSPCA_KINECT=m -CONFIG_USB_GSPCA_KONICA=m -CONFIG_USB_GSPCA_MARS=m -CONFIG_USB_GSPCA_MR97310A=m -CONFIG_USB_GSPCA_NW80X=m -CONFIG_USB_GSPCA_OV519=m -CONFIG_USB_GSPCA_OV534=m -CONFIG_USB_GSPCA_OV534_9=m -CONFIG_USB_GSPCA_PAC207=m -CONFIG_USB_GSPCA_PAC7302=m -CONFIG_USB_GSPCA_PAC7311=m -CONFIG_USB_GSPCA_SE401=m -CONFIG_USB_GSPCA_SN9C2028=m -CONFIG_USB_GSPCA_SN9C20X=m -CONFIG_USB_GSPCA_SONIXB=m -CONFIG_USB_GSPCA_SONIXJ=m -CONFIG_USB_GSPCA_SPCA500=m -CONFIG_USB_GSPCA_SPCA501=m -CONFIG_USB_GSPCA_SPCA505=m -CONFIG_USB_GSPCA_SPCA506=m -CONFIG_USB_GSPCA_SPCA508=m -CONFIG_USB_GSPCA_SPCA561=m -CONFIG_USB_GSPCA_SPCA1528=m -CONFIG_USB_GSPCA_SQ905=m -CONFIG_USB_GSPCA_SQ905C=m -CONFIG_USB_GSPCA_SQ930X=m -CONFIG_USB_GSPCA_STK014=m -CONFIG_USB_GSPCA_STK1135=m -CONFIG_USB_GSPCA_STV0680=m -CONFIG_USB_GSPCA_SUNPLUS=m -CONFIG_USB_GSPCA_T613=m -CONFIG_USB_GSPCA_TOPRO=m -CONFIG_USB_GSPCA_TOUPTEK=m -CONFIG_USB_GSPCA_TV8532=m -CONFIG_USB_GSPCA_VC032X=m -CONFIG_USB_GSPCA_VICAM=m -CONFIG_USB_GSPCA_XIRLINK_CIT=m -CONFIG_USB_GSPCA_ZC3XX=m -CONFIG_USB_PWC=m -# CONFIG_USB_PWC_DEBUG is not set -CONFIG_USB_PWC_INPUT_EVDEV=y -CONFIG_VIDEO_CPIA2=m -CONFIG_USB_ZR364XX=m -CONFIG_USB_STKWEBCAM=m -CONFIG_USB_S2255=m -CONFIG_VIDEO_USBTV=m - -# -# Analog TV USB devices -# -CONFIG_VIDEO_PVRUSB2=m -CONFIG_VIDEO_PVRUSB2_SYSFS=y -CONFIG_VIDEO_PVRUSB2_DVB=y -# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set -CONFIG_VIDEO_HDPVR=m -CONFIG_VIDEO_USBVISION=m -CONFIG_VIDEO_STK1160_COMMON=m -CONFIG_VIDEO_STK1160=m -# CONFIG_VIDEO_GO7007 is not set - -# -# Analog/digital TV USB devices -# -CONFIG_VIDEO_AU0828=m -CONFIG_VIDEO_AU0828_V4L2=y -CONFIG_VIDEO_AU0828_RC=y -CONFIG_VIDEO_CX231XX=m -CONFIG_VIDEO_CX231XX_RC=y -CONFIG_VIDEO_CX231XX_ALSA=m -CONFIG_VIDEO_CX231XX_DVB=m -CONFIG_VIDEO_TM6000=m -CONFIG_VIDEO_TM6000_ALSA=m -CONFIG_VIDEO_TM6000_DVB=m - -# -# Digital TV USB devices -# -CONFIG_DVB_USB=m -# CONFIG_DVB_USB_DEBUG is not set -CONFIG_DVB_USB_DIB3000MC=m -CONFIG_DVB_USB_A800=m -CONFIG_DVB_USB_DIBUSB_MB=m -# CONFIG_DVB_USB_DIBUSB_MB_FAULTY is not set -CONFIG_DVB_USB_DIBUSB_MC=m -CONFIG_DVB_USB_DIB0700=m -CONFIG_DVB_USB_UMT_010=m -CONFIG_DVB_USB_CXUSB=m -CONFIG_DVB_USB_M920X=m -CONFIG_DVB_USB_DIGITV=m -CONFIG_DVB_USB_VP7045=m -CONFIG_DVB_USB_VP702X=m -CONFIG_DVB_USB_GP8PSK=m -CONFIG_DVB_USB_NOVA_T_USB2=m -CONFIG_DVB_USB_TTUSB2=m -CONFIG_DVB_USB_DTT200U=m -CONFIG_DVB_USB_OPERA1=m -CONFIG_DVB_USB_AF9005=m -CONFIG_DVB_USB_AF9005_REMOTE=m -CONFIG_DVB_USB_PCTV452E=m -CONFIG_DVB_USB_DW2102=m -CONFIG_DVB_USB_CINERGY_T2=m -CONFIG_DVB_USB_DTV5100=m -CONFIG_DVB_USB_AZ6027=m -CONFIG_DVB_USB_TECHNISAT_USB2=m -CONFIG_DVB_USB_V2=m -CONFIG_DVB_USB_AF9015=m -CONFIG_DVB_USB_AF9035=m -CONFIG_DVB_USB_ANYSEE=m -CONFIG_DVB_USB_AU6610=m -CONFIG_DVB_USB_AZ6007=m -CONFIG_DVB_USB_CE6230=m -CONFIG_DVB_USB_EC168=m -CONFIG_DVB_USB_GL861=m -CONFIG_DVB_USB_LME2510=m -CONFIG_DVB_USB_MXL111SF=m -CONFIG_DVB_USB_RTL28XXU=m -# CONFIG_DVB_USB_DVBSKY is not set -# CONFIG_DVB_USB_ZD1301 is not set -CONFIG_DVB_TTUSB_BUDGET=m -CONFIG_DVB_TTUSB_DEC=m -CONFIG_SMS_USB_DRV=m -CONFIG_DVB_B2C2_FLEXCOP_USB=m -# CONFIG_DVB_B2C2_FLEXCOP_USB_DEBUG is not set -# CONFIG_DVB_AS102 is not set - -# -# Webcam, TV (analog/digital) USB devices -# -CONFIG_VIDEO_EM28XX=m -CONFIG_VIDEO_EM28XX_V4L2=m -CONFIG_VIDEO_EM28XX_ALSA=m -CONFIG_VIDEO_EM28XX_DVB=m -CONFIG_VIDEO_EM28XX_RC=m - -# -# Software defined radio USB devices -# -CONFIG_USB_AIRSPY=m -# CONFIG_USB_HACKRF is not set -CONFIG_MEDIA_PCI_SUPPORT=y - -# -# Media capture support -# -CONFIG_VIDEO_MEYE=m -CONFIG_VIDEO_SOLO6X10=m -CONFIG_VIDEO_TW5864=m -# CONFIG_VIDEO_TW68 is not set -# CONFIG_VIDEO_TW686X is not set - -# -# Media capture/analog TV support -# -CONFIG_VIDEO_IVTV=m -# CONFIG_VIDEO_IVTV_DEPRECATED_IOCTLS is not set -CONFIG_VIDEO_IVTV_ALSA=m -CONFIG_VIDEO_FB_IVTV=m -CONFIG_VIDEO_HEXIUM_GEMINI=m -CONFIG_VIDEO_HEXIUM_ORION=m -CONFIG_VIDEO_MXB=m -# CONFIG_VIDEO_DT3155 is not set - -# -# Media capture/analog/hybrid TV support -# -CONFIG_VIDEO_CX18=m -CONFIG_VIDEO_CX18_ALSA=m -CONFIG_VIDEO_CX23885=m -CONFIG_MEDIA_ALTERA_CI=m -# CONFIG_VIDEO_CX25821 is not set -CONFIG_VIDEO_CX88=m -CONFIG_VIDEO_CX88_ALSA=m -CONFIG_VIDEO_CX88_BLACKBIRD=m -CONFIG_VIDEO_CX88_DVB=m -CONFIG_VIDEO_CX88_ENABLE_VP3054=y -CONFIG_VIDEO_CX88_VP3054=m -CONFIG_VIDEO_CX88_MPEG=m -CONFIG_VIDEO_BT848=m -CONFIG_DVB_BT8XX=m -CONFIG_VIDEO_SAA7134=m -CONFIG_VIDEO_SAA7134_ALSA=m -CONFIG_VIDEO_SAA7134_RC=y -CONFIG_VIDEO_SAA7134_DVB=m -CONFIG_VIDEO_SAA7164=m - -# -# Media digital TV PCI Adapters -# -CONFIG_DVB_AV7110_IR=y -CONFIG_DVB_AV7110=m -CONFIG_DVB_AV7110_OSD=y -CONFIG_DVB_BUDGET_CORE=m -CONFIG_DVB_BUDGET=m -CONFIG_DVB_BUDGET_CI=m -CONFIG_DVB_BUDGET_AV=m -CONFIG_DVB_BUDGET_PATCH=m -CONFIG_DVB_B2C2_FLEXCOP_PCI=m -# CONFIG_DVB_B2C2_FLEXCOP_PCI_DEBUG is not set -CONFIG_DVB_PLUTO2=m -CONFIG_DVB_DM1105=m -CONFIG_DVB_PT1=m -# CONFIG_DVB_PT3 is not set -CONFIG_MANTIS_CORE=m -CONFIG_DVB_MANTIS=m -CONFIG_DVB_HOPPER=m -CONFIG_DVB_NGENE=m -CONFIG_DVB_DDBRIDGE=m -# CONFIG_DVB_DDBRIDGE_MSIENABLE is not set -# CONFIG_DVB_SMIPCIE is not set -# CONFIG_VIDEO_IPU3_CIO2 is not set -# CONFIG_V4L_PLATFORM_DRIVERS is not set -CONFIG_V4L_MEM2MEM_DRIVERS=y -CONFIG_VIDEO_MEM2MEM_DEINTERLACE=m -CONFIG_VIDEO_SH_VEU=m -CONFIG_V4L_TEST_DRIVERS=y -# CONFIG_VIDEO_VIMC is not set -# CONFIG_VIDEO_VIVID is not set -# CONFIG_VIDEO_VIM2M is not set -# CONFIG_VIDEO_VICODEC is not set -CONFIG_DVB_PLATFORM_DRIVERS=y -# CONFIG_SDR_PLATFORM_DRIVERS is not set - -# -# Supported MMC/SDIO adapters -# -CONFIG_SMS_SDIO_DRV=m -CONFIG_RADIO_ADAPTERS=y -CONFIG_RADIO_TEA575X=m -CONFIG_RADIO_SI470X=m -CONFIG_USB_SI470X=m -CONFIG_I2C_SI470X=m -CONFIG_RADIO_SI4713=m -CONFIG_USB_SI4713=m -CONFIG_PLATFORM_SI4713=m -CONFIG_I2C_SI4713=m -CONFIG_USB_MR800=m -CONFIG_USB_DSBR=m -CONFIG_RADIO_MAXIRADIO=m -CONFIG_RADIO_SHARK=m -CONFIG_RADIO_SHARK2=m -CONFIG_USB_KEENE=m -CONFIG_USB_RAREMONO=m -CONFIG_USB_MA901=m -CONFIG_RADIO_TEA5764=m -CONFIG_RADIO_SAA7706H=m -# CONFIG_RADIO_TEF6862 is not set -CONFIG_RADIO_WL1273=m - -# -# Texas Instruments WL128x FM driver (ST based) -# -CONFIG_RADIO_WL128X=m - -# -# Supported FireWire (IEEE 1394) Adapters -# -CONFIG_DVB_FIREDTV=m -CONFIG_DVB_FIREDTV_INPUT=y -CONFIG_MEDIA_COMMON_OPTIONS=y - -# -# common driver options -# -CONFIG_VIDEO_CX2341X=m -CONFIG_VIDEO_TVEEPROM=m -CONFIG_CYPRESS_FIRMWARE=m -CONFIG_VIDEOBUF2_CORE=m -CONFIG_VIDEOBUF2_V4L2=m -CONFIG_VIDEOBUF2_MEMOPS=m -CONFIG_VIDEOBUF2_DMA_CONTIG=m -CONFIG_VIDEOBUF2_VMALLOC=m -CONFIG_VIDEOBUF2_DMA_SG=m -CONFIG_VIDEOBUF2_DVB=m -CONFIG_DVB_B2C2_FLEXCOP=m -CONFIG_VIDEO_SAA7146=m -CONFIG_VIDEO_SAA7146_VV=m -CONFIG_SMS_SIANO_MDTV=m -CONFIG_SMS_SIANO_RC=y -# CONFIG_SMS_SIANO_DEBUGFS is not set - -# -# Media ancillary drivers (tuners, sensors, i2c, spi, frontends) -# -CONFIG_MEDIA_SUBDRV_AUTOSELECT=y -CONFIG_MEDIA_ATTACH=y -CONFIG_VIDEO_IR_I2C=m - -# -# Audio decoders, processors and mixers -# -CONFIG_VIDEO_TVAUDIO=m -CONFIG_VIDEO_TDA7432=m -CONFIG_VIDEO_TDA9840=m -CONFIG_VIDEO_TEA6415C=m -CONFIG_VIDEO_TEA6420=m -CONFIG_VIDEO_MSP3400=m -CONFIG_VIDEO_CS3308=m -CONFIG_VIDEO_CS5345=m -CONFIG_VIDEO_CS53L32A=m -CONFIG_VIDEO_WM8775=m -CONFIG_VIDEO_WM8739=m -CONFIG_VIDEO_VP27SMPX=m - -# -# RDS decoders -# -CONFIG_VIDEO_SAA6588=m - -# -# Video decoders -# -CONFIG_VIDEO_BT819=m -CONFIG_VIDEO_BT856=m -CONFIG_VIDEO_BT866=m -CONFIG_VIDEO_KS0127=m -CONFIG_VIDEO_SAA7110=m -CONFIG_VIDEO_SAA711X=m -CONFIG_VIDEO_TVP5150=m -CONFIG_VIDEO_VPX3220=m - -# -# Video and audio decoders -# -CONFIG_VIDEO_SAA717X=m -CONFIG_VIDEO_CX25840=m - -# -# Video encoders -# -CONFIG_VIDEO_SAA7127=m -CONFIG_VIDEO_SAA7185=m -CONFIG_VIDEO_ADV7170=m -CONFIG_VIDEO_ADV7175=m - -# -# Camera sensor devices -# -CONFIG_VIDEO_OV2640=m -CONFIG_VIDEO_MT9V011=m - -# -# Flash devices -# - -# -# Video improvement chips -# -CONFIG_VIDEO_UPD64031A=m -CONFIG_VIDEO_UPD64083=m - -# -# Audio/Video compression chips -# -CONFIG_VIDEO_SAA6752HS=m - -# -# SDR tuner chips -# - -# -# Miscellaneous helper chips -# -CONFIG_VIDEO_M52790=m - -# -# Sensors used on soc_camera driver -# -CONFIG_MEDIA_TUNER=m -CONFIG_MEDIA_TUNER_SIMPLE=m -CONFIG_MEDIA_TUNER_TDA18250=m -CONFIG_MEDIA_TUNER_TDA8290=m -CONFIG_MEDIA_TUNER_TDA827X=m -CONFIG_MEDIA_TUNER_TDA18271=m -CONFIG_MEDIA_TUNER_TDA9887=m -CONFIG_MEDIA_TUNER_TEA5761=m -CONFIG_MEDIA_TUNER_TEA5767=m -CONFIG_MEDIA_TUNER_MT20XX=m -CONFIG_MEDIA_TUNER_MT2060=m -CONFIG_MEDIA_TUNER_MT2063=m -CONFIG_MEDIA_TUNER_MT2266=m -CONFIG_MEDIA_TUNER_MT2131=m -CONFIG_MEDIA_TUNER_QT1010=m -CONFIG_MEDIA_TUNER_XC2028=m -CONFIG_MEDIA_TUNER_XC5000=m -CONFIG_MEDIA_TUNER_XC4000=m -CONFIG_MEDIA_TUNER_MXL5005S=m -CONFIG_MEDIA_TUNER_MXL5007T=m -CONFIG_MEDIA_TUNER_MC44S803=m -CONFIG_MEDIA_TUNER_MAX2165=m -CONFIG_MEDIA_TUNER_TDA18218=m -CONFIG_MEDIA_TUNER_FC0011=m -CONFIG_MEDIA_TUNER_FC0012=m -CONFIG_MEDIA_TUNER_FC0013=m -CONFIG_MEDIA_TUNER_TDA18212=m -CONFIG_MEDIA_TUNER_E4000=m -CONFIG_MEDIA_TUNER_FC2580=m -CONFIG_MEDIA_TUNER_M88RS6000T=m -CONFIG_MEDIA_TUNER_TUA9001=m -CONFIG_MEDIA_TUNER_SI2157=m -CONFIG_MEDIA_TUNER_IT913X=m -CONFIG_MEDIA_TUNER_R820T=m -CONFIG_MEDIA_TUNER_QM1D1C0042=m -CONFIG_MEDIA_TUNER_QM1D1B0004=m - -# -# Multistandard (satellite) frontends -# -CONFIG_DVB_STB0899=m -CONFIG_DVB_STB6100=m -CONFIG_DVB_STV090x=m -CONFIG_DVB_STV0910=m -CONFIG_DVB_STV6110x=m -CONFIG_DVB_STV6111=m -CONFIG_DVB_MXL5XX=m -CONFIG_DVB_M88DS3103=m - -# -# Multistandard (cable + terrestrial) frontends -# -CONFIG_DVB_DRXK=m -CONFIG_DVB_TDA18271C2DD=m -CONFIG_DVB_SI2165=m -CONFIG_DVB_MN88472=m -CONFIG_DVB_MN88473=m - -# -# DVB-S (satellite) frontends -# -CONFIG_DVB_CX24110=m -CONFIG_DVB_CX24123=m -CONFIG_DVB_MT312=m -CONFIG_DVB_ZL10036=m -CONFIG_DVB_ZL10039=m -CONFIG_DVB_S5H1420=m -CONFIG_DVB_STV0288=m -CONFIG_DVB_STB6000=m -CONFIG_DVB_STV0299=m -CONFIG_DVB_STV6110=m -CONFIG_DVB_STV0900=m -CONFIG_DVB_TDA8083=m -CONFIG_DVB_TDA10086=m -CONFIG_DVB_TDA8261=m -CONFIG_DVB_VES1X93=m -CONFIG_DVB_TUNER_ITD1000=m -CONFIG_DVB_TUNER_CX24113=m -CONFIG_DVB_TDA826X=m -CONFIG_DVB_TUA6100=m -CONFIG_DVB_CX24116=m -CONFIG_DVB_CX24117=m -CONFIG_DVB_CX24120=m -CONFIG_DVB_SI21XX=m -CONFIG_DVB_TS2020=m -CONFIG_DVB_DS3000=m -CONFIG_DVB_MB86A16=m -CONFIG_DVB_TDA10071=m - -# -# DVB-T (terrestrial) frontends -# -CONFIG_DVB_SP8870=m -CONFIG_DVB_SP887X=m -CONFIG_DVB_CX22700=m -CONFIG_DVB_CX22702=m -CONFIG_DVB_DRXD=m -CONFIG_DVB_L64781=m -CONFIG_DVB_TDA1004X=m -CONFIG_DVB_NXT6000=m -CONFIG_DVB_MT352=m -CONFIG_DVB_ZL10353=m -CONFIG_DVB_DIB3000MB=m -CONFIG_DVB_DIB3000MC=m -CONFIG_DVB_DIB7000M=m -CONFIG_DVB_DIB7000P=m -CONFIG_DVB_TDA10048=m -CONFIG_DVB_AF9013=m -CONFIG_DVB_EC100=m -CONFIG_DVB_STV0367=m -CONFIG_DVB_CXD2820R=m -CONFIG_DVB_CXD2841ER=m -CONFIG_DVB_RTL2830=m -CONFIG_DVB_RTL2832=m -CONFIG_DVB_RTL2832_SDR=m -CONFIG_DVB_SI2168=m -CONFIG_DVB_GP8PSK_FE=m - -# -# DVB-C (cable) frontends -# -CONFIG_DVB_VES1820=m -CONFIG_DVB_TDA10021=m -CONFIG_DVB_TDA10023=m -CONFIG_DVB_STV0297=m - -# -# ATSC (North American/Korean Terrestrial/Cable DTV) frontends -# -CONFIG_DVB_NXT200X=m -CONFIG_DVB_OR51211=m -CONFIG_DVB_OR51132=m -CONFIG_DVB_BCM3510=m -CONFIG_DVB_LGDT330X=m -CONFIG_DVB_LGDT3305=m -CONFIG_DVB_LGDT3306A=m -CONFIG_DVB_LG2160=m -CONFIG_DVB_S5H1409=m -CONFIG_DVB_AU8522=m -CONFIG_DVB_AU8522_DTV=m -CONFIG_DVB_AU8522_V4L=m -CONFIG_DVB_S5H1411=m - -# -# ISDB-T (terrestrial) frontends -# -CONFIG_DVB_S921=m -CONFIG_DVB_DIB8000=m -CONFIG_DVB_MB86A20S=m - -# -# ISDB-S (satellite) & ISDB-T (terrestrial) frontends -# -CONFIG_DVB_TC90522=m - -# -# Digital terrestrial only tuners/PLL -# -CONFIG_DVB_PLL=m -CONFIG_DVB_TUNER_DIB0070=m -CONFIG_DVB_TUNER_DIB0090=m - -# -# SEC control devices for DVB-S -# -CONFIG_DVB_DRX39XYJ=m -CONFIG_DVB_LNBH25=m -CONFIG_DVB_LNBP21=m -CONFIG_DVB_LNBP22=m -CONFIG_DVB_ISL6405=m -CONFIG_DVB_ISL6421=m -CONFIG_DVB_ISL6423=m -CONFIG_DVB_A8293=m -CONFIG_DVB_LGS8GXX=m -CONFIG_DVB_ATBM8830=m -CONFIG_DVB_TDA665x=m -CONFIG_DVB_IX2505V=m -CONFIG_DVB_M88RS2000=m -CONFIG_DVB_AF9033=m - -# -# Common Interface (EN50221) controller drivers -# -CONFIG_DVB_CXD2099=m - -# -# Tools to develop new frontends -# -CONFIG_DVB_DUMMY_FE=m - -# -# Graphics support -# -CONFIG_AGP=y -CONFIG_AGP_AMD64=y -CONFIG_AGP_INTEL=y -CONFIG_AGP_SIS=y -CONFIG_AGP_VIA=y -CONFIG_INTEL_GTT=y -CONFIG_VGA_ARB=y -CONFIG_VGA_ARB_MAX_GPUS=16 -CONFIG_VGA_SWITCHEROO=y -CONFIG_DRM=m -CONFIG_DRM_MIPI_DSI=y -# CONFIG_DRM_DP_AUX_CHARDEV is not set -CONFIG_DRM_KMS_HELPER=m -CONFIG_DRM_KMS_FB_HELPER=y -CONFIG_DRM_FBDEV_EMULATION=y -CONFIG_DRM_FBDEV_OVERALLOC=100 -CONFIG_DRM_LOAD_EDID_FIRMWARE=y -# CONFIG_DRM_DP_CEC is not set -CONFIG_DRM_TTM=m -CONFIG_DRM_VM=y - -# -# I2C encoder or helper chips -# -CONFIG_DRM_I2C_CH7006=m -CONFIG_DRM_I2C_SIL164=m -CONFIG_DRM_I2C_NXP_TDA998X=m -# CONFIG_DRM_I2C_NXP_TDA9950 is not set -CONFIG_DRM_RADEON=m -CONFIG_DRM_RADEON_USERPTR=y -# CONFIG_DRM_AMDGPU is not set - -# -# ACP (Audio CoProcessor) Configuration -# - -# -# AMD Library routines -# -CONFIG_DRM_NOUVEAU=m -CONFIG_NOUVEAU_LEGACY_CTX_SUPPORT=y -CONFIG_NOUVEAU_DEBUG=5 -CONFIG_NOUVEAU_DEBUG_DEFAULT=3 -# CONFIG_NOUVEAU_DEBUG_MMU is not set -CONFIG_DRM_NOUVEAU_BACKLIGHT=y -CONFIG_DRM_I915=m -# CONFIG_DRM_I915_ALPHA_SUPPORT is not set -CONFIG_DRM_I915_CAPTURE_ERROR=y -CONFIG_DRM_I915_COMPRESS_ERROR=y -CONFIG_DRM_I915_USERPTR=y -CONFIG_DRM_I915_GVT=y -CONFIG_DRM_VGEM=m -# CONFIG_DRM_VKMS is not set -CONFIG_DRM_VMWGFX=m -CONFIG_DRM_VMWGFX_FBCON=y -CONFIG_DRM_GMA500=m -CONFIG_DRM_GMA600=y -CONFIG_DRM_GMA3600=y -CONFIG_DRM_UDL=m -CONFIG_DRM_AST=m -CONFIG_DRM_MGAG200=m -CONFIG_DRM_CIRRUS_QEMU=m -CONFIG_DRM_QXL=m -CONFIG_DRM_BOCHS=m -# CONFIG_DRM_VIRTIO_GPU is not set -CONFIG_DRM_PANEL=y - -# -# Display Panels -# -# CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN is not set -CONFIG_DRM_BRIDGE=y -CONFIG_DRM_PANEL_BRIDGE=y - -# -# Display Interface Bridges -# -# CONFIG_DRM_ANALOGIX_ANX78XX is not set -# CONFIG_DRM_HISI_HIBMC is not set -# CONFIG_DRM_TINYDRM is not set -# CONFIG_DRM_XEN is not set -# CONFIG_DRM_LEGACY is not set -CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y - -# -# Frame buffer Devices -# -CONFIG_FB=y -# CONFIG_FIRMWARE_EDID is not set -CONFIG_FB_CMDLINE=y -CONFIG_FB_NOTIFY=y -CONFIG_FB_BOOT_VESA_SUPPORT=y -CONFIG_FB_CFB_FILLRECT=y -CONFIG_FB_CFB_COPYAREA=y -CONFIG_FB_CFB_IMAGEBLIT=y -CONFIG_FB_SYS_FILLRECT=y -CONFIG_FB_SYS_COPYAREA=y -CONFIG_FB_SYS_IMAGEBLIT=y -CONFIG_FB_FOREIGN_ENDIAN=y -CONFIG_FB_BOTH_ENDIAN=y -# CONFIG_FB_BIG_ENDIAN is not set -# CONFIG_FB_LITTLE_ENDIAN is not set -CONFIG_FB_SYS_FOPS=y -CONFIG_FB_DEFERRED_IO=y -CONFIG_FB_BACKLIGHT=y -CONFIG_FB_MODE_HELPERS=y -CONFIG_FB_TILEBLITTING=y - -# -# Frame buffer hardware drivers -# -# CONFIG_FB_CIRRUS is not set -# CONFIG_FB_PM2 is not set -# CONFIG_FB_CYBER2000 is not set -# CONFIG_FB_ARC is not set -# CONFIG_FB_ASILIANT is not set -# CONFIG_FB_IMSTT is not set -CONFIG_FB_VGA16=m -CONFIG_FB_UVESA=m -CONFIG_FB_VESA=y -CONFIG_FB_EFI=y -# CONFIG_FB_N411 is not set -# CONFIG_FB_HGA is not set -CONFIG_FB_OPENCORES=m -# 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_LE80578 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_VIA is not set -# CONFIG_FB_NEOMAGIC is not set -# CONFIG_FB_KYRO is not set -# CONFIG_FB_3DFX is not set -CONFIG_FB_VOODOO1=m -# 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_SM501 is not set -# CONFIG_FB_SMSCUFX is not set -# CONFIG_FB_UDL is not set -CONFIG_FB_IBM_GXT4500=m -CONFIG_FB_VIRTUAL=m -CONFIG_XEN_FBDEV_FRONTEND=y -# CONFIG_FB_METRONOME is not set -# CONFIG_FB_MB862XX is not set -# CONFIG_FB_BROADSHEET is not set -CONFIG_FB_HYPERV=m -# CONFIG_FB_SIMPLE is not set -CONFIG_FB_SM712=m -CONFIG_BACKLIGHT_LCD_SUPPORT=y -CONFIG_LCD_CLASS_DEVICE=m -CONFIG_LCD_PLATFORM=m -CONFIG_BACKLIGHT_CLASS_DEVICE=y -# CONFIG_BACKLIGHT_GENERIC is not set -CONFIG_BACKLIGHT_PWM=m -CONFIG_BACKLIGHT_APPLE=m -CONFIG_BACKLIGHT_PM8941_WLED=m -# CONFIG_BACKLIGHT_SAHARA is not set -# CONFIG_BACKLIGHT_ADP8860 is not set -# CONFIG_BACKLIGHT_ADP8870 is not set -CONFIG_BACKLIGHT_LM3630A=m -CONFIG_BACKLIGHT_LM3639=m -CONFIG_BACKLIGHT_LP855X=m -CONFIG_BACKLIGHT_SKY81452=m -CONFIG_BACKLIGHT_GPIO=m -CONFIG_BACKLIGHT_LV5207LP=m -CONFIG_BACKLIGHT_BD6107=m -# CONFIG_BACKLIGHT_ARCXCNN is not set -CONFIG_VGASTATE=m -CONFIG_HDMI=y - -# -# Console display driver support -# -CONFIG_VGA_CONSOLE=y -CONFIG_VGACON_SOFT_SCROLLBACK=y -CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=64 -# CONFIG_VGACON_SOFT_SCROLLBACK_PERSISTENT_ENABLE_BY_DEFAULT is not set -CONFIG_DUMMY_CONSOLE=y -CONFIG_DUMMY_CONSOLE_COLUMNS=80 -CONFIG_DUMMY_CONSOLE_ROWS=25 -CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y -CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y -# CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER is not set -# CONFIG_LOGO is not set -CONFIG_SOUND=m -CONFIG_SOUND_OSS_CORE=y -CONFIG_SOUND_OSS_CORE_PRECLAIM=y -CONFIG_SND=m -CONFIG_SND_TIMER=m -CONFIG_SND_PCM=m -CONFIG_SND_HWDEP=m -CONFIG_SND_SEQ_DEVICE=m -CONFIG_SND_RAWMIDI=m -CONFIG_SND_JACK=y -CONFIG_SND_JACK_INPUT_DEV=y -CONFIG_SND_OSSEMUL=y -CONFIG_SND_MIXER_OSS=m -CONFIG_SND_PCM_OSS=m -CONFIG_SND_PCM_OSS_PLUGINS=y -CONFIG_SND_PCM_TIMER=y -CONFIG_SND_HRTIMER=m -CONFIG_SND_DYNAMIC_MINORS=y -CONFIG_SND_MAX_CARDS=32 -# CONFIG_SND_SUPPORT_OLD_API is not set -CONFIG_SND_PROC_FS=y -CONFIG_SND_VERBOSE_PROCFS=y -# CONFIG_SND_VERBOSE_PRINTK is not set -# CONFIG_SND_DEBUG is not set -CONFIG_SND_VMASTER=y -CONFIG_SND_DMA_SGBUF=y -CONFIG_SND_SEQUENCER=m -CONFIG_SND_SEQ_DUMMY=m -CONFIG_SND_SEQUENCER_OSS=m -CONFIG_SND_SEQ_HRTIMER_DEFAULT=y -CONFIG_SND_SEQ_MIDI_EVENT=m -CONFIG_SND_SEQ_MIDI=m -CONFIG_SND_SEQ_MIDI_EMUL=m -CONFIG_SND_SEQ_VIRMIDI=m -CONFIG_SND_MPU401_UART=m -CONFIG_SND_OPL3_LIB=m -CONFIG_SND_OPL3_LIB_SEQ=m -CONFIG_SND_VX_LIB=m -CONFIG_SND_AC97_CODEC=m -CONFIG_SND_DRIVERS=y -CONFIG_SND_PCSP=m -CONFIG_SND_DUMMY=m -CONFIG_SND_ALOOP=m -CONFIG_SND_VIRMIDI=m -CONFIG_SND_MTPAV=m -CONFIG_SND_MTS64=m -CONFIG_SND_SERIAL_U16550=m -CONFIG_SND_MPU401=m -CONFIG_SND_PORTMAN2X4=m -CONFIG_SND_AC97_POWER_SAVE=y -CONFIG_SND_AC97_POWER_SAVE_DEFAULT=0 -CONFIG_SND_SB_COMMON=m -CONFIG_SND_PCI=y -CONFIG_SND_AD1889=m -CONFIG_SND_ALS300=m -CONFIG_SND_ALS4000=m -CONFIG_SND_ALI5451=m -CONFIG_SND_ASIHPI=m -CONFIG_SND_ATIIXP=m -CONFIG_SND_ATIIXP_MODEM=m -CONFIG_SND_AU8810=m -CONFIG_SND_AU8820=m -CONFIG_SND_AU8830=m -# CONFIG_SND_AW2 is not set -CONFIG_SND_AZT3328=m -CONFIG_SND_BT87X=m -# CONFIG_SND_BT87X_OVERCLOCK is not set -CONFIG_SND_CA0106=m -CONFIG_SND_CMIPCI=m -CONFIG_SND_OXYGEN_LIB=m -CONFIG_SND_OXYGEN=m -CONFIG_SND_CS4281=m -CONFIG_SND_CS46XX=m -CONFIG_SND_CS46XX_NEW_DSP=y -CONFIG_SND_CTXFI=m -CONFIG_SND_DARLA20=m -CONFIG_SND_GINA20=m -CONFIG_SND_LAYLA20=m -CONFIG_SND_DARLA24=m -CONFIG_SND_GINA24=m -CONFIG_SND_LAYLA24=m -CONFIG_SND_MONA=m -CONFIG_SND_MIA=m -CONFIG_SND_ECHO3G=m -CONFIG_SND_INDIGO=m -CONFIG_SND_INDIGOIO=m -CONFIG_SND_INDIGODJ=m -CONFIG_SND_INDIGOIOX=m -CONFIG_SND_INDIGODJX=m -CONFIG_SND_EMU10K1=m -CONFIG_SND_EMU10K1_SEQ=m -CONFIG_SND_EMU10K1X=m -CONFIG_SND_ENS1370=m -CONFIG_SND_ENS1371=m -CONFIG_SND_ES1938=m -CONFIG_SND_ES1968=m -CONFIG_SND_ES1968_INPUT=y -CONFIG_SND_ES1968_RADIO=y -CONFIG_SND_FM801=m -CONFIG_SND_FM801_TEA575X_BOOL=y -CONFIG_SND_HDSP=m -CONFIG_SND_HDSPM=m -CONFIG_SND_ICE1712=m -CONFIG_SND_ICE1724=m -CONFIG_SND_INTEL8X0=m -CONFIG_SND_INTEL8X0M=m -CONFIG_SND_KORG1212=m -CONFIG_SND_LOLA=m -CONFIG_SND_LX6464ES=m -CONFIG_SND_MAESTRO3=m -CONFIG_SND_MAESTRO3_INPUT=y -CONFIG_SND_MIXART=m -CONFIG_SND_NM256=m -CONFIG_SND_PCXHR=m -CONFIG_SND_RIPTIDE=m -CONFIG_SND_RME32=m -CONFIG_SND_RME96=m -CONFIG_SND_RME9652=m -CONFIG_SND_SONICVIBES=m -CONFIG_SND_TRIDENT=m -CONFIG_SND_VIA82XX=m -CONFIG_SND_VIA82XX_MODEM=m -CONFIG_SND_VIRTUOSO=m -CONFIG_SND_VX222=m -CONFIG_SND_YMFPCI=m - -# -# HD-Audio -# -CONFIG_SND_HDA=m -CONFIG_SND_HDA_INTEL=m -CONFIG_SND_HDA_HWDEP=y -CONFIG_SND_HDA_RECONFIG=y -CONFIG_SND_HDA_INPUT_BEEP=y -CONFIG_SND_HDA_INPUT_BEEP_MODE=0 -CONFIG_SND_HDA_PATCH_LOADER=y -CONFIG_SND_HDA_CODEC_REALTEK=m -CONFIG_SND_HDA_CODEC_ANALOG=m -CONFIG_SND_HDA_CODEC_SIGMATEL=m -CONFIG_SND_HDA_CODEC_VIA=m -CONFIG_SND_HDA_CODEC_HDMI=m -CONFIG_SND_HDA_CODEC_CIRRUS=m -CONFIG_SND_HDA_CODEC_CONEXANT=m -CONFIG_SND_HDA_CODEC_CA0110=m -CONFIG_SND_HDA_CODEC_CA0132=m -CONFIG_SND_HDA_CODEC_CA0132_DSP=y -CONFIG_SND_HDA_CODEC_CMEDIA=m -CONFIG_SND_HDA_CODEC_SI3054=m -CONFIG_SND_HDA_GENERIC=m -CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0 -CONFIG_SND_HDA_CORE=m -CONFIG_SND_HDA_DSP_LOADER=y -CONFIG_SND_HDA_COMPONENT=y -CONFIG_SND_HDA_I915=y -CONFIG_SND_HDA_PREALLOC_SIZE=4096 -CONFIG_SND_USB=y -CONFIG_SND_USB_AUDIO=m -CONFIG_SND_USB_UA101=m -CONFIG_SND_USB_USX2Y=m -CONFIG_SND_USB_CAIAQ=m -CONFIG_SND_USB_CAIAQ_INPUT=y -CONFIG_SND_USB_US122L=m -CONFIG_SND_USB_6FIRE=m -# CONFIG_SND_USB_HIFACE is not set -CONFIG_SND_BCD2000=m -CONFIG_SND_USB_LINE6=m -CONFIG_SND_USB_POD=m -CONFIG_SND_USB_PODHD=m -CONFIG_SND_USB_TONEPORT=m -CONFIG_SND_USB_VARIAX=m -CONFIG_SND_FIREWIRE=y -CONFIG_SND_FIREWIRE_LIB=m -CONFIG_SND_DICE=m -# CONFIG_SND_OXFW is not set -CONFIG_SND_ISIGHT=m -CONFIG_SND_FIREWORKS=m -CONFIG_SND_BEBOB=m -CONFIG_SND_FIREWIRE_DIGI00X=m -CONFIG_SND_FIREWIRE_TASCAM=m -# CONFIG_SND_FIREWIRE_MOTU is not set -# CONFIG_SND_FIREFACE is not set -# CONFIG_SND_PCMCIA is not set -# CONFIG_SND_SOC is not set -CONFIG_SND_X86=y -# CONFIG_HDMI_LPE_AUDIO is not set -CONFIG_SND_SYNTH_EMUX=m -# CONFIG_SND_XEN_FRONTEND is not set -CONFIG_AC97_BUS=m - -# -# HID support -# -CONFIG_HID=y -CONFIG_HID_BATTERY_STRENGTH=y -CONFIG_HIDRAW=y -CONFIG_UHID=y -CONFIG_HID_GENERIC=y - -# -# Special HID drivers -# -CONFIG_HID_A4TECH=y -# CONFIG_HID_ACCUTOUCH is not set -CONFIG_HID_ACRUX=m -CONFIG_HID_ACRUX_FF=y -CONFIG_HID_APPLE=y -CONFIG_HID_APPLEIR=m -# CONFIG_HID_ASUS is not set -CONFIG_HID_AUREAL=m -CONFIG_HID_BELKIN=y -CONFIG_HID_BETOP_FF=m -CONFIG_HID_CHERRY=y -CONFIG_HID_CHICONY=y -CONFIG_HID_CORSAIR=m -# CONFIG_HID_COUGAR is not set -CONFIG_HID_PRODIKEYS=m -# CONFIG_HID_CMEDIA is not set -CONFIG_HID_CP2112=m -CONFIG_HID_CYPRESS=y -CONFIG_HID_DRAGONRISE=m -CONFIG_DRAGONRISE_FF=y -CONFIG_HID_EMS_FF=m -# CONFIG_HID_ELAN is not set -CONFIG_HID_ELECOM=m -CONFIG_HID_ELO=m -CONFIG_HID_EZKEY=y -CONFIG_HID_GEMBIRD=m -CONFIG_HID_GFRM=m -CONFIG_HID_HOLTEK=m -CONFIG_HOLTEK_FF=y -# CONFIG_HID_GOOGLE_HAMMER is not set -CONFIG_HID_GT683R=m -CONFIG_HID_KEYTOUCH=m -CONFIG_HID_KYE=m -CONFIG_HID_UCLOGIC=m -CONFIG_HID_WALTOP=m -CONFIG_HID_GYRATION=m -CONFIG_HID_ICADE=m -CONFIG_HID_ITE=y -# CONFIG_HID_JABRA is not set -CONFIG_HID_TWINHAN=m -CONFIG_HID_KENSINGTON=y -CONFIG_HID_LCPOWER=m -CONFIG_HID_LED=m -CONFIG_HID_LENOVO=m -CONFIG_HID_LOGITECH=y -CONFIG_HID_LOGITECH_DJ=m -CONFIG_HID_LOGITECH_HIDPP=m -CONFIG_LOGITECH_FF=y -CONFIG_LOGIRUMBLEPAD2_FF=y -CONFIG_LOGIG940_FF=y -CONFIG_LOGIWHEELS_FF=y -CONFIG_HID_MAGICMOUSE=m -# CONFIG_HID_MAYFLASH is not set -CONFIG_HID_REDRAGON=y -CONFIG_HID_MICROSOFT=y -CONFIG_HID_MONTEREY=y -CONFIG_HID_MULTITOUCH=m -# CONFIG_HID_NTI is not set -CONFIG_HID_NTRIG=y -CONFIG_HID_ORTEK=m -CONFIG_HID_PANTHERLORD=m -CONFIG_PANTHERLORD_FF=y -# CONFIG_HID_PENMOUNT is not set -CONFIG_HID_PETALYNX=m -CONFIG_HID_PICOLCD=m -CONFIG_HID_PICOLCD_FB=y -CONFIG_HID_PICOLCD_BACKLIGHT=y -CONFIG_HID_PICOLCD_LCD=y -CONFIG_HID_PICOLCD_LEDS=y -CONFIG_HID_PICOLCD_CIR=y -CONFIG_HID_PLANTRONICS=y -CONFIG_HID_PRIMAX=m -# CONFIG_HID_RETRODE is not set -CONFIG_HID_ROCCAT=m -CONFIG_HID_SAITEK=m -CONFIG_HID_SAMSUNG=m -CONFIG_HID_SONY=m -CONFIG_SONY_FF=y -CONFIG_HID_SPEEDLINK=m -# CONFIG_HID_STEAM is not set -CONFIG_HID_STEELSERIES=m -CONFIG_HID_SUNPLUS=m -CONFIG_HID_RMI=m -CONFIG_HID_GREENASIA=m -CONFIG_GREENASIA_FF=y -CONFIG_HID_HYPERV_MOUSE=m -CONFIG_HID_SMARTJOYPLUS=m -CONFIG_SMARTJOYPLUS_FF=y -CONFIG_HID_TIVO=m -CONFIG_HID_TOPSEED=m -CONFIG_HID_THINGM=m -CONFIG_HID_THRUSTMASTER=m -CONFIG_THRUSTMASTER_FF=y -# CONFIG_HID_UDRAW_PS3 is not set -CONFIG_HID_WACOM=m -CONFIG_HID_WIIMOTE=m -CONFIG_HID_XINMO=m -CONFIG_HID_ZEROPLUS=m -CONFIG_ZEROPLUS_FF=y -CONFIG_HID_ZYDACRON=m -CONFIG_HID_SENSOR_HUB=m -CONFIG_HID_SENSOR_CUSTOM_SENSOR=m -CONFIG_HID_ALPS=m - -# -# USB HID support -# -CONFIG_USB_HID=y -CONFIG_HID_PID=y -CONFIG_USB_HIDDEV=y - -# -# I2C HID support -# -CONFIG_I2C_HID=m - -# -# Intel ISH HID support -# -CONFIG_INTEL_ISH_HID=m -CONFIG_USB_OHCI_LITTLE_ENDIAN=y -CONFIG_USB_SUPPORT=y -CONFIG_USB_COMMON=y -CONFIG_USB_ARCH_HAS_HCD=y -CONFIG_USB=y -CONFIG_USB_PCI=y -CONFIG_USB_ANNOUNCE_NEW_DEVICES=y - -# -# 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_OTG_FSM=m -CONFIG_USB_LEDS_TRIGGER_USBPORT=m -CONFIG_USB_MON=y -CONFIG_USB_WUSB=m -CONFIG_USB_WUSB_CBAF=m -# CONFIG_USB_WUSB_CBAF_DEBUG is not set - -# -# USB Host Controller Drivers -# -# CONFIG_USB_C67X00_HCD is not set -CONFIG_USB_XHCI_HCD=y -# CONFIG_USB_XHCI_DBGCAP is not set -CONFIG_USB_XHCI_PCI=y -CONFIG_USB_XHCI_PLATFORM=m -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_ROOT_HUB_TT=y -CONFIG_USB_EHCI_TT_NEWSCHED=y -CONFIG_USB_EHCI_PCI=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_FOTG210_HCD=m -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_OHCI_HCD_PCI=y -# CONFIG_USB_OHCI_HCD_PLATFORM is not set -CONFIG_USB_UHCI_HCD=y -CONFIG_USB_U132_HCD=m -CONFIG_USB_SL811_HCD=m -CONFIG_USB_SL811_HCD_ISO=y -# CONFIG_USB_SL811_CS is not set -# CONFIG_USB_R8A66597_HCD is not set -CONFIG_USB_WHCI_HCD=m -CONFIG_USB_HWA_HCD=m -# CONFIG_USB_HCD_BCMA is not set -# CONFIG_USB_HCD_SSB is not set -# CONFIG_USB_HCD_TEST_MODE is not set - -# -# USB Device Class drivers -# -CONFIG_USB_ACM=m -CONFIG_USB_PRINTER=m -CONFIG_USB_WDM=m -CONFIG_USB_TMC=m - -# -# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may -# - -# -# also be needed; see USB_STORAGE Help for more info -# -CONFIG_USB_STORAGE=m -# CONFIG_USB_STORAGE_DEBUG is not set -CONFIG_USB_STORAGE_REALTEK=m -CONFIG_REALTEK_AUTOPM=y -CONFIG_USB_STORAGE_DATAFAB=m -CONFIG_USB_STORAGE_FREECOM=m -CONFIG_USB_STORAGE_ISD200=m -CONFIG_USB_STORAGE_USBAT=m -CONFIG_USB_STORAGE_SDDR09=m -CONFIG_USB_STORAGE_SDDR55=m -CONFIG_USB_STORAGE_JUMPSHOT=m -CONFIG_USB_STORAGE_ALAUDA=m -CONFIG_USB_STORAGE_ONETOUCH=m -CONFIG_USB_STORAGE_KARMA=m -CONFIG_USB_STORAGE_CYPRESS_ATACB=m -CONFIG_USB_STORAGE_ENE_UB6250=m -CONFIG_USB_UAS=m - -# -# USB Imaging devices -# -CONFIG_USB_MDC800=m -CONFIG_USB_MICROTEK=m -# CONFIG_USBIP_CORE is not set -CONFIG_USB_MUSB_HDRC=m -CONFIG_USB_MUSB_HOST=y - -# -# Platform Glue Layer -# - -# -# MUSB DMA mode -# -CONFIG_MUSB_PIO_ONLY=y -CONFIG_USB_DWC3=m -CONFIG_USB_DWC3_HOST=y - -# -# Platform Glue Driver Support -# -CONFIG_USB_DWC3_PCI=m -CONFIG_USB_DWC3_HAPS=m -CONFIG_USB_DWC2=y -CONFIG_USB_DWC2_HOST=y - -# -# Gadget/Dual-role mode requires USB Gadget support to be enabled -# -CONFIG_USB_DWC2_PCI=y -# CONFIG_USB_DWC2_DEBUG is not set -# CONFIG_USB_DWC2_TRACK_MISSED_SOFS is not set -# CONFIG_USB_CHIPIDEA is not set -CONFIG_USB_ISP1760=m -CONFIG_USB_ISP1760_HCD=y -CONFIG_USB_ISP1760_HOST_ROLE=y - -# -# USB port drivers -# -CONFIG_USB_USS720=m -CONFIG_USB_SERIAL=y -CONFIG_USB_SERIAL_CONSOLE=y -CONFIG_USB_SERIAL_GENERIC=y -# CONFIG_USB_SERIAL_SIMPLE is not set -CONFIG_USB_SERIAL_AIRCABLE=m -CONFIG_USB_SERIAL_ARK3116=m -CONFIG_USB_SERIAL_BELKIN=m -CONFIG_USB_SERIAL_CH341=m -CONFIG_USB_SERIAL_WHITEHEAT=m -CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m -CONFIG_USB_SERIAL_CP210X=m -CONFIG_USB_SERIAL_CYPRESS_M8=m -CONFIG_USB_SERIAL_EMPEG=m -CONFIG_USB_SERIAL_FTDI_SIO=m -CONFIG_USB_SERIAL_VISOR=m -CONFIG_USB_SERIAL_IPAQ=m -CONFIG_USB_SERIAL_IR=m -CONFIG_USB_SERIAL_EDGEPORT=m -CONFIG_USB_SERIAL_EDGEPORT_TI=m -# CONFIG_USB_SERIAL_F81232 is not set -# CONFIG_USB_SERIAL_F8153X is not set -CONFIG_USB_SERIAL_GARMIN=m -CONFIG_USB_SERIAL_IPW=m -CONFIG_USB_SERIAL_IUU=m -CONFIG_USB_SERIAL_KEYSPAN_PDA=m -CONFIG_USB_SERIAL_KEYSPAN=m -CONFIG_USB_SERIAL_KLSI=m -CONFIG_USB_SERIAL_KOBIL_SCT=m -CONFIG_USB_SERIAL_MCT_U232=m -# CONFIG_USB_SERIAL_METRO is not set -CONFIG_USB_SERIAL_MOS7720=m -CONFIG_USB_SERIAL_MOS7715_PARPORT=y -CONFIG_USB_SERIAL_MOS7840=m -CONFIG_USB_SERIAL_MXUPORT=m -CONFIG_USB_SERIAL_NAVMAN=m -CONFIG_USB_SERIAL_PL2303=m -CONFIG_USB_SERIAL_OTI6858=m -CONFIG_USB_SERIAL_QCAUX=m -CONFIG_USB_SERIAL_QUALCOMM=m -CONFIG_USB_SERIAL_SPCP8X5=m -CONFIG_USB_SERIAL_SAFE=m -CONFIG_USB_SERIAL_SAFE_PADDED=y -CONFIG_USB_SERIAL_SIERRAWIRELESS=m -CONFIG_USB_SERIAL_SYMBOL=m -CONFIG_USB_SERIAL_TI=m -CONFIG_USB_SERIAL_CYBERJACK=m -CONFIG_USB_SERIAL_XIRCOM=m -CONFIG_USB_SERIAL_WWAN=m -CONFIG_USB_SERIAL_OPTION=m -CONFIG_USB_SERIAL_OMNINET=m -CONFIG_USB_SERIAL_OPTICON=m -CONFIG_USB_SERIAL_XSENS_MT=m -CONFIG_USB_SERIAL_WISHBONE=m -CONFIG_USB_SERIAL_SSU100=m -CONFIG_USB_SERIAL_QT2=m -# CONFIG_USB_SERIAL_UPD78F0730 is not set -CONFIG_USB_SERIAL_DEBUG=m - -# -# USB Miscellaneous drivers -# -CONFIG_USB_EMI62=m -CONFIG_USB_EMI26=m -CONFIG_USB_ADUTUX=m -CONFIG_USB_SEVSEG=m -# CONFIG_USB_RIO500 is not set -CONFIG_USB_LEGOTOWER=m -CONFIG_USB_LCD=m -# CONFIG_USB_CYPRESS_CY7C63 is not set -# CONFIG_USB_CYTHERM is not set -CONFIG_USB_IDMOUSE=m -CONFIG_USB_FTDI_ELAN=m -CONFIG_USB_APPLEDISPLAY=m -CONFIG_USB_SISUSBVGA=m -CONFIG_USB_SISUSBVGA_CON=y -CONFIG_USB_LD=m -CONFIG_USB_TRANCEVIBRATOR=m -CONFIG_USB_IOWARRIOR=m -# CONFIG_USB_TEST is not set -# CONFIG_USB_EHSET_TEST_FIXTURE is not set -CONFIG_USB_ISIGHTFW=m -CONFIG_USB_YUREX=m -CONFIG_USB_EZUSB_FX2=m -# CONFIG_USB_HUB_USB251XB is not set -CONFIG_USB_HSIC_USB3503=m -CONFIG_USB_HSIC_USB4604=m -# CONFIG_USB_LINK_LAYER_TEST is not set -CONFIG_USB_CHAOSKEY=m -CONFIG_USB_ATM=m -CONFIG_USB_SPEEDTOUCH=m -CONFIG_USB_CXACRU=m -CONFIG_USB_UEAGLEATM=m -CONFIG_USB_XUSBATM=m - -# -# USB Physical Layer drivers -# -CONFIG_USB_PHY=y -CONFIG_NOP_USB_XCEIV=y -CONFIG_USB_GPIO_VBUS=m -# CONFIG_TAHVO_USB is not set -CONFIG_USB_ISP1301=m -# CONFIG_USB_GADGET is not set -# CONFIG_TYPEC is not set -# CONFIG_USB_ROLE_SWITCH is not set -# CONFIG_USB_LED_TRIG is not set -# CONFIG_USB_ULPI_BUS is not set -CONFIG_UWB=m -CONFIG_UWB_HWA=m -CONFIG_UWB_WHCI=m -CONFIG_UWB_I1480U=m -CONFIG_MMC=m -CONFIG_MMC_BLOCK=m -CONFIG_MMC_BLOCK_MINORS=8 -CONFIG_SDIO_UART=m -# CONFIG_MMC_TEST is not set - -# -# MMC/SD/SDIO Host Controller Drivers -# -# CONFIG_MMC_DEBUG is not set -CONFIG_MMC_SDHCI=m -CONFIG_MMC_SDHCI_PCI=m -CONFIG_MMC_RICOH_MMC=y -CONFIG_MMC_SDHCI_ACPI=m -CONFIG_MMC_SDHCI_PLTFM=m -# CONFIG_MMC_SDHCI_F_SDH30 is not set -CONFIG_MMC_WBSD=m -CONFIG_MMC_TIFM_SD=m -CONFIG_MMC_SDRICOH_CS=m -CONFIG_MMC_CB710=m -CONFIG_MMC_VIA_SDMMC=m -CONFIG_MMC_VUB300=m -CONFIG_MMC_USHC=m -CONFIG_MMC_USDHI6ROL0=m -CONFIG_MMC_CQHCI=m -# CONFIG_MMC_TOSHIBA_PCI is not set -# CONFIG_MMC_MTK is not set -# CONFIG_MMC_SDHCI_XENON is not set -CONFIG_MEMSTICK=m -# CONFIG_MEMSTICK_DEBUG is not set - -# -# MemoryStick drivers -# -# CONFIG_MEMSTICK_UNSAFE_RESUME is not set -CONFIG_MSPRO_BLOCK=m -# CONFIG_MS_BLOCK is not set - -# -# MemoryStick Host Controller Drivers -# -CONFIG_MEMSTICK_TIFM_MS=m -CONFIG_MEMSTICK_JMICRON_38X=m -CONFIG_MEMSTICK_R592=m -CONFIG_NEW_LEDS=y -CONFIG_LEDS_CLASS=y -CONFIG_LEDS_CLASS_FLASH=m -# CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set - -# -# LED drivers -# -# CONFIG_LEDS_APU is not set -# CONFIG_LEDS_AS3645A is not set -CONFIG_LEDS_LM3530=m -CONFIG_LEDS_LM3642=m -# CONFIG_LEDS_LM3601X is not set -# CONFIG_LEDS_MT6323 is not set -CONFIG_LEDS_PCA9532=m -CONFIG_LEDS_PCA9532_GPIO=y -CONFIG_LEDS_GPIO=m -CONFIG_LEDS_LP3944=m -CONFIG_LEDS_LP3952=m -CONFIG_LEDS_LP55XX_COMMON=m -CONFIG_LEDS_LP5521=m -CONFIG_LEDS_LP5523=m -CONFIG_LEDS_LP5562=m -CONFIG_LEDS_LP8501=m -CONFIG_LEDS_CLEVO_MAIL=m -CONFIG_LEDS_PCA955X=m -# CONFIG_LEDS_PCA955X_GPIO is not set -CONFIG_LEDS_PCA963X=m -CONFIG_LEDS_PWM=m -CONFIG_LEDS_BD2802=m -CONFIG_LEDS_INTEL_SS4200=m -CONFIG_LEDS_LT3593=m -CONFIG_LEDS_TCA6507=m -# CONFIG_LEDS_TLC591XX is not set -CONFIG_LEDS_LM355x=m - -# -# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM) -# -CONFIG_LEDS_BLINKM=m -CONFIG_LEDS_MLXCPLD=m -# CONFIG_LEDS_MLXREG is not set -# CONFIG_LEDS_USER is not set -# CONFIG_LEDS_NIC78BX is not set - -# -# LED Triggers -# -CONFIG_LEDS_TRIGGERS=y -CONFIG_LEDS_TRIGGER_TIMER=m -CONFIG_LEDS_TRIGGER_ONESHOT=y -# CONFIG_LEDS_TRIGGER_DISK is not set -# CONFIG_LEDS_TRIGGER_MTD is not set -CONFIG_LEDS_TRIGGER_HEARTBEAT=m -CONFIG_LEDS_TRIGGER_BACKLIGHT=m -CONFIG_LEDS_TRIGGER_CPU=y -# CONFIG_LEDS_TRIGGER_ACTIVITY is not set -CONFIG_LEDS_TRIGGER_GPIO=m -CONFIG_LEDS_TRIGGER_DEFAULT_ON=m - -# -# iptables trigger is under Netfilter config (LED target) -# -CONFIG_LEDS_TRIGGER_TRANSIENT=m -CONFIG_LEDS_TRIGGER_CAMERA=m -# CONFIG_LEDS_TRIGGER_PANIC is not set -# CONFIG_LEDS_TRIGGER_NETDEV is not set -CONFIG_ACCESSIBILITY=y -CONFIG_A11Y_BRAILLE_CONSOLE=y -CONFIG_INFINIBAND=m -CONFIG_INFINIBAND_USER_MAD=m -CONFIG_INFINIBAND_USER_ACCESS=m -# CONFIG_INFINIBAND_EXP_LEGACY_VERBS_NEW_UAPI is not set -CONFIG_INFINIBAND_USER_MEM=y -CONFIG_INFINIBAND_ON_DEMAND_PAGING=y -CONFIG_INFINIBAND_ADDR_TRANS=y -CONFIG_INFINIBAND_ADDR_TRANS_CONFIGFS=y -CONFIG_INFINIBAND_MTHCA=m -CONFIG_INFINIBAND_MTHCA_DEBUG=y -CONFIG_INFINIBAND_QIB=m -CONFIG_INFINIBAND_QIB_DCA=y -CONFIG_INFINIBAND_CXGB3=m -CONFIG_INFINIBAND_CXGB4=m -# CONFIG_INFINIBAND_I40IW is not set -CONFIG_MLX4_INFINIBAND=m -CONFIG_INFINIBAND_NES=m -# CONFIG_INFINIBAND_NES_DEBUG is not set -# CONFIG_INFINIBAND_OCRDMA is not set -# CONFIG_INFINIBAND_VMWARE_PVRDMA is not set -CONFIG_INFINIBAND_USNIC=m -CONFIG_INFINIBAND_IPOIB=m -CONFIG_INFINIBAND_IPOIB_CM=y -CONFIG_INFINIBAND_IPOIB_DEBUG=y -CONFIG_INFINIBAND_IPOIB_DEBUG_DATA=y -CONFIG_INFINIBAND_SRP=m -CONFIG_INFINIBAND_SRPT=m -CONFIG_INFINIBAND_ISER=m -CONFIG_INFINIBAND_ISERT=m -# CONFIG_INFINIBAND_OPA_VNIC is not set -CONFIG_INFINIBAND_RDMAVT=m -CONFIG_RDMA_RXE=m -CONFIG_INFINIBAND_HFI1=m -CONFIG_HFI1_DEBUG_SDMA_ORDER=y -CONFIG_SDMA_VERBOSITY=y -CONFIG_INFINIBAND_QEDR=m -# CONFIG_INFINIBAND_BNXT_RE is not set -CONFIG_EDAC_ATOMIC_SCRUB=y -CONFIG_EDAC_SUPPORT=y -CONFIG_EDAC=y -CONFIG_EDAC_LEGACY_SYSFS=y -# CONFIG_EDAC_DEBUG is not set -CONFIG_EDAC_DECODE_MCE=m -# CONFIG_EDAC_GHES is not set -CONFIG_EDAC_AMD64=m -# CONFIG_EDAC_AMD64_ERROR_INJECTION is not set -CONFIG_EDAC_E752X=m -CONFIG_EDAC_I82975X=m -CONFIG_EDAC_I3000=m -CONFIG_EDAC_I3200=m -CONFIG_EDAC_IE31200=m -CONFIG_EDAC_X38=m -CONFIG_EDAC_I5400=m -CONFIG_EDAC_I7CORE=m -CONFIG_EDAC_I5000=m -CONFIG_EDAC_I5100=m -CONFIG_EDAC_I7300=m -CONFIG_EDAC_SBRIDGE=m -CONFIG_EDAC_SKX=m -# CONFIG_EDAC_PND2 is not set -CONFIG_RTC_LIB=y -CONFIG_RTC_MC146818_LIB=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_HCTOSYS=y -CONFIG_RTC_HCTOSYS_DEVICE="rtc0" -CONFIG_RTC_SYSTOHC=y -CONFIG_RTC_SYSTOHC_DEVICE="rtc0" -# CONFIG_RTC_DEBUG is not set -CONFIG_RTC_NVMEM=y - -# -# 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_ABB5ZES3=m -CONFIG_RTC_DRV_ABX80X=m -CONFIG_RTC_DRV_DS1307=m -# CONFIG_RTC_DRV_DS1307_CENTURY is not set -CONFIG_RTC_DRV_DS1374=m -# CONFIG_RTC_DRV_DS1374_WDT is not set -CONFIG_RTC_DRV_DS1672=m -CONFIG_RTC_DRV_MAX6900=m -CONFIG_RTC_DRV_RS5C372=m -CONFIG_RTC_DRV_ISL1208=m -CONFIG_RTC_DRV_ISL12022=m -CONFIG_RTC_DRV_X1205=m -CONFIG_RTC_DRV_PCF8523=m -CONFIG_RTC_DRV_PCF85063=m -# CONFIG_RTC_DRV_PCF85363 is not set -CONFIG_RTC_DRV_PCF8563=m -CONFIG_RTC_DRV_PCF8583=m -CONFIG_RTC_DRV_M41T80=m -CONFIG_RTC_DRV_M41T80_WDT=y -CONFIG_RTC_DRV_BQ32K=m -# CONFIG_RTC_DRV_S35390A is not set -CONFIG_RTC_DRV_FM3130=m -# CONFIG_RTC_DRV_RX8010 is not set -CONFIG_RTC_DRV_RX8581=m -CONFIG_RTC_DRV_RX8025=m -CONFIG_RTC_DRV_EM3027=m -CONFIG_RTC_DRV_RV8803=m - -# -# SPI RTC drivers -# -CONFIG_RTC_I2C_AND_SPI=m - -# -# SPI and I2C RTC drivers -# -CONFIG_RTC_DRV_DS3232=m -CONFIG_RTC_DRV_DS3232_HWMON=y -# CONFIG_RTC_DRV_PCF2127 is not set -CONFIG_RTC_DRV_RV3029C2=m -CONFIG_RTC_DRV_RV3029_HWMON=y - -# -# Platform RTC drivers -# -CONFIG_RTC_DRV_CMOS=y -CONFIG_RTC_DRV_DS1286=m -CONFIG_RTC_DRV_DS1511=m -CONFIG_RTC_DRV_DS1553=m -CONFIG_RTC_DRV_DS1685_FAMILY=m -CONFIG_RTC_DRV_DS1685=y -# CONFIG_RTC_DRV_DS1689 is not set -# CONFIG_RTC_DRV_DS17285 is not set -# CONFIG_RTC_DRV_DS17485 is not set -# CONFIG_RTC_DRV_DS17885 is not set -CONFIG_RTC_DS1685_PROC_REGS=y -CONFIG_RTC_DRV_DS1742=m -CONFIG_RTC_DRV_DS2404=m -CONFIG_RTC_DRV_STK17TA8=m -# CONFIG_RTC_DRV_M48T86 is not set -CONFIG_RTC_DRV_M48T35=m -CONFIG_RTC_DRV_M48T59=m -CONFIG_RTC_DRV_MSM6242=m -CONFIG_RTC_DRV_BQ4802=m -CONFIG_RTC_DRV_RP5C01=m -CONFIG_RTC_DRV_V3020=m -# CONFIG_RTC_DRV_CROS_EC is not set - -# -# on-CPU RTC drivers -# -# CONFIG_RTC_DRV_FTRTC010 is not set -# CONFIG_RTC_DRV_MT6397 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_DMA_ENGINE=y -CONFIG_DMA_VIRTUAL_CHANNELS=y -CONFIG_DMA_ACPI=y -# CONFIG_ALTERA_MSGDMA is not set -CONFIG_INTEL_IDMA64=m -CONFIG_INTEL_IOATDMA=m -CONFIG_INTEL_MIC_X100_DMA=m -# CONFIG_QCOM_HIDMA_MGMT is not set -# CONFIG_QCOM_HIDMA is not set -CONFIG_DW_DMAC_CORE=y -# CONFIG_DW_DMAC is not set -# CONFIG_DW_DMAC_PCI is not set -CONFIG_HSU_DMA=y - -# -# DMA Clients -# -CONFIG_ASYNC_TX_DMA=y -# CONFIG_DMATEST is not set -CONFIG_DMA_ENGINE_RAID=y - -# -# DMABUF options -# -CONFIG_SYNC_FILE=y -# CONFIG_SW_SYNC is not set -CONFIG_DCA=m -CONFIG_AUXDISPLAY=y -# CONFIG_HD44780 is not set -CONFIG_KS0108=m -CONFIG_KS0108_PORT=0x378 -CONFIG_KS0108_DELAY=2 -CONFIG_CFAG12864B=m -CONFIG_CFAG12864B_RATE=20 -# CONFIG_IMG_ASCII_LCD is not set -# CONFIG_PANEL is not set -CONFIG_UIO=m -CONFIG_UIO_CIF=m -# CONFIG_UIO_PDRV_GENIRQ is not set -CONFIG_UIO_DMEM_GENIRQ=m -CONFIG_UIO_AEC=m -CONFIG_UIO_SERCOS3=m -CONFIG_UIO_PCI_GENERIC=m -# CONFIG_UIO_NETX is not set -# CONFIG_UIO_PRUSS is not set -# CONFIG_UIO_MF624 is not set -# CONFIG_UIO_HV_GENERIC is not set -CONFIG_VFIO_IOMMU_TYPE1=y -CONFIG_VFIO_VIRQFD=y -CONFIG_VFIO=y -# CONFIG_VFIO_NOIOMMU is not set -CONFIG_VFIO_PCI=y -CONFIG_VFIO_PCI_VGA=y -CONFIG_VFIO_PCI_MMAP=y -CONFIG_VFIO_PCI_INTX=y -CONFIG_VFIO_PCI_IGD=y -# CONFIG_VFIO_MDEV is not set -CONFIG_IRQ_BYPASS_MANAGER=y -# CONFIG_VIRT_DRIVERS is not set -CONFIG_VIRTIO=y -CONFIG_VIRTIO_MENU=y -CONFIG_VIRTIO_PCI=y -CONFIG_VIRTIO_PCI_LEGACY=y -CONFIG_VIRTIO_BALLOON=m -CONFIG_VIRTIO_INPUT=m -CONFIG_VIRTIO_MMIO=m -# CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES is not set - -# -# Microsoft Hyper-V guest support -# -CONFIG_HYPERV=m -CONFIG_HYPERV_TSCPAGE=y -CONFIG_HYPERV_UTILS=m -CONFIG_HYPERV_BALLOON=m - -# -# Xen driver support -# -CONFIG_XEN_BALLOON=y -CONFIG_XEN_SELFBALLOONING=y -# CONFIG_XEN_BALLOON_MEMORY_HOTPLUG is not set -CONFIG_XEN_SCRUB_PAGES_DEFAULT=y -CONFIG_XEN_DEV_EVTCHN=m -CONFIG_XEN_BACKEND=y -CONFIG_XENFS=m -CONFIG_XEN_COMPAT_XENFS=y -CONFIG_XEN_SYS_HYPERVISOR=y -CONFIG_XEN_XENBUS_FRONTEND=y -CONFIG_XEN_GNTDEV=m -CONFIG_XEN_GRANT_DEV_ALLOC=m -# CONFIG_XEN_GRANT_DMA_ALLOC is not set -CONFIG_SWIOTLB_XEN=y -CONFIG_XEN_TMEM=m -CONFIG_XEN_PCIDEV_BACKEND=m -# CONFIG_XEN_PVCALLS_FRONTEND is not set -# CONFIG_XEN_PVCALLS_BACKEND is not set -# CONFIG_XEN_SCSI_BACKEND is not set -CONFIG_XEN_PRIVCMD=m -CONFIG_XEN_ACPI_PROCESSOR=m -CONFIG_XEN_MCE_LOG=y -CONFIG_XEN_HAVE_PVMMU=y -CONFIG_XEN_EFI=y -CONFIG_XEN_AUTO_XLATE=y -CONFIG_XEN_ACPI=y -CONFIG_XEN_SYMS=y -CONFIG_XEN_HAVE_VPMU=y -CONFIG_STAGING=y -# CONFIG_PRISM2_USB is not set -# CONFIG_COMEDI is not set -# CONFIG_RTL8192U is not set -# CONFIG_RTLLIB is not set -# CONFIG_RTL8723BS is not set -CONFIG_R8712U=m -CONFIG_R8188EU=m -CONFIG_88EU_AP_MODE=y -# CONFIG_R8822BE is not set -CONFIG_RTS5208=m -# CONFIG_VT6655 is not set -# CONFIG_VT6656 is not set -CONFIG_FB_SM750=m -# CONFIG_FB_XGI is not set - -# -# Speakup console speech -# -# CONFIG_SPEAKUP is not set -CONFIG_STAGING_MEDIA=y -CONFIG_I2C_BCM2048=m -CONFIG_VIDEO_ZORAN=m -CONFIG_VIDEO_ZORAN_DC30=m -CONFIG_VIDEO_ZORAN_ZR36060=m -CONFIG_VIDEO_ZORAN_BUZ=m -CONFIG_VIDEO_ZORAN_DC10=m -CONFIG_VIDEO_ZORAN_LML33=m -CONFIG_VIDEO_ZORAN_LML33R10=m -CONFIG_VIDEO_ZORAN_AVS6EYES=m - -# -# Android -# -# CONFIG_ASHMEM is not set -# CONFIG_ANDROID_VSOC is not set -# CONFIG_ION is not set -CONFIG_LTE_GDM724X=m -CONFIG_FIREWIRE_SERIAL=m -CONFIG_FWTTY_MAX_TOTAL_PORTS=64 -CONFIG_FWTTY_MAX_CARD_PORTS=32 -CONFIG_DGNC=m -# CONFIG_GS_FPGABOOT is not set -CONFIG_UNISYSSPAR=y -# CONFIG_WILC1000_SDIO is not set -CONFIG_MOST=m -# CONFIG_MOST_CDEV is not set -# CONFIG_MOST_NET is not set -# CONFIG_MOST_SOUND is not set -# CONFIG_MOST_VIDEO is not set -# CONFIG_MOST_I2C is not set -# CONFIG_MOST_USB is not set -CONFIG_KS7010=m -CONFIG_GREYBUS=m -CONFIG_GREYBUS_ES2=m -CONFIG_GREYBUS_AUDIO=m -CONFIG_GREYBUS_BOOTROM=m -CONFIG_GREYBUS_HID=m -CONFIG_GREYBUS_LIGHT=m -CONFIG_GREYBUS_LOG=m -CONFIG_GREYBUS_LOOPBACK=m -CONFIG_GREYBUS_POWER=m -CONFIG_GREYBUS_RAW=m -CONFIG_GREYBUS_VIBRATOR=m -CONFIG_GREYBUS_BRIDGED_PHY=m -CONFIG_GREYBUS_GPIO=m -CONFIG_GREYBUS_I2C=m -CONFIG_GREYBUS_PWM=m -CONFIG_GREYBUS_SDIO=m -CONFIG_GREYBUS_UART=m -CONFIG_GREYBUS_USB=m -# CONFIG_DRM_VBOXVIDEO is not set -# CONFIG_MTK_MMC is not set - -# -# Gasket devices -# -# CONFIG_STAGING_GASKET_FRAMEWORK is not set -# CONFIG_EROFS_FS is not set -CONFIG_X86_PLATFORM_DEVICES=y -CONFIG_ACER_WMI=m -# CONFIG_ACER_WIRELESS is not set -CONFIG_ACERHDF=m -CONFIG_ALIENWARE_WMI=m -CONFIG_ASUS_LAPTOP=m -# CONFIG_DELL_SMBIOS is not set -CONFIG_DELL_WMI_AIO=m -# CONFIG_DELL_WMI_LED is not set -CONFIG_DELL_SMO8800=m -# CONFIG_DELL_RBTN is not set -CONFIG_FUJITSU_LAPTOP=m -CONFIG_FUJITSU_TABLET=m -CONFIG_AMILO_RFKILL=m -# CONFIG_GPD_POCKET_FAN is not set -CONFIG_HP_ACCEL=m -CONFIG_HP_WIRELESS=m -CONFIG_HP_WMI=m -CONFIG_MSI_LAPTOP=m -CONFIG_PANASONIC_LAPTOP=m -CONFIG_COMPAL_LAPTOP=m -CONFIG_SONY_LAPTOP=m -CONFIG_SONYPI_COMPAT=y -CONFIG_IDEAPAD_LAPTOP=m -CONFIG_THINKPAD_ACPI=m -CONFIG_THINKPAD_ACPI_ALSA_SUPPORT=y -# CONFIG_THINKPAD_ACPI_DEBUGFACILITIES is not set -# CONFIG_THINKPAD_ACPI_DEBUG is not set -# CONFIG_THINKPAD_ACPI_UNSAFE_LEDS is not set -CONFIG_THINKPAD_ACPI_VIDEO=y -CONFIG_THINKPAD_ACPI_HOTKEY_POLL=y -CONFIG_SENSORS_HDAPS=m -CONFIG_INTEL_MENLOW=m -CONFIG_EEEPC_LAPTOP=m -CONFIG_ASUS_WMI=m -CONFIG_ASUS_NB_WMI=m -CONFIG_EEEPC_WMI=m -# CONFIG_ASUS_WIRELESS is not set -CONFIG_ACPI_WMI=m -CONFIG_WMI_BMOF=m -# CONFIG_INTEL_WMI_THUNDERBOLT is not set -CONFIG_MSI_WMI=m -# CONFIG_PEAQ_WMI is not set -CONFIG_TOPSTAR_LAPTOP=m -CONFIG_TOSHIBA_BT_RFKILL=m -CONFIG_TOSHIBA_HAPS=m -CONFIG_TOSHIBA_WMI=m -CONFIG_ACPI_CMPC=m -# CONFIG_INTEL_INT0002_VGPIO is not set -# CONFIG_INTEL_HID_EVENT is not set -CONFIG_INTEL_VBTN=m -CONFIG_INTEL_IPS=m -# CONFIG_INTEL_PMC_CORE is not set -# CONFIG_IBM_RTL is not set -CONFIG_SAMSUNG_LAPTOP=m -CONFIG_MXM_WMI=m -CONFIG_INTEL_OAKTRAIL=m -CONFIG_SAMSUNG_Q10=m -CONFIG_APPLE_GMUX=m -CONFIG_INTEL_RST=m -# CONFIG_INTEL_SMARTCONNECT is not set -CONFIG_PVPANIC=m -# CONFIG_INTEL_PMC_IPC is not set -CONFIG_SURFACE_PRO3_BUTTON=m -# CONFIG_SURFACE_3_BUTTON is not set -# CONFIG_INTEL_PUNIT_IPC is not set -# CONFIG_MLX_PLATFORM is not set -# CONFIG_INTEL_TURBO_MAX_3 is not set -# CONFIG_I2C_MULTI_INSTANTIATE is not set -# CONFIG_INTEL_ATOMISP2_PM is not set -CONFIG_PMC_ATOM=y -CONFIG_CHROME_PLATFORMS=y -CONFIG_CHROMEOS_LAPTOP=m -CONFIG_CHROMEOS_PSTORE=m -# CONFIG_CHROMEOS_TBMC is not set -# CONFIG_CROS_EC_I2C is not set -CONFIG_CROS_EC_LPC=m -# CONFIG_CROS_EC_LPC_MEC is not set -CONFIG_CROS_EC_PROTO=y -# CONFIG_CROS_KBD_LED_BACKLIGHT is not set -# CONFIG_MELLANOX_PLATFORM is not set -CONFIG_CLKDEV_LOOKUP=y -CONFIG_HAVE_CLK_PREPARE=y -CONFIG_COMMON_CLK=y - -# -# Common Clock Framework -# -# CONFIG_COMMON_CLK_MAX9485 is not set -CONFIG_COMMON_CLK_SI5351=m -# CONFIG_COMMON_CLK_SI544 is not set -CONFIG_COMMON_CLK_CDCE706=m -# CONFIG_COMMON_CLK_CS2000_CP is not set -CONFIG_COMMON_CLK_PWM=m -# CONFIG_HWSPINLOCK is not set - -# -# Clock Source drivers -# -CONFIG_CLKEVT_I8253=y -CONFIG_I8253_LOCK=y -CONFIG_CLKBLD_I8253=y -CONFIG_MAILBOX=y -CONFIG_PCC=y -CONFIG_ALTERA_MBOX=m -CONFIG_IOMMU_API=y -CONFIG_IOMMU_SUPPORT=y - -# -# Generic IOMMU Pagetable Support -# -# CONFIG_IOMMU_DEBUGFS is not set -# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set -CONFIG_IOMMU_IOVA=y -CONFIG_AMD_IOMMU=y -CONFIG_AMD_IOMMU_V2=m -CONFIG_DMAR_TABLE=y -CONFIG_INTEL_IOMMU=y -# CONFIG_INTEL_IOMMU_SVM is not set -# CONFIG_INTEL_IOMMU_DEFAULT_ON is not set -CONFIG_INTEL_IOMMU_FLOPPY_WA=y -CONFIG_IRQ_REMAP=y - -# -# Remoteproc drivers -# -CONFIG_REMOTEPROC=m - -# -# Rpmsg drivers -# -# CONFIG_RPMSG_QCOM_GLINK_RPM is not set -# CONFIG_RPMSG_VIRTIO is not set -# CONFIG_SOUNDWIRE is not set - -# -# SOC (System On Chip) specific Drivers -# - -# -# Amlogic SoC drivers -# - -# -# Broadcom SoC drivers -# - -# -# NXP/Freescale QorIQ SoC drivers -# - -# -# i.MX SoC drivers -# - -# -# Qualcomm SoC drivers -# -# CONFIG_SOC_TI is not set - -# -# Xilinx SoC drivers -# -# CONFIG_XILINX_VCU is not set -CONFIG_PM_DEVFREQ=y - -# -# DEVFREQ Governors -# -CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=m -# CONFIG_DEVFREQ_GOV_PERFORMANCE is not set -# CONFIG_DEVFREQ_GOV_POWERSAVE is not set -# CONFIG_DEVFREQ_GOV_USERSPACE is not set -# CONFIG_DEVFREQ_GOV_PASSIVE is not set - -# -# DEVFREQ Drivers -# -CONFIG_PM_DEVFREQ_EVENT=y -CONFIG_EXTCON=y - -# -# Extcon Device Drivers -# -# CONFIG_EXTCON_GPIO is not set -# CONFIG_EXTCON_INTEL_INT3496 is not set -# CONFIG_EXTCON_MAX14577 is not set -# CONFIG_EXTCON_MAX3355 is not set -# CONFIG_EXTCON_RT8973A is not set -# CONFIG_EXTCON_SM5502 is not set -# CONFIG_EXTCON_USB_GPIO is not set -# CONFIG_EXTCON_USBC_CROS_EC is not set -# CONFIG_MEMORY is not set -# CONFIG_IIO is not set -CONFIG_NTB=m -# CONFIG_NTB_AMD is not set -# CONFIG_NTB_IDT is not set -# CONFIG_NTB_INTEL is not set -# CONFIG_NTB_SWITCHTEC is not set -# CONFIG_NTB_PINGPONG is not set -# CONFIG_NTB_TOOL is not set -# CONFIG_NTB_PERF is not set -# CONFIG_NTB_TRANSPORT is not set -# CONFIG_VME_BUS is not set -CONFIG_PWM=y -CONFIG_PWM_SYSFS=y -CONFIG_PWM_CROS_EC=m -CONFIG_PWM_LP3943=m -# CONFIG_PWM_LPSS_PCI is not set -# CONFIG_PWM_LPSS_PLATFORM is not set -CONFIG_PWM_PCA9685=m - -# -# IRQ chip support -# -CONFIG_ARM_GIC_MAX_NR=1 -# CONFIG_IPACK_BUS is not set -CONFIG_RESET_CONTROLLER=y -# CONFIG_RESET_TI_SYSCON is not set -# CONFIG_FMC is not set - -# -# PHY Subsystem -# -CONFIG_GENERIC_PHY=y -CONFIG_BCM_KONA_USB2_PHY=m -# CONFIG_PHY_PXA_28NM_HSIC is not set -# CONFIG_PHY_PXA_28NM_USB2 is not set -CONFIG_PHY_SAMSUNG_USB2=m -CONFIG_POWERCAP=y -CONFIG_INTEL_RAPL=m -# CONFIG_IDLE_INJECT is not set -# CONFIG_MCB is not set - -# -# Performance monitor support -# -CONFIG_RAS=y -# CONFIG_RAS_CEC is not set -CONFIG_THUNDERBOLT=m - -# -# Android -# -CONFIG_ANDROID=y -CONFIG_ANDROID_BINDER_IPC=y -CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder" -# CONFIG_ANDROID_BINDER_IPC_SELFTEST is not set -# CONFIG_LIBNVDIMM is not set -CONFIG_DAX=y -# CONFIG_DEV_DAX is not set -CONFIG_NVMEM=y - -# -# HW tracing support -# -CONFIG_STM=m -CONFIG_STM_DUMMY=m -CONFIG_STM_SOURCE_CONSOLE=m -# CONFIG_STM_SOURCE_HEARTBEAT is not set -# CONFIG_STM_SOURCE_FTRACE is not set -CONFIG_INTEL_TH=m -CONFIG_INTEL_TH_PCI=m -# CONFIG_INTEL_TH_ACPI is not set -CONFIG_INTEL_TH_GTH=m -CONFIG_INTEL_TH_STH=m -CONFIG_INTEL_TH_MSU=m -CONFIG_INTEL_TH_PTI=m -# CONFIG_INTEL_TH_DEBUG is not set -CONFIG_FPGA=m -# CONFIG_ALTERA_PR_IP_CORE is not set -# CONFIG_FPGA_MGR_ALTERA_CVP is not set -# CONFIG_FPGA_BRIDGE is not set -# CONFIG_FPGA_DFL is not set -CONFIG_PM_OPP=y -# CONFIG_UNISYS_VISORBUS is not set -# CONFIG_SIOX is not set -# CONFIG_SLIMBUS is not set - -# -# File systems -# -CONFIG_DCACHE_WORD_ACCESS=y -CONFIG_FS_IOMAP=y -CONFIG_EXT2_FS=m -CONFIG_EXT2_FS_XATTR=y -# CONFIG_EXT2_FS_POSIX_ACL is not set -CONFIG_EXT2_FS_SECURITY=y -CONFIG_EXT3_FS=m -CONFIG_EXT3_FS_POSIX_ACL=y -CONFIG_EXT3_FS_SECURITY=y -CONFIG_EXT4_FS=y -CONFIG_EXT4_FS_POSIX_ACL=y -CONFIG_EXT4_FS_SECURITY=y -CONFIG_EXT4_ENCRYPTION=y -CONFIG_EXT4_FS_ENCRYPTION=y -# CONFIG_EXT4_DEBUG is not set -CONFIG_JBD2=y -# CONFIG_JBD2_DEBUG is not set -CONFIG_FS_MBCACHE=y -CONFIG_REISERFS_FS=m -# CONFIG_REISERFS_CHECK is not set -CONFIG_REISERFS_PROC_INFO=y -CONFIG_REISERFS_FS_XATTR=y -CONFIG_REISERFS_FS_POSIX_ACL=y -CONFIG_REISERFS_FS_SECURITY=y -CONFIG_JFS_FS=m -CONFIG_JFS_POSIX_ACL=y -CONFIG_JFS_SECURITY=y -# CONFIG_JFS_DEBUG is not set -# CONFIG_JFS_STATISTICS is not set -CONFIG_XFS_FS=m -CONFIG_XFS_QUOTA=y -CONFIG_XFS_POSIX_ACL=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_ONLINE_SCRUB is not set -# CONFIG_XFS_WARN is not set -# CONFIG_XFS_DEBUG is not set -CONFIG_GFS2_FS=m -CONFIG_GFS2_FS_LOCKING_DLM=y -CONFIG_OCFS2_FS=m -CONFIG_OCFS2_FS_O2CB=m -CONFIG_OCFS2_FS_USERSPACE_CLUSTER=m -# CONFIG_OCFS2_FS_STATS is not set -# CONFIG_OCFS2_DEBUG_MASKLOG is not set -# CONFIG_OCFS2_DEBUG_FS is not set -CONFIG_BTRFS_FS=m -CONFIG_BTRFS_FS_POSIX_ACL=y -# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set -# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set -# CONFIG_BTRFS_DEBUG is not set -# CONFIG_BTRFS_ASSERT is not set -# CONFIG_BTRFS_FS_REF_VERIFY is not set -CONFIG_NILFS2_FS=m -CONFIG_F2FS_FS=m -CONFIG_F2FS_STAT_FS=y -CONFIG_F2FS_FS_XATTR=y -CONFIG_F2FS_FS_POSIX_ACL=y -# CONFIG_F2FS_FS_SECURITY is not set -# CONFIG_F2FS_CHECK_FS is not set -# CONFIG_F2FS_FS_ENCRYPTION is not set -CONFIG_F2FS_IO_TRACE=y -# CONFIG_F2FS_FAULT_INJECTION is not set -CONFIG_FS_DAX=y -CONFIG_FS_DAX_PMD=y -CONFIG_FS_POSIX_ACL=y -CONFIG_EXPORTFS=y -# CONFIG_EXPORTFS_BLOCK_OPS is not set -CONFIG_FILE_LOCKING=y -CONFIG_MANDATORY_FILE_LOCKING=y -CONFIG_FS_ENCRYPTION=y -CONFIG_FSNOTIFY=y -CONFIG_DNOTIFY=y -CONFIG_INOTIFY_USER=y -CONFIG_FANOTIFY=y -CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y -CONFIG_QUOTA=y -CONFIG_QUOTA_NETLINK_INTERFACE=y -# CONFIG_PRINT_QUOTA_WARNING is not set -# CONFIG_QUOTA_DEBUG is not set -CONFIG_QUOTA_TREE=y -# CONFIG_QFMT_V1 is not set -CONFIG_QFMT_V2=y -CONFIG_QUOTACTL=y -CONFIG_QUOTACTL_COMPAT=y -CONFIG_AUTOFS4_FS=y -CONFIG_AUTOFS_FS=y -CONFIG_FUSE_FS=m -CONFIG_CUSE=m -CONFIG_OVERLAY_FS=y -# CONFIG_OVERLAY_FS_REDIRECT_DIR is not set -CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y -# CONFIG_OVERLAY_FS_INDEX is not set -# CONFIG_OVERLAY_FS_XINO_AUTO is not set -# CONFIG_OVERLAY_FS_METACOPY is not set - -# -# Caches -# -CONFIG_FSCACHE=m -CONFIG_FSCACHE_STATS=y -# CONFIG_FSCACHE_HISTOGRAM is not set -# CONFIG_FSCACHE_DEBUG is not set -CONFIG_FSCACHE_OBJECT_LIST=y -CONFIG_CACHEFILES=m -# CONFIG_CACHEFILES_DEBUG is not set -# CONFIG_CACHEFILES_HISTOGRAM is not set - -# -# CD-ROM/DVD Filesystems -# -CONFIG_ISO9660_FS=y -CONFIG_JOLIET=y -CONFIG_ZISOFS=y -CONFIG_UDF_FS=m - -# -# DOS/FAT/NT Filesystems -# -CONFIG_FAT_FS=m -CONFIG_MSDOS_FS=m -CONFIG_VFAT_FS=m -CONFIG_FAT_DEFAULT_CODEPAGE=437 -CONFIG_FAT_DEFAULT_IOCHARSET="ascii" -# CONFIG_FAT_DEFAULT_UTF8 is not set -# CONFIG_NTFS_FS is not set - -# -# Pseudo filesystems -# -CONFIG_PROC_FS=y -CONFIG_PROC_KCORE=y -CONFIG_PROC_VMCORE=y -# CONFIG_PROC_VMCORE_DEVICE_DUMP is not set -CONFIG_PROC_SYSCTL=y -CONFIG_PROC_PAGE_MONITOR=y -# CONFIG_PROC_CHILDREN is not set -CONFIG_KERNFS=y -CONFIG_SYSFS=y -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_TMPFS_XATTR=y -CONFIG_HUGETLBFS=y -CONFIG_HUGETLB_PAGE=y -CONFIG_MEMFD_CREATE=y -CONFIG_ARCH_HAS_GIGANTIC_PAGE=y -CONFIG_CONFIGFS_FS=y -CONFIG_EFIVAR_FS=y -CONFIG_MISC_FILESYSTEMS=y -# CONFIG_ORANGEFS_FS is not set -# CONFIG_ADFS_FS is not set -CONFIG_AFFS_FS=m -CONFIG_ECRYPT_FS=m -CONFIG_ECRYPT_FS_MESSAGING=y -CONFIG_HFS_FS=m -CONFIG_HFSPLUS_FS=m -CONFIG_BEFS_FS=m -# CONFIG_BEFS_DEBUG is not set -# CONFIG_BFS_FS is not set -# CONFIG_EFS_FS is not set -# CONFIG_JFFS2_FS is not set -CONFIG_UBIFS_FS=m -# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set -CONFIG_UBIFS_FS_LZO=y -CONFIG_UBIFS_FS_ZLIB=y -# CONFIG_UBIFS_ATIME_SUPPORT is not set -CONFIG_UBIFS_FS_XATTR=y -# CONFIG_UBIFS_FS_ENCRYPTION is not set -CONFIG_UBIFS_FS_SECURITY=y -CONFIG_CRAMFS=m -CONFIG_CRAMFS_BLOCKDEV=y -# CONFIG_CRAMFS_MTD is not set -CONFIG_SQUASHFS=m -# CONFIG_SQUASHFS_FILE_CACHE is not set -CONFIG_SQUASHFS_FILE_DIRECT=y -# CONFIG_SQUASHFS_DECOMP_SINGLE is not set -# CONFIG_SQUASHFS_DECOMP_MULTI is not set -CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y -CONFIG_SQUASHFS_XATTR=y -CONFIG_SQUASHFS_ZLIB=y -# CONFIG_SQUASHFS_LZ4 is not set -CONFIG_SQUASHFS_LZO=y -CONFIG_SQUASHFS_XZ=y -# CONFIG_SQUASHFS_ZSTD is not set -# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set -# CONFIG_SQUASHFS_EMBEDDED is not set -CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 -# CONFIG_VXFS_FS is not set -CONFIG_MINIX_FS=m -# 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=m -CONFIG_ROMFS_BACKED_BY_BLOCK=y -# CONFIG_ROMFS_BACKED_BY_MTD is not set -# CONFIG_ROMFS_BACKED_BY_BOTH is not set -CONFIG_ROMFS_ON_BLOCK=y -CONFIG_PSTORE=y -CONFIG_PSTORE_DEFLATE_COMPRESS=y -# CONFIG_PSTORE_LZO_COMPRESS is not set -# CONFIG_PSTORE_LZ4_COMPRESS is not set -# CONFIG_PSTORE_LZ4HC_COMPRESS is not set -# CONFIG_PSTORE_842_COMPRESS is not set -# CONFIG_PSTORE_ZSTD_COMPRESS is not set -CONFIG_PSTORE_COMPRESS=y -CONFIG_PSTORE_DEFLATE_COMPRESS_DEFAULT=y -CONFIG_PSTORE_COMPRESS_DEFAULT="deflate" -CONFIG_PSTORE_CONSOLE=y -CONFIG_PSTORE_PMSG=y -CONFIG_PSTORE_FTRACE=y -CONFIG_PSTORE_RAM=m -CONFIG_SYSV_FS=m -CONFIG_UFS_FS=m -# CONFIG_UFS_FS_WRITE is not set -# CONFIG_UFS_DEBUG is not set -# CONFIG_EXOFS_FS is not set -CONFIG_AUFS_FS=y -# CONFIG_AUFS_BRANCH_MAX_127 is not set -# CONFIG_AUFS_BRANCH_MAX_511 is not set -# CONFIG_AUFS_BRANCH_MAX_1023 is not set -CONFIG_AUFS_BRANCH_MAX_32767=y -CONFIG_AUFS_SBILIST=y -CONFIG_AUFS_HNOTIFY=y -CONFIG_AUFS_HFSNOTIFY=y -CONFIG_AUFS_EXPORT=y -CONFIG_AUFS_INO_T_64=y -CONFIG_AUFS_XATTR=y -CONFIG_AUFS_FHSM=y -CONFIG_AUFS_RDU=y -# CONFIG_AUFS_DIRREN is not set -CONFIG_AUFS_SHWH=y -CONFIG_AUFS_BR_RAMFS=y -CONFIG_AUFS_BR_FUSE=y -CONFIG_AUFS_POLL=y -CONFIG_AUFS_BR_HFSPLUS=y -CONFIG_AUFS_BDEV_LOOP=y -CONFIG_AUFS_DEBUG=y -CONFIG_AUFS_MAGIC_SYSRQ=y -CONFIG_NETWORK_FILESYSTEMS=y -CONFIG_NFS_FS=m -CONFIG_NFS_V2=m -CONFIG_NFS_V3=m -CONFIG_NFS_V3_ACL=y -CONFIG_NFS_V4=m -CONFIG_NFS_SWAP=y -CONFIG_NFS_V4_1=y -# CONFIG_NFS_V4_2 is not set -CONFIG_PNFS_FILE_LAYOUT=m -CONFIG_PNFS_BLOCK=m -CONFIG_PNFS_FLEXFILE_LAYOUT=m -CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN="kernel.org" -# CONFIG_NFS_V4_1_MIGRATION is not set -CONFIG_NFS_FSCACHE=y -# CONFIG_NFS_USE_LEGACY_DNS is not set -CONFIG_NFS_USE_KERNEL_DNS=y -CONFIG_NFS_DEBUG=y -CONFIG_NFSD=m -CONFIG_NFSD_V2_ACL=y -CONFIG_NFSD_V3=y -CONFIG_NFSD_V3_ACL=y -CONFIG_NFSD_V4=y -# CONFIG_NFSD_BLOCKLAYOUT is not set -# CONFIG_NFSD_SCSILAYOUT is not set -# CONFIG_NFSD_FLEXFILELAYOUT is not set -# CONFIG_NFSD_V4_SECURITY_LABEL is not set -CONFIG_GRACE_PERIOD=m -CONFIG_LOCKD=m -CONFIG_LOCKD_V4=y -CONFIG_NFS_ACL_SUPPORT=m -CONFIG_NFS_COMMON=y -CONFIG_SUNRPC=m -CONFIG_SUNRPC_GSS=m -CONFIG_SUNRPC_BACKCHANNEL=y -CONFIG_SUNRPC_SWAP=y -CONFIG_RPCSEC_GSS_KRB5=m -CONFIG_SUNRPC_DEBUG=y -CONFIG_SUNRPC_XPRT_RDMA=m -CONFIG_CEPH_FS=m -# CONFIG_CEPH_FSCACHE is not set -CONFIG_CEPH_FS_POSIX_ACL=y -CONFIG_CIFS=m -# CONFIG_CIFS_STATS2 is not set -CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y -CONFIG_CIFS_WEAK_PW_HASH=y -CONFIG_CIFS_UPCALL=y -CONFIG_CIFS_XATTR=y -# CONFIG_CIFS_POSIX is not set -CONFIG_CIFS_ACL=y -# CONFIG_CIFS_DEBUG is not set -CONFIG_CIFS_DFS_UPCALL=y -# CONFIG_CIFS_SMB_DIRECT is not set -CONFIG_CIFS_FSCACHE=y -CONFIG_CODA_FS=m -# CONFIG_AFS_FS is not set -CONFIG_9P_FS=m -CONFIG_9P_FSCACHE=y -CONFIG_9P_FS_POSIX_ACL=y -# CONFIG_9P_FS_SECURITY is not set -CONFIG_NLS=y -CONFIG_NLS_DEFAULT="utf8" -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_CODEPAGE_737=m -CONFIG_NLS_CODEPAGE_775=m -CONFIG_NLS_CODEPAGE_850=m -CONFIG_NLS_CODEPAGE_852=m -CONFIG_NLS_CODEPAGE_855=m -CONFIG_NLS_CODEPAGE_857=m -CONFIG_NLS_CODEPAGE_860=m -CONFIG_NLS_CODEPAGE_861=m -CONFIG_NLS_CODEPAGE_862=m -CONFIG_NLS_CODEPAGE_863=m -CONFIG_NLS_CODEPAGE_864=m -CONFIG_NLS_CODEPAGE_865=m -CONFIG_NLS_CODEPAGE_866=m -CONFIG_NLS_CODEPAGE_869=m -CONFIG_NLS_CODEPAGE_936=m -CONFIG_NLS_CODEPAGE_950=m -CONFIG_NLS_CODEPAGE_932=m -CONFIG_NLS_CODEPAGE_949=m -CONFIG_NLS_CODEPAGE_874=m -CONFIG_NLS_ISO8859_8=m -CONFIG_NLS_CODEPAGE_1250=m -CONFIG_NLS_CODEPAGE_1251=m -CONFIG_NLS_ASCII=y -CONFIG_NLS_ISO8859_1=m -CONFIG_NLS_ISO8859_2=m -CONFIG_NLS_ISO8859_3=m -CONFIG_NLS_ISO8859_4=m -CONFIG_NLS_ISO8859_5=m -CONFIG_NLS_ISO8859_6=m -CONFIG_NLS_ISO8859_7=m -CONFIG_NLS_ISO8859_9=m -CONFIG_NLS_ISO8859_13=m -CONFIG_NLS_ISO8859_14=m -CONFIG_NLS_ISO8859_15=m -CONFIG_NLS_KOI8_R=m -CONFIG_NLS_KOI8_U=m -CONFIG_NLS_MAC_ROMAN=m -CONFIG_NLS_MAC_CELTIC=m -CONFIG_NLS_MAC_CENTEURO=m -CONFIG_NLS_MAC_CROATIAN=m -CONFIG_NLS_MAC_CYRILLIC=m -CONFIG_NLS_MAC_GAELIC=m -CONFIG_NLS_MAC_GREEK=m -CONFIG_NLS_MAC_ICELAND=m -CONFIG_NLS_MAC_INUIT=m -CONFIG_NLS_MAC_ROMANIAN=m -CONFIG_NLS_MAC_TURKISH=m -CONFIG_NLS_UTF8=m -CONFIG_DLM=m -CONFIG_DLM_DEBUG=y - -# -# Security options -# -CONFIG_KEYS=y -CONFIG_KEYS_COMPAT=y -# CONFIG_PERSISTENT_KEYRINGS is not set -# CONFIG_BIG_KEYS is not set -CONFIG_TRUSTED_KEYS=m -CONFIG_ENCRYPTED_KEYS=y -# CONFIG_KEY_DH_OPERATIONS is not set -# CONFIG_SECURITY_DMESG_RESTRICT is not set -CONFIG_SECURITY=y -CONFIG_SECURITYFS=y -CONFIG_SECURITY_NETWORK=y -CONFIG_PAGE_TABLE_ISOLATION=y -# CONFIG_SECURITY_INFINIBAND is not set -CONFIG_SECURITY_NETWORK_XFRM=y -CONFIG_SECURITY_PATH=y -CONFIG_INTEL_TXT=y -CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y -# CONFIG_HARDENED_USERCOPY is not set -# CONFIG_FORTIFY_SOURCE is not set -# CONFIG_STATIC_USERMODEHELPER is not set -# CONFIG_SECURITY_SELINUX is not set -# CONFIG_SECURITY_SMACK is not set -# CONFIG_SECURITY_TOMOYO is not set -CONFIG_SECURITY_APPARMOR=y -CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1 -CONFIG_SECURITY_APPARMOR_HASH=y -CONFIG_SECURITY_APPARMOR_HASH_DEFAULT=y -# CONFIG_SECURITY_APPARMOR_DEBUG is not set -# CONFIG_SECURITY_LOADPIN is not set -# CONFIG_SECURITY_YAMA is not set -CONFIG_INTEGRITY=y -# CONFIG_INTEGRITY_SIGNATURE is not set -CONFIG_INTEGRITY_AUDIT=y -# CONFIG_IMA is not set -# CONFIG_EVM is not set -CONFIG_DEFAULT_SECURITY_APPARMOR=y -# CONFIG_DEFAULT_SECURITY_DAC is not set -CONFIG_DEFAULT_SECURITY="apparmor" -CONFIG_XOR_BLOCKS=m -CONFIG_ASYNC_CORE=m -CONFIG_ASYNC_MEMCPY=m -CONFIG_ASYNC_XOR=m -CONFIG_ASYNC_PQ=m -CONFIG_ASYNC_RAID6_RECOV=m -CONFIG_CRYPTO=y - -# -# Crypto core or helper -# -CONFIG_CRYPTO_ALGAPI=y -CONFIG_CRYPTO_ALGAPI2=y -CONFIG_CRYPTO_AEAD=y -CONFIG_CRYPTO_AEAD2=y -CONFIG_CRYPTO_BLKCIPHER=y -CONFIG_CRYPTO_BLKCIPHER2=y -CONFIG_CRYPTO_HASH=y -CONFIG_CRYPTO_HASH2=y -CONFIG_CRYPTO_RNG=y -CONFIG_CRYPTO_RNG2=y -CONFIG_CRYPTO_RNG_DEFAULT=y -CONFIG_CRYPTO_AKCIPHER2=y -CONFIG_CRYPTO_AKCIPHER=y -CONFIG_CRYPTO_KPP2=y -CONFIG_CRYPTO_KPP=m -CONFIG_CRYPTO_ACOMP2=y -CONFIG_CRYPTO_RSA=y -CONFIG_CRYPTO_DH=m -CONFIG_CRYPTO_ECDH=m -CONFIG_CRYPTO_MANAGER=y -CONFIG_CRYPTO_MANAGER2=y -CONFIG_CRYPTO_USER=m -# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set -CONFIG_CRYPTO_GF128MUL=y -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_NULL2=y -CONFIG_CRYPTO_PCRYPT=m -CONFIG_CRYPTO_WORKQUEUE=y -CONFIG_CRYPTO_CRYPTD=y -CONFIG_CRYPTO_MCRYPTD=m -CONFIG_CRYPTO_AUTHENC=m -CONFIG_CRYPTO_TEST=m -CONFIG_CRYPTO_SIMD=m -CONFIG_CRYPTO_GLUE_HELPER_X86=m -CONFIG_CRYPTO_ENGINE=m - -# -# Authenticated Encryption with Associated Data -# -CONFIG_CRYPTO_CCM=m -CONFIG_CRYPTO_GCM=m -# CONFIG_CRYPTO_CHACHA20POLY1305 is not set -# CONFIG_CRYPTO_AEGIS128 is not set -# CONFIG_CRYPTO_AEGIS128L is not set -# CONFIG_CRYPTO_AEGIS256 is not set -# CONFIG_CRYPTO_AEGIS128_AESNI_SSE2 is not set -# CONFIG_CRYPTO_AEGIS128L_AESNI_SSE2 is not set -# CONFIG_CRYPTO_AEGIS256_AESNI_SSE2 is not set -# CONFIG_CRYPTO_MORUS640 is not set -# CONFIG_CRYPTO_MORUS640_SSE2 is not set -# CONFIG_CRYPTO_MORUS1280 is not set -# CONFIG_CRYPTO_MORUS1280_SSE2 is not set -# CONFIG_CRYPTO_MORUS1280_AVX2 is not set -CONFIG_CRYPTO_SEQIV=y -CONFIG_CRYPTO_ECHAINIV=m - -# -# Block modes -# -CONFIG_CRYPTO_CBC=y -# CONFIG_CRYPTO_CFB is not set -CONFIG_CRYPTO_CTR=y -CONFIG_CRYPTO_CTS=y -CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_LRW=y -CONFIG_CRYPTO_PCBC=m -CONFIG_CRYPTO_XTS=y -CONFIG_CRYPTO_KEYWRAP=m - -# -# Hash modes -# -CONFIG_CRYPTO_CMAC=m -CONFIG_CRYPTO_HMAC=y -CONFIG_CRYPTO_XCBC=m -CONFIG_CRYPTO_VMAC=m - -# -# Digest -# -CONFIG_CRYPTO_CRC32C=y -CONFIG_CRYPTO_CRC32C_INTEL=m -CONFIG_CRYPTO_CRC32=y -CONFIG_CRYPTO_CRC32_PCLMUL=m -CONFIG_CRYPTO_CRCT10DIF=y -# CONFIG_CRYPTO_CRCT10DIF_PCLMUL is not set -CONFIG_CRYPTO_GHASH=m -CONFIG_CRYPTO_POLY1305=m -CONFIG_CRYPTO_POLY1305_X86_64=m -CONFIG_CRYPTO_MD4=m -CONFIG_CRYPTO_MD5=y -CONFIG_CRYPTO_MICHAEL_MIC=m -CONFIG_CRYPTO_RMD128=m -CONFIG_CRYPTO_RMD160=m -CONFIG_CRYPTO_RMD256=m -CONFIG_CRYPTO_RMD320=m -CONFIG_CRYPTO_SHA1=y -CONFIG_CRYPTO_SHA1_SSSE3=m -CONFIG_CRYPTO_SHA256_SSSE3=m -CONFIG_CRYPTO_SHA512_SSSE3=m -# CONFIG_CRYPTO_SHA1_MB is not set -CONFIG_CRYPTO_SHA256_MB=m -CONFIG_CRYPTO_SHA512_MB=m -CONFIG_CRYPTO_SHA256=y -CONFIG_CRYPTO_SHA512=m -CONFIG_CRYPTO_SHA3=m -# CONFIG_CRYPTO_SM3 is not set -CONFIG_CRYPTO_TGR192=m -CONFIG_CRYPTO_WP512=m -CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL=m - -# -# Ciphers -# -CONFIG_CRYPTO_AES=y -# CONFIG_CRYPTO_AES_TI is not set -CONFIG_CRYPTO_AES_X86_64=m -CONFIG_CRYPTO_AES_NI_INTEL=m -CONFIG_CRYPTO_ANUBIS=m -CONFIG_CRYPTO_ARC4=m -CONFIG_CRYPTO_BLOWFISH=m -CONFIG_CRYPTO_BLOWFISH_COMMON=m -CONFIG_CRYPTO_BLOWFISH_X86_64=m -CONFIG_CRYPTO_CAMELLIA=m -CONFIG_CRYPTO_CAMELLIA_X86_64=m -CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64=m -CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64=m -CONFIG_CRYPTO_CAST_COMMON=m -CONFIG_CRYPTO_CAST5=m -CONFIG_CRYPTO_CAST5_AVX_X86_64=m -CONFIG_CRYPTO_CAST6=m -CONFIG_CRYPTO_CAST6_AVX_X86_64=m -CONFIG_CRYPTO_DES=m -CONFIG_CRYPTO_DES3_EDE_X86_64=m -CONFIG_CRYPTO_FCRYPT=m -CONFIG_CRYPTO_KHAZAD=m -CONFIG_CRYPTO_SALSA20=m -CONFIG_CRYPTO_CHACHA20=m -CONFIG_CRYPTO_CHACHA20_X86_64=m -CONFIG_CRYPTO_SEED=m -CONFIG_CRYPTO_SERPENT=m -CONFIG_CRYPTO_SERPENT_SSE2_X86_64=m -CONFIG_CRYPTO_SERPENT_AVX_X86_64=m -CONFIG_CRYPTO_SERPENT_AVX2_X86_64=m -# CONFIG_CRYPTO_SM4 is not set -CONFIG_CRYPTO_TEA=m -CONFIG_CRYPTO_TWOFISH=m -CONFIG_CRYPTO_TWOFISH_COMMON=m -CONFIG_CRYPTO_TWOFISH_X86_64=m -CONFIG_CRYPTO_TWOFISH_X86_64_3WAY=m -CONFIG_CRYPTO_TWOFISH_AVX_X86_64=m - -# -# Compression -# -CONFIG_CRYPTO_DEFLATE=y -CONFIG_CRYPTO_LZO=y -# CONFIG_CRYPTO_842 is not set -CONFIG_CRYPTO_LZ4=m -CONFIG_CRYPTO_LZ4HC=m -# CONFIG_CRYPTO_ZSTD is not set - -# -# Random Number Generation -# -CONFIG_CRYPTO_ANSI_CPRNG=m -CONFIG_CRYPTO_DRBG_MENU=y -CONFIG_CRYPTO_DRBG_HMAC=y -# CONFIG_CRYPTO_DRBG_HASH is not set -# CONFIG_CRYPTO_DRBG_CTR is not set -CONFIG_CRYPTO_DRBG=y -CONFIG_CRYPTO_JITTERENTROPY=y -CONFIG_CRYPTO_USER_API=y -CONFIG_CRYPTO_USER_API_HASH=y -CONFIG_CRYPTO_USER_API_SKCIPHER=y -CONFIG_CRYPTO_USER_API_RNG=m -# CONFIG_CRYPTO_USER_API_AEAD is not set -CONFIG_CRYPTO_HASH_INFO=y -CONFIG_CRYPTO_HW=y -CONFIG_CRYPTO_DEV_PADLOCK=m -CONFIG_CRYPTO_DEV_PADLOCK_AES=m -CONFIG_CRYPTO_DEV_PADLOCK_SHA=m -CONFIG_CRYPTO_DEV_CCP=y -CONFIG_CRYPTO_DEV_CCP_DD=m -CONFIG_CRYPTO_DEV_SP_CCP=y -CONFIG_CRYPTO_DEV_CCP_CRYPTO=m -CONFIG_CRYPTO_DEV_SP_PSP=y -CONFIG_CRYPTO_DEV_QAT=m -CONFIG_CRYPTO_DEV_QAT_DH895xCC=m -# CONFIG_CRYPTO_DEV_QAT_C3XXX is not set -# CONFIG_CRYPTO_DEV_QAT_C62X is not set -CONFIG_CRYPTO_DEV_QAT_DH895xCCVF=m -# CONFIG_CRYPTO_DEV_QAT_C3XXXVF is not set -# CONFIG_CRYPTO_DEV_QAT_C62XVF is not set -# CONFIG_CRYPTO_DEV_NITROX_CNN55XX is not set -CONFIG_CRYPTO_DEV_CHELSIO=m -CONFIG_CRYPTO_DEV_VIRTIO=m -CONFIG_ASYMMETRIC_KEY_TYPE=y -CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y -CONFIG_X509_CERTIFICATE_PARSER=y -CONFIG_PKCS7_MESSAGE_PARSER=y -# CONFIG_PKCS7_TEST_KEY is not set -# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set - -# -# Certificates for signature checking -# -CONFIG_SYSTEM_TRUSTED_KEYRING=y -CONFIG_SYSTEM_TRUSTED_KEYS="" -# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set -# CONFIG_SECONDARY_TRUSTED_KEYRING is not set -# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set -CONFIG_BINARY_PRINTF=y - -# -# Library routines -# -CONFIG_RAID6_PQ=m -CONFIG_BITREVERSE=y -CONFIG_RATIONAL=y -CONFIG_GENERIC_STRNCPY_FROM_USER=y -CONFIG_GENERIC_STRNLEN_USER=y -CONFIG_GENERIC_NET_UTILS=y -CONFIG_GENERIC_FIND_FIRST_BIT=y -CONFIG_GENERIC_PCI_IOMAP=y -CONFIG_GENERIC_IOMAP=y -CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y -CONFIG_ARCH_HAS_FAST_MULTIPLIER=y -CONFIG_CRC_CCITT=y -CONFIG_CRC16=y -CONFIG_CRC_T10DIF=y -CONFIG_CRC_ITU_T=m -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_CRC64=m -# CONFIG_CRC4 is not set -# CONFIG_CRC7 is not set -CONFIG_LIBCRC32C=m -CONFIG_CRC8=m -CONFIG_XXHASH=m -# CONFIG_RANDOM32_SELFTEST is not set -CONFIG_ZLIB_INFLATE=y -CONFIG_ZLIB_DEFLATE=y -CONFIG_LZO_COMPRESS=y -CONFIG_LZO_DECOMPRESS=y -CONFIG_LZ4_COMPRESS=m -CONFIG_LZ4HC_COMPRESS=m -CONFIG_LZ4_DECOMPRESS=y -CONFIG_ZSTD_COMPRESS=m -CONFIG_ZSTD_DECOMPRESS=m -CONFIG_XZ_DEC=y -CONFIG_XZ_DEC_X86=y -CONFIG_XZ_DEC_POWERPC=y -CONFIG_XZ_DEC_IA64=y -CONFIG_XZ_DEC_ARM=y -CONFIG_XZ_DEC_ARMTHUMB=y -CONFIG_XZ_DEC_SPARC=y -CONFIG_XZ_DEC_BCJ=y -# CONFIG_XZ_DEC_TEST is not set -CONFIG_DECOMPRESS_GZIP=y -CONFIG_DECOMPRESS_BZIP2=y -CONFIG_DECOMPRESS_LZMA=y -CONFIG_DECOMPRESS_XZ=y -CONFIG_DECOMPRESS_LZO=y -CONFIG_DECOMPRESS_LZ4=y -CONFIG_GENERIC_ALLOCATOR=y -CONFIG_REED_SOLOMON=m -CONFIG_REED_SOLOMON_ENC8=y -CONFIG_REED_SOLOMON_DEC8=y -CONFIG_TEXTSEARCH=y -CONFIG_TEXTSEARCH_KMP=m -CONFIG_TEXTSEARCH_BM=m -CONFIG_TEXTSEARCH_FSM=m -CONFIG_BTREE=y -CONFIG_INTERVAL_TREE=y -CONFIG_RADIX_TREE_MULTIORDER=y -CONFIG_ASSOCIATIVE_ARRAY=y -CONFIG_HAS_IOMEM=y -CONFIG_HAS_IOPORT_MAP=y -CONFIG_HAS_DMA=y -CONFIG_NEED_SG_DMA_LENGTH=y -CONFIG_NEED_DMA_MAP_STATE=y -CONFIG_ARCH_DMA_ADDR_T_64BIT=y -CONFIG_DMA_DIRECT_OPS=y -CONFIG_DMA_VIRT_OPS=y -CONFIG_SWIOTLB=y -CONFIG_SGL_ALLOC=y -CONFIG_IOMMU_HELPER=y -CONFIG_CHECK_SIGNATURE=y -CONFIG_CPU_RMAP=y -CONFIG_DQL=y -CONFIG_GLOB=y -# CONFIG_GLOB_SELFTEST is not set -CONFIG_NLATTR=y -CONFIG_LRU_CACHE=m -CONFIG_CLZ_TAB=y -CONFIG_CORDIC=m -# CONFIG_DDR is not set -CONFIG_IRQ_POLL=y -CONFIG_MPILIB=y -CONFIG_OID_REGISTRY=y -CONFIG_UCS2_STRING=y -CONFIG_FONT_SUPPORT=y -# CONFIG_FONTS is not set -CONFIG_FONT_8x8=y -CONFIG_FONT_8x16=y -CONFIG_SG_POOL=y -CONFIG_ARCH_HAS_SG_CHAIN=y -CONFIG_ARCH_HAS_PMEM_API=y -CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE=y -CONFIG_ARCH_HAS_UACCESS_MCSAFE=y -CONFIG_SBITMAP=y -CONFIG_PARMAN=m -# CONFIG_STRING_SELFTEST is not set - -# -# Kernel hacking -# - -# -# printk and dmesg options -# -CONFIG_PRINTK_TIME=y -CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7 -CONFIG_CONSOLE_LOGLEVEL_QUIET=4 -CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 -CONFIG_DYNAMIC_DEBUG=y - -# -# Compile-time checks and compiler options -# -CONFIG_ENABLE_MUST_CHECK=y -CONFIG_FRAME_WARN=2048 -CONFIG_STRIP_ASM_SYMS=y -CONFIG_UNUSED_SYMBOLS=y -CONFIG_DEBUG_FS=y -CONFIG_HEADERS_CHECK=y -CONFIG_DEBUG_SECTION_MISMATCH=y -CONFIG_SECTION_MISMATCH_WARN_ONLY=y -CONFIG_STACK_VALIDATION=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 -CONFIG_MAGIC_SYSRQ_SERIAL=y -# CONFIG_DEBUG_KERNEL is not set - -# -# Memory Debugging -# -# CONFIG_PAGE_EXTENSION is not set -# CONFIG_PAGE_POISONING is not set -CONFIG_DEBUG_RODATA_TEST=y -CONFIG_HAVE_DEBUG_KMEMLEAK=y -CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y -CONFIG_DEBUG_MEMORY_INIT=y -CONFIG_HAVE_DEBUG_STACKOVERFLOW=y -CONFIG_HAVE_ARCH_KASAN=y -# CONFIG_KASAN is not set -CONFIG_ARCH_HAS_KCOV=y -CONFIG_CC_HAS_SANCOV_TRACE_PC=y -# CONFIG_KCOV is not set - -# -# Debug Lockups and Hangs -# -CONFIG_HARDLOCKUP_CHECK_TIMESTAMP=y -# CONFIG_PANIC_ON_OOPS is not set -CONFIG_PANIC_ON_OOPS_VALUE=0 -CONFIG_PANIC_TIMEOUT=0 -CONFIG_SCHED_INFO=y -CONFIG_DEBUG_TIMEKEEPING=y - -# -# Lock Debugging (spinlocks, mutexes, etc...) -# -CONFIG_LOCK_DEBUGGING_SUPPORT=y -# CONFIG_WW_MUTEX_SELFTEST is not set -CONFIG_STACKTRACE=y -# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set -CONFIG_DEBUG_BUGVERBOSE=y - -# -# RCU Debugging -# -CONFIG_RCU_CPU_STALL_TIMEOUT=60 -CONFIG_FUNCTION_ERROR_INJECTION=y -CONFIG_USER_STACKTRACE_SUPPORT=y -CONFIG_NOP_TRACER=y -CONFIG_HAVE_FUNCTION_TRACER=y -CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y -CONFIG_HAVE_DYNAMIC_FTRACE=y -CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y -CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y -CONFIG_HAVE_SYSCALL_TRACEPOINTS=y -CONFIG_HAVE_FENTRY=y -CONFIG_HAVE_C_RECORDMCOUNT=y -CONFIG_TRACER_MAX_TRACE=y -CONFIG_TRACE_CLOCK=y -CONFIG_RING_BUFFER=y -CONFIG_EVENT_TRACING=y -CONFIG_CONTEXT_SWITCH_TRACER=y -CONFIG_RING_BUFFER_ALLOW_SWAP=y -CONFIG_TRACING=y -CONFIG_GENERIC_TRACER=y -CONFIG_TRACING_SUPPORT=y -CONFIG_FTRACE=y -CONFIG_FUNCTION_TRACER=y -CONFIG_FUNCTION_GRAPH_TRACER=y -# CONFIG_PREEMPTIRQ_EVENTS is not set -# CONFIG_IRQSOFF_TRACER is not set -CONFIG_SCHED_TRACER=y -# CONFIG_HWLAT_TRACER is not set -CONFIG_FTRACE_SYSCALLS=y -CONFIG_TRACER_SNAPSHOT=y -CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP=y -CONFIG_BRANCH_PROFILE_NONE=y -# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set -# CONFIG_PROFILE_ALL_BRANCHES is not set -CONFIG_STACK_TRACER=y -CONFIG_BLK_DEV_IO_TRACE=y -CONFIG_KPROBE_EVENTS=y -# CONFIG_KPROBE_EVENTS_ON_NOTRACE is not set -CONFIG_UPROBE_EVENTS=y -CONFIG_BPF_EVENTS=y -CONFIG_PROBE_EVENTS=y -CONFIG_DYNAMIC_FTRACE=y -CONFIG_DYNAMIC_FTRACE_WITH_REGS=y -CONFIG_FUNCTION_PROFILER=y -# CONFIG_BPF_KPROBE_OVERRIDE is not set -CONFIG_FTRACE_MCOUNT_RECORD=y -# CONFIG_FTRACE_STARTUP_TEST is not set -# CONFIG_MMIOTRACE is not set -# CONFIG_HIST_TRIGGERS is not set -# CONFIG_TRACEPOINT_BENCHMARK is not set -CONFIG_RING_BUFFER_BENCHMARK=m -# CONFIG_RING_BUFFER_STARTUP_TEST is not set -# CONFIG_PREEMPTIRQ_DELAY_TEST is not set -# CONFIG_TRACE_EVAL_MAP_FILE is not set -CONFIG_TRACING_EVENTS_GPIO=y -# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set -# CONFIG_DMA_API_DEBUG is not set -CONFIG_RUNTIME_TESTING_MENU=y -# CONFIG_LKDTM is not set -# CONFIG_TEST_LIST_SORT is not set -# CONFIG_TEST_SORT is not set -CONFIG_ATOMIC64_SELFTEST=y -CONFIG_ASYNC_RAID6_TEST=m -CONFIG_TEST_HEXDUMP=m -# CONFIG_TEST_STRING_HELPERS is not set -CONFIG_TEST_KSTRTOX=y -CONFIG_TEST_PRINTF=m -# CONFIG_TEST_BITMAP is not set -# CONFIG_TEST_BITFIELD is not set -# CONFIG_TEST_UUID is not set -# CONFIG_TEST_OVERFLOW is not set -# CONFIG_TEST_RHASHTABLE is not set -# CONFIG_TEST_HASH is not set -# CONFIG_TEST_IDA is not set -# CONFIG_TEST_PARMAN is not set -# CONFIG_TEST_LKM is not set -# CONFIG_TEST_USER_COPY is not set -# CONFIG_TEST_BPF is not set -# CONFIG_FIND_BIT_BENCHMARK is not set -# CONFIG_TEST_FIRMWARE is not set -# CONFIG_TEST_SYSCTL is not set -# CONFIG_TEST_UDELAY is not set -CONFIG_TEST_STATIC_KEYS=m -# CONFIG_TEST_KMOD is not set -# CONFIG_MEMTEST is not set -# CONFIG_BUG_ON_DATA_CORRUPTION is not set -# CONFIG_SAMPLES is not set -CONFIG_HAVE_ARCH_KGDB=y -CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y -# CONFIG_UBSAN is not set -CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y -CONFIG_STRICT_DEVMEM=y -# CONFIG_IO_STRICT_DEVMEM is not set -CONFIG_TRACE_IRQFLAGS_SUPPORT=y -CONFIG_EARLY_PRINTK_USB=y -# CONFIG_X86_VERBOSE_BOOTUP is not set -CONFIG_EARLY_PRINTK=y -CONFIG_EARLY_PRINTK_DBGP=y -# CONFIG_EARLY_PRINTK_EFI is not set -# CONFIG_EARLY_PRINTK_USB_XDBC is not set -# CONFIG_EFI_PGT_DUMP is not set -# CONFIG_DEBUG_WX is not set -CONFIG_DOUBLEFAULT=y -CONFIG_HAVE_MMIOTRACE_SUPPORT=y -CONFIG_IO_DELAY_TYPE_0X80=0 -CONFIG_IO_DELAY_TYPE_0XED=1 -CONFIG_IO_DELAY_TYPE_UDELAY=2 -CONFIG_IO_DELAY_TYPE_NONE=3 -CONFIG_IO_DELAY_0X80=y -# CONFIG_IO_DELAY_0XED is not set -# CONFIG_IO_DELAY_UDELAY is not set -# CONFIG_IO_DELAY_NONE is not set -CONFIG_DEFAULT_IO_DELAY_TYPE=0 -CONFIG_OPTIMIZE_INLINING=y -# CONFIG_PUNIT_ATOM_DEBUG is not set -CONFIG_UNWINDER_ORC=y -# CONFIG_UNWINDER_FRAME_POINTER is not set +# +# Automatically generated file; DO NOT EDIT. +# Linux/x86_64 5.4.6 Kernel Configuration +# + +# +# Compiler: gcc (Pisi Linux) 9.2.1 20191214 +# +CONFIG_CC_IS_GCC=y +CONFIG_GCC_VERSION=90201 +CONFIG_CLANG_VERSION=0 +CONFIG_CC_CAN_LINK=y +CONFIG_CC_HAS_ASM_GOTO=y +CONFIG_CC_HAS_ASM_INLINE=y +CONFIG_CC_HAS_WARN_MAYBE_UNINITIALIZED=y +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_EXTABLE_SORT=y +CONFIG_THREAD_INFO_IN_TASK=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +# CONFIG_COMPILE_TEST is not set +# CONFIG_HEADER_TEST is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_BUILD_SALT="" +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_BZIP2=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_BZIP2 is not set +# CONFIG_KERNEL_LZMA is not set +CONFIG_KERNEL_XZ=y +# CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +CONFIG_CROSS_MEMORY_ATTACH=y +# CONFIG_USELIB is not set +CONFIG_AUDIT=y +CONFIG_HAVE_ARCH_AUDITSYSCALL=y +CONFIG_AUDITSYSCALL=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_GENERIC_IRQ_CHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y +CONFIG_GENERIC_IRQ_RESERVATION_MODE=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_SPARSE_IRQ=y +# CONFIG_GENERIC_IRQ_DEBUGFS is not set +# end of IRQ subsystem + +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_ARCH_CLOCKSOURCE_DATA=y +CONFIG_ARCH_CLOCKSOURCE_INIT=y +CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y +CONFIG_GENERIC_CMOS_UPDATE=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +# CONFIG_NO_HZ_IDLE is not set +CONFIG_NO_HZ_FULL=y +CONFIG_CONTEXT_TRACKING=y +# CONFIG_CONTEXT_TRACKING_FORCE is not set +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +# end of Timers subsystem + +# CONFIG_PREEMPT_NONE is not set +CONFIG_PREEMPT_VOLUNTARY=y +# CONFIG_PREEMPT is not set + +# +# CPU/Task time and stats accounting +# +CONFIG_VIRT_CPU_ACCOUNTING=y +CONFIG_VIRT_CPU_ACCOUNTING_GEN=y +# CONFIG_IRQ_TIME_ACCOUNTING is not set +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +# CONFIG_PSI is not set +# end of CPU/Task time and stats accounting + +CONFIG_CPU_ISOLATION=y + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +# CONFIG_RCU_EXPERT is not set +CONFIG_SRCU=y +CONFIG_TREE_SRCU=y +CONFIG_TASKS_RCU=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_RCU_NEED_SEGCBLIST=y +CONFIG_RCU_NOCB_CPU=y +# end of RCU Subsystem + +CONFIG_BUILD_BIN2C=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +# CONFIG_IKHEADERS is not set +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 +CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13 +CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y + +# +# Scheduler features +# +# CONFIG_UCLAMP_TASK is not set +# end of Scheduler features + +CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y +CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y +CONFIG_ARCH_SUPPORTS_INT128=y +# CONFIG_NUMA_BALANCING is not set +CONFIG_CGROUPS=y +CONFIG_PAGE_COUNTER=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +# CONFIG_MEMCG_SWAP_ENABLED is not set +CONFIG_MEMCG_KMEM=y +CONFIG_BLK_CGROUP=y +CONFIG_CGROUP_WRITEBACK=y +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +CONFIG_CFS_BANDWIDTH=y +# CONFIG_RT_GROUP_SCHED is not set +# CONFIG_CGROUP_PIDS is not set +# CONFIG_CGROUP_RDMA is not set +CONFIG_CGROUP_FREEZER=y +# CONFIG_CGROUP_HUGETLB is not set +CONFIG_CPUSETS=y +CONFIG_PROC_PID_CPUSET=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +# CONFIG_CGROUP_PERF is not set +CONFIG_CGROUP_BPF=y +# CONFIG_CGROUP_DEBUG is not set +CONFIG_SOCK_CGROUP_DATA=y +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_IPC_NS=y +CONFIG_USER_NS=y +CONFIG_PID_NS=y +CONFIG_NET_NS=y +CONFIG_CHECKPOINT_RESTORE=y +CONFIG_SCHED_AUTOGROUP=y +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +CONFIG_RD_XZ=y +CONFIG_RD_LZO=y +CONFIG_RD_LZ4=y +CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_HAVE_UID16=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +CONFIG_HAVE_PCSPKR_PLATFORM=y +CONFIG_BPF=y +CONFIG_EXPERT=y +CONFIG_UID16=y +CONFIG_MULTIUSER=y +CONFIG_SGETMASK_SYSCALL=y +# CONFIG_SYSFS_SYSCALL is not set +CONFIG_SYSCTL_SYSCALL=y +CONFIG_FHANDLE=y +CONFIG_POSIX_TIMERS=y +CONFIG_PRINTK=y +CONFIG_PRINTK_NMI=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_PCSPKR_PLATFORM=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_FUTEX_PI=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_IO_URING=y +CONFIG_ADVISE_SYSCALLS=y +CONFIG_MEMBARRIER=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y +CONFIG_KALLSYMS_BASE_RELATIVE=y +CONFIG_BPF_SYSCALL=y +CONFIG_BPF_JIT_ALWAYS_ON=y +# CONFIG_USERFAULTFD is not set +CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y +CONFIG_RSEQ=y +# CONFIG_DEBUG_RSEQ is not set +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +# CONFIG_PC104 is not set + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +# end of Kernel Performance Events And Counters + +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLUB_MEMCG_SYSFS_ON is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_SLAB_MERGE_DEFAULT is not set +CONFIG_SLAB_FREELIST_RANDOM=y +# CONFIG_SLAB_FREELIST_HARDENED is not set +CONFIG_SHUFFLE_PAGE_ALLOCATOR=y +CONFIG_SLUB_CPU_PARTIAL=y +CONFIG_SYSTEM_DATA_VERIFICATION=y +CONFIG_PROFILING=y +CONFIG_TRACEPOINTS=y +# end of General setup + +CONFIG_64BIT=y +CONFIG_X86_64=y +CONFIG_X86=y +CONFIG_INSTRUCTION_DECODER=y +CONFIG_OUTPUT_FORMAT="elf64-x86-64" +CONFIG_ARCH_DEFCONFIG="arch/x86/configs/x86_64_defconfig" +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_MMU=y +CONFIG_ARCH_MMAP_RND_BITS_MIN=28 +CONFIG_ARCH_MMAP_RND_BITS_MAX=32 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16 +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_ARCH_HAS_CPU_RELAX=y +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_ARCH_HAS_FILTER_PGPROT=y +CONFIG_HAVE_SETUP_PER_CPU_AREA=y +CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y +CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ZONE_DMA32=y +CONFIG_AUDIT_ARCH=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_HAVE_INTEL_TXT=y +CONFIG_X86_64_SMP=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_PGTABLE_LEVELS=4 +CONFIG_CC_HAS_SANE_STACKPROTECTOR=y + +# +# Processor type and features +# +CONFIG_ZONE_DMA=y +CONFIG_SMP=y +CONFIG_X86_FEATURE_NAMES=y +CONFIG_X86_X2APIC=y +CONFIG_X86_MPPARSE=y +# CONFIG_GOLDFISH is not set +CONFIG_RETPOLINE=y +CONFIG_X86_CPU_RESCTRL=y +CONFIG_X86_EXTENDED_PLATFORM=y +# CONFIG_X86_NUMACHIP is not set +# CONFIG_X86_VSMP is not set +# CONFIG_X86_UV is not set +# CONFIG_X86_GOLDFISH is not set +# CONFIG_X86_INTEL_MID is not set +CONFIG_X86_INTEL_LPSS=y +CONFIG_X86_AMD_PLATFORM_DEVICE=y +CONFIG_IOSF_MBI=y +# CONFIG_IOSF_MBI_DEBUG is not set +CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y +CONFIG_SCHED_OMIT_FRAME_POINTER=y +CONFIG_HYPERVISOR_GUEST=y +CONFIG_PARAVIRT=y +CONFIG_PARAVIRT_XXL=y +# CONFIG_PARAVIRT_DEBUG is not set +# CONFIG_PARAVIRT_SPINLOCKS is not set +CONFIG_X86_HV_CALLBACK_VECTOR=y +CONFIG_XEN=y +CONFIG_XEN_PV=y +CONFIG_XEN_PV_SMP=y +CONFIG_XEN_DOM0=y +CONFIG_XEN_PVHVM=y +CONFIG_XEN_PVHVM_SMP=y +CONFIG_XEN_512GB=y +CONFIG_XEN_SAVE_RESTORE=y +CONFIG_XEN_DEBUG_FS=y +CONFIG_XEN_PVH=y +CONFIG_KVM_GUEST=y +CONFIG_ARCH_CPUIDLE_HALTPOLL=y +CONFIG_PVH=y +# CONFIG_KVM_DEBUG_FS is not set +# CONFIG_PARAVIRT_TIME_ACCOUNTING is not set +CONFIG_PARAVIRT_CLOCK=y +# CONFIG_JAILHOUSE_GUEST is not set +CONFIG_ACRN_GUEST=y +# CONFIG_MK8 is not set +# CONFIG_MPSC is not set +# CONFIG_MCORE2 is not set +# CONFIG_MATOM is not set +CONFIG_GENERIC_CPU=y +CONFIG_X86_INTERNODE_CACHE_SHIFT=6 +CONFIG_X86_L1_CACHE_SHIFT=6 +CONFIG_X86_TSC=y +CONFIG_X86_CMPXCHG64=y +CONFIG_X86_CMOV=y +CONFIG_X86_MINIMUM_CPU_FAMILY=64 +CONFIG_X86_DEBUGCTLMSR=y +# CONFIG_PROCESSOR_SELECT is not set +CONFIG_CPU_SUP_INTEL=y +CONFIG_CPU_SUP_AMD=y +CONFIG_CPU_SUP_HYGON=y +CONFIG_CPU_SUP_CENTAUR=y +CONFIG_CPU_SUP_ZHAOXIN=y +CONFIG_HPET_TIMER=y +CONFIG_HPET_EMULATE_RTC=y +CONFIG_DMI=y +CONFIG_GART_IOMMU=y +CONFIG_CALGARY_IOMMU=y +CONFIG_CALGARY_IOMMU_ENABLED_BY_DEFAULT=y +# CONFIG_MAXSMP is not set +CONFIG_NR_CPUS_RANGE_BEGIN=2 +CONFIG_NR_CPUS_RANGE_END=512 +CONFIG_NR_CPUS_DEFAULT=64 +CONFIG_NR_CPUS=128 +CONFIG_SCHED_SMT=y +CONFIG_SCHED_MC=y +CONFIG_SCHED_MC_PRIO=y +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_IO_APIC=y +CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y +CONFIG_X86_MCE=y +# CONFIG_X86_MCELOG_LEGACY is not set +CONFIG_X86_MCE_INTEL=y +CONFIG_X86_MCE_AMD=y +CONFIG_X86_MCE_THRESHOLD=y +CONFIG_X86_MCE_INJECT=m +CONFIG_X86_THERMAL_VECTOR=y + +# +# Performance monitoring +# +CONFIG_PERF_EVENTS_INTEL_UNCORE=m +CONFIG_PERF_EVENTS_INTEL_RAPL=m +CONFIG_PERF_EVENTS_INTEL_CSTATE=m +CONFIG_PERF_EVENTS_AMD_POWER=m +# end of Performance monitoring + +CONFIG_X86_16BIT=y +CONFIG_X86_ESPFIX64=y +CONFIG_X86_VSYSCALL_EMULATION=y +CONFIG_I8K=m +CONFIG_MICROCODE=y +CONFIG_MICROCODE_INTEL=y +CONFIG_MICROCODE_AMD=y +CONFIG_MICROCODE_OLD_INTERFACE=y +CONFIG_X86_MSR=m +CONFIG_X86_CPUID=m +# CONFIG_X86_5LEVEL is not set +CONFIG_X86_DIRECT_GBPAGES=y +# CONFIG_X86_CPA_STATISTICS is not set +# CONFIG_AMD_MEM_ENCRYPT is not set +CONFIG_NUMA=y +CONFIG_AMD_NUMA=y +CONFIG_X86_64_ACPI_NUMA=y +CONFIG_NODES_SPAN_OTHER_NODES=y +# CONFIG_NUMA_EMU is not set +CONFIG_NODES_SHIFT=6 +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_MEMORY_PROBE=y +CONFIG_ARCH_PROC_KCORE_TEXT=y +CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 +# CONFIG_X86_PMEM_LEGACY is not set +CONFIG_X86_CHECK_BIOS_CORRUPTION=y +# CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK is not set +CONFIG_X86_RESERVE_LOW=64 +CONFIG_MTRR=y +CONFIG_MTRR_SANITIZER=y +CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT=0 +CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT=1 +CONFIG_X86_PAT=y +CONFIG_ARCH_USES_PG_UNCACHED=y +CONFIG_ARCH_RANDOM=y +CONFIG_X86_SMAP=y +CONFIG_X86_INTEL_UMIP=y +# CONFIG_X86_INTEL_MPX is not set +CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS=y +# CONFIG_X86_INTEL_TSX_MODE_OFF is not set +# CONFIG_X86_INTEL_TSX_MODE_ON is not set +CONFIG_X86_INTEL_TSX_MODE_AUTO=y +CONFIG_EFI=y +CONFIG_EFI_STUB=y +CONFIG_EFI_MIXED=y +CONFIG_SECCOMP=y +# CONFIG_HZ_100 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 +CONFIG_SCHED_HRTICK=y +CONFIG_KEXEC=y +# CONFIG_KEXEC_FILE is not set +CONFIG_CRASH_DUMP=y +CONFIG_KEXEC_JUMP=y +CONFIG_PHYSICAL_START=0x200000 +CONFIG_RELOCATABLE=y +CONFIG_RANDOMIZE_BASE=y +CONFIG_X86_NEED_RELOCS=y +CONFIG_PHYSICAL_ALIGN=0x1000000 +CONFIG_DYNAMIC_MEMORY_LAYOUT=y +CONFIG_RANDOMIZE_MEMORY=y +CONFIG_RANDOMIZE_MEMORY_PHYSICAL_PADDING=0xa +CONFIG_HOTPLUG_CPU=y +# CONFIG_BOOTPARAM_HOTPLUG_CPU0 is not set +# CONFIG_DEBUG_HOTPLUG_CPU0 is not set +# CONFIG_COMPAT_VDSO is not set +CONFIG_LEGACY_VSYSCALL_EMULATE=y +# CONFIG_LEGACY_VSYSCALL_XONLY is not set +# CONFIG_LEGACY_VSYSCALL_NONE is not set +# CONFIG_CMDLINE_BOOL is not set +CONFIG_MODIFY_LDT_SYSCALL=y +CONFIG_HAVE_LIVEPATCH=y +CONFIG_LIVEPATCH=y +# end of Processor type and features + +CONFIG_ARCH_HAS_ADD_PAGES=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y +CONFIG_USE_PERCPU_NUMA_NODE_ID=y +CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y +CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION=y +CONFIG_ARCH_ENABLE_THP_MIGRATION=y + +# +# Power management and ACPI options +# +CONFIG_ARCH_HIBERNATION_HEADER=y +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +# CONFIG_SUSPEND_SKIP_SYNC is not set +CONFIG_HIBERNATE_CALLBACKS=y +CONFIG_HIBERNATION=y +CONFIG_PM_STD_PARTITION="" +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_WAKELOCKS is not set +CONFIG_PM=y +CONFIG_PM_DEBUG=y +# CONFIG_PM_ADVANCED_DEBUG is not set +# CONFIG_PM_TEST_SUSPEND is not set +CONFIG_PM_SLEEP_DEBUG=y +# CONFIG_DPM_WATCHDOG is not set +CONFIG_PM_TRACE=y +CONFIG_PM_TRACE_RTC=y +CONFIG_PM_CLK=y +CONFIG_PM_GENERIC_DOMAINS=y +# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set +CONFIG_PM_GENERIC_DOMAINS_SLEEP=y +# CONFIG_ENERGY_MODEL is not set +CONFIG_ARCH_SUPPORTS_ACPI=y +CONFIG_ACPI=y +CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y +CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y +CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y +# CONFIG_ACPI_DEBUGGER is not set +CONFIG_ACPI_SPCR_TABLE=y +CONFIG_ACPI_LPIT=y +CONFIG_ACPI_SLEEP=y +# CONFIG_ACPI_PROCFS_POWER is not set +CONFIG_ACPI_REV_OVERRIDE_POSSIBLE=y +# CONFIG_ACPI_EC_DEBUGFS is not set +CONFIG_ACPI_AC=m +CONFIG_ACPI_BATTERY=m +CONFIG_ACPI_BUTTON=m +CONFIG_ACPI_VIDEO=m +CONFIG_ACPI_FAN=m +CONFIG_ACPI_TAD=m +CONFIG_ACPI_DOCK=y +CONFIG_ACPI_CPU_FREQ_PSS=y +CONFIG_ACPI_PROCESSOR_CSTATE=y +CONFIG_ACPI_PROCESSOR_IDLE=y +CONFIG_ACPI_CPPC_LIB=y +CONFIG_ACPI_PROCESSOR=y +CONFIG_ACPI_IPMI=m +CONFIG_ACPI_HOTPLUG_CPU=y +CONFIG_ACPI_PROCESSOR_AGGREGATOR=m +CONFIG_ACPI_THERMAL=m +CONFIG_ACPI_NUMA=y +CONFIG_ACPI_CUSTOM_DSDT_FILE="" +CONFIG_ARCH_HAS_ACPI_TABLE_UPGRADE=y +CONFIG_ACPI_TABLE_UPGRADE=y +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_PCI_SLOT is not set +CONFIG_ACPI_CONTAINER=y +# CONFIG_ACPI_HOTPLUG_MEMORY is not set +CONFIG_ACPI_HOTPLUG_IOAPIC=y +CONFIG_ACPI_SBS=m +CONFIG_ACPI_HED=y +# CONFIG_ACPI_CUSTOM_METHOD is not set +CONFIG_ACPI_BGRT=y +# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set +CONFIG_ACPI_NFIT=m +# CONFIG_NFIT_SECURITY_DEBUG is not set +# CONFIG_ACPI_HMAT is not set +CONFIG_HAVE_ACPI_APEI=y +CONFIG_HAVE_ACPI_APEI_NMI=y +CONFIG_ACPI_APEI=y +CONFIG_ACPI_APEI_GHES=y +CONFIG_ACPI_APEI_PCIEAER=y +CONFIG_ACPI_APEI_MEMORY_FAILURE=y +CONFIG_ACPI_APEI_EINJ=m +# CONFIG_ACPI_APEI_ERST_DEBUG is not set +CONFIG_DPTF_POWER=m +CONFIG_ACPI_WATCHDOG=y +CONFIG_ACPI_EXTLOG=m +CONFIG_ACPI_ADXL=y +CONFIG_PMIC_OPREGION=y +CONFIG_CRC_PMIC_OPREGION=y +# CONFIG_XPOWER_PMIC_OPREGION is not set +CONFIG_BXT_WC_PMIC_OPREGION=y +CONFIG_CHT_WC_PMIC_OPREGION=y +CONFIG_CHT_DC_TI_PMIC_OPREGION=y +CONFIG_ACPI_CONFIGFS=m +# CONFIG_TPS68470_PMIC_OPREGION is not set +CONFIG_X86_PM_TIMER=y +# CONFIG_SFI is not set + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_GOV_COMMON=y +# CONFIG_CPU_FREQ_STAT is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y + +# +# CPU frequency scaling drivers +# +CONFIG_X86_INTEL_PSTATE=y +CONFIG_X86_PCC_CPUFREQ=m +CONFIG_X86_ACPI_CPUFREQ=m +CONFIG_X86_ACPI_CPUFREQ_CPB=y +CONFIG_X86_POWERNOW_K8=m +CONFIG_X86_AMD_FREQ_SENSITIVITY=m +CONFIG_X86_SPEEDSTEP_CENTRINO=m +CONFIG_X86_P4_CLOCKMOD=m + +# +# shared options +# +CONFIG_X86_SPEEDSTEP_LIB=m +# end of CPU Frequency scaling + +# +# CPU Idle +# +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_CPU_IDLE_GOV_TEO=y +CONFIG_CPU_IDLE_GOV_HALTPOLL=y +CONFIG_HALTPOLL_CPUIDLE=m +# end of CPU Idle + +CONFIG_INTEL_IDLE=y +# end of Power management and ACPI options + +# +# Bus options (PCI etc.) +# +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_PCI_XEN=y +CONFIG_MMCONF_FAM10H=y +# CONFIG_PCI_CNB20LE_QUIRK is not set +CONFIG_ISA_BUS=y +CONFIG_ISA_DMA_API=y +CONFIG_AMD_NB=y +# CONFIG_X86_SYSFB is not set +# end of Bus options (PCI etc.) + +# +# Binary Emulations +# +CONFIG_IA32_EMULATION=y +CONFIG_X86_X32=y +CONFIG_COMPAT_32=y +CONFIG_COMPAT=y +CONFIG_COMPAT_FOR_U64_ALIGNMENT=y +CONFIG_SYSVIPC_COMPAT=y +# end of Binary Emulations + +CONFIG_X86_DEV_DMA_OPS=y + +# +# Firmware Drivers +# +CONFIG_EDD=y +# CONFIG_EDD_OFF is not set +CONFIG_FIRMWARE_MEMMAP=y +CONFIG_DMIID=y +CONFIG_DMI_SYSFS=m +CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y +CONFIG_ISCSI_IBFT_FIND=y +CONFIG_ISCSI_IBFT=m +CONFIG_FW_CFG_SYSFS=m +# CONFIG_FW_CFG_SYSFS_CMDLINE is not set +# CONFIG_GOOGLE_FIRMWARE is not set + +# +# EFI (Extensible Firmware Interface) Support +# +CONFIG_EFI_VARS=y +CONFIG_EFI_ESRT=y +CONFIG_EFI_VARS_PSTORE=y +CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE=y +CONFIG_EFI_RUNTIME_MAP=y +# CONFIG_EFI_FAKE_MEMMAP is not set +CONFIG_EFI_RUNTIME_WRAPPERS=y +CONFIG_EFI_BOOTLOADER_CONTROL=m +CONFIG_EFI_CAPSULE_LOADER=m +# CONFIG_EFI_TEST is not set +CONFIG_APPLE_PROPERTIES=y +# CONFIG_RESET_ATTACK_MITIGATION is not set +CONFIG_EFI_RCI2_TABLE=y +# end of EFI (Extensible Firmware Interface) Support + +CONFIG_UEFI_CPER=y +CONFIG_UEFI_CPER_X86=y +CONFIG_EFI_DEV_PATH_PARSER=y +CONFIG_EFI_EARLYCON=y + +# +# Tegra firmware driver +# +# end of Tegra firmware driver +# end of Firmware Drivers + +CONFIG_HAVE_KVM=y +CONFIG_HAVE_KVM_IRQCHIP=y +CONFIG_HAVE_KVM_IRQFD=y +CONFIG_HAVE_KVM_IRQ_ROUTING=y +CONFIG_HAVE_KVM_EVENTFD=y +CONFIG_KVM_MMIO=y +CONFIG_KVM_ASYNC_PF=y +CONFIG_HAVE_KVM_MSI=y +CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT=y +CONFIG_KVM_VFIO=y +CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y +CONFIG_KVM_COMPAT=y +CONFIG_HAVE_KVM_IRQ_BYPASS=y +CONFIG_HAVE_KVM_NO_POLL=y +CONFIG_VIRTUALIZATION=y +CONFIG_KVM=m +CONFIG_KVM_INTEL=m +CONFIG_KVM_AMD=m +CONFIG_KVM_AMD_SEV=y +# CONFIG_KVM_MMU_AUDIT is not set +CONFIG_VHOST_NET=m +CONFIG_VHOST_SCSI=m +CONFIG_VHOST_VSOCK=m +CONFIG_VHOST=m +# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set + +# +# General architecture-dependent options +# +CONFIG_CRASH_CORE=y +CONFIG_KEXEC_CORE=y +CONFIG_HOTPLUG_SMT=y +CONFIG_OPROFILE=m +CONFIG_OPROFILE_EVENT_MULTIPLEX=y +CONFIG_HAVE_OPROFILE=y +CONFIG_OPROFILE_NMI_TIMER=y +CONFIG_KPROBES=y +CONFIG_JUMP_LABEL=y +# CONFIG_STATIC_KEYS_SELFTEST is not set +CONFIG_OPTPROBES=y +CONFIG_KPROBES_ON_FTRACE=y +CONFIG_UPROBES=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_KRETPROBES=y +CONFIG_USER_RETURN_NOTIFIER=y +CONFIG_HAVE_IOREMAP_PROT=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_OPTPROBES=y +CONFIG_HAVE_KPROBES_ON_FTRACE=y +CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y +CONFIG_HAVE_NMI=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SET_DIRECT_MAP=y +CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y +CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y +CONFIG_HAVE_ASM_MODVERSIONS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_RSEQ=y +CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y +CONFIG_HAVE_USER_RETURN_NOTIFIER=y +CONFIG_HAVE_PERF_EVENTS_NMI=y +CONFIG_HAVE_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y +CONFIG_HAVE_RCU_TABLE_FREE=y +CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y +CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y +CONFIG_HAVE_CMPXCHG_LOCAL=y +CONFIG_HAVE_CMPXCHG_DOUBLE=y +CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y +CONFIG_ARCH_WANT_OLD_COMPAT_IPC=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_SECCOMP_FILTER=y +CONFIG_HAVE_ARCH_STACKLEAK=y +CONFIG_HAVE_STACKPROTECTOR=y +CONFIG_CC_HAS_STACKPROTECTOR_NONE=y +CONFIG_STACKPROTECTOR=y +CONFIG_STACKPROTECTOR_STRONG=y +CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MOVE_PMD=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD=y +CONFIG_HAVE_ARCH_HUGE_VMAP=y +CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y +CONFIG_HAVE_ARCH_SOFT_DIRTY=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_HAVE_ARCH_MMAP_RND_BITS=y +CONFIG_HAVE_EXIT_THREAD=y +CONFIG_ARCH_MMAP_RND_BITS=28 +CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=8 +CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES=y +CONFIG_HAVE_COPY_THREAD_TLS=y +CONFIG_HAVE_STACK_VALIDATION=y +CONFIG_HAVE_RELIABLE_STACKTRACE=y +CONFIG_ISA_BUS_API=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_COMPAT_OLD_SIGACTION=y +CONFIG_64BIT_TIME=y +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_HAVE_ARCH_VMAP_STACK=y +CONFIG_VMAP_STACK=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_STRICT_MODULE_RWX=y +CONFIG_ARCH_HAS_REFCOUNT=y +# CONFIG_REFCOUNT_FULL is not set +CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y +CONFIG_ARCH_USE_MEMREMAP_PROT=y +# CONFIG_LOCK_EVENT_COUNTS is not set +CONFIG_ARCH_HAS_MEM_ENCRYPT=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +# end of GCOV-based kernel profiling + +CONFIG_PLUGIN_HOSTCC="" +CONFIG_HAVE_GCC_PLUGINS=y +# end of General architecture-dependent options + +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +CONFIG_MODULE_FORCE_LOAD=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_MODULE_SIG is not set +# CONFIG_MODULE_COMPRESS is not set +# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set +CONFIG_UNUSED_SYMBOLS=y +CONFIG_MODULES_TREE_LOOKUP=y +CONFIG_BLOCK=y +CONFIG_BLK_SCSI_REQUEST=y +CONFIG_BLK_DEV_BSG=y +CONFIG_BLK_DEV_BSGLIB=y +CONFIG_BLK_DEV_INTEGRITY=y +# CONFIG_BLK_DEV_ZONED is not set +CONFIG_BLK_DEV_THROTTLING=y +# CONFIG_BLK_DEV_THROTTLING_LOW is not set +# CONFIG_BLK_CMDLINE_PARSER is not set +CONFIG_BLK_WBT=y +# CONFIG_BLK_CGROUP_IOLATENCY is not set +# CONFIG_BLK_CGROUP_IOCOST is not set +CONFIG_BLK_WBT_MQ=y +# CONFIG_BLK_DEBUG_FS is not set +CONFIG_BLK_SED_OPAL=y + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_AIX_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +CONFIG_LDM_PARTITION=y +# CONFIG_LDM_DEBUG is not set +CONFIG_SGI_PARTITION=y +# CONFIG_ULTRIX_PARTITION is not set +CONFIG_SUN_PARTITION=y +CONFIG_KARMA_PARTITION=y +CONFIG_EFI_PARTITION=y +CONFIG_SYSV68_PARTITION=y +# CONFIG_CMDLINE_PARTITION is not set +# end of Partition Types + +CONFIG_BLOCK_COMPAT=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BLK_MQ_VIRTIO=y +CONFIG_BLK_MQ_RDMA=y +CONFIG_BLK_PM=y + +# +# IO Schedulers +# +CONFIG_MQ_IOSCHED_DEADLINE=y +CONFIG_MQ_IOSCHED_KYBER=y +CONFIG_IOSCHED_BFQ=y +CONFIG_BFQ_GROUP_IOSCHED=y +# CONFIG_BFQ_CGROUP_DEBUG is not set +# end of IO Schedulers + +CONFIG_PREEMPT_NOTIFIERS=y +CONFIG_PADATA=y +CONFIG_ASN1=y +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +CONFIG_INLINE_READ_UNLOCK=y +CONFIG_INLINE_READ_UNLOCK_IRQ=y +CONFIG_INLINE_WRITE_UNLOCK=y +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y +CONFIG_QUEUED_SPINLOCKS=y +CONFIG_ARCH_USE_QUEUED_RWLOCKS=y +CONFIG_QUEUED_RWLOCKS=y +CONFIG_ARCH_HAS_SYNC_CORE_BEFORE_USERMODE=y +CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y +CONFIG_FREEZER=y + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +CONFIG_COMPAT_BINFMT_ELF=y +CONFIG_ELFCORE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_SCRIPT=y +CONFIG_BINFMT_MISC=m +CONFIG_COREDUMP=y +# end of Executable file formats + +# +# Memory Management options +# +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_NEED_MULTIPLE_NODES=y +CONFIG_HAVE_MEMORY_PRESENT=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_HAVE_MEMBLOCK_NODE_MAP=y +CONFIG_HAVE_FAST_GUP=y +CONFIG_MEMORY_ISOLATION=y +CONFIG_HAVE_BOOTMEM_INFO_NODE=y +CONFIG_MEMORY_HOTPLUG=y +CONFIG_MEMORY_HOTPLUG_SPARSE=y +# CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE is not set +CONFIG_MEMORY_HOTREMOVE=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_MEMORY_BALLOON=y +CONFIG_BALLOON_COMPACTION=y +CONFIG_COMPACTION=y +CONFIG_MIGRATION=y +CONFIG_CONTIG_ALLOC=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y +CONFIG_MMU_NOTIFIER=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y +CONFIG_MEMORY_FAILURE=y +# CONFIG_HWPOISON_INJECT is not set +CONFIG_TRANSPARENT_HUGEPAGE=y +# CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS is not set +CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y +CONFIG_ARCH_WANTS_THP_SWAP=y +CONFIG_THP_SWAP=y +CONFIG_TRANSPARENT_HUGE_PAGECACHE=y +CONFIG_CLEANCACHE=y +CONFIG_FRONTSWAP=y +CONFIG_CMA=y +# CONFIG_CMA_DEBUG is not set +# CONFIG_CMA_DEBUGFS is not set +CONFIG_CMA_AREAS=7 +# CONFIG_MEM_SOFT_DIRTY is not set +CONFIG_ZSWAP=y +CONFIG_ZPOOL=y +CONFIG_ZBUD=y +CONFIG_Z3FOLD=m +CONFIG_ZSMALLOC=y +# CONFIG_PGTABLE_MAPPING is not set +# CONFIG_ZSMALLOC_STAT is not set +CONFIG_GENERIC_EARLY_IOREMAP=y +# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set +# CONFIG_IDLE_PAGE_TRACKING is not set +CONFIG_ARCH_HAS_PTE_DEVMAP=y +# CONFIG_ZONE_DEVICE is not set +CONFIG_HMM_MIRROR=y +CONFIG_FRAME_VECTOR=y +CONFIG_ARCH_USES_HIGH_VMA_FLAGS=y +CONFIG_ARCH_HAS_PKEYS=y +# CONFIG_PERCPU_STATS is not set +# CONFIG_GUP_BENCHMARK is not set +# CONFIG_READ_ONLY_THP_FOR_FS is not set +CONFIG_ARCH_HAS_PTE_SPECIAL=y +# end of Memory Management options + +CONFIG_NET=y +CONFIG_COMPAT_NETLINK_MESSAGES=y +CONFIG_NET_INGRESS=y +CONFIG_NET_EGRESS=y +CONFIG_SKB_EXTENSIONS=y + +# +# Networking options +# +CONFIG_PACKET=m +CONFIG_PACKET_DIAG=m +CONFIG_UNIX=y +CONFIG_UNIX_SCM=y +CONFIG_UNIX_DIAG=m +CONFIG_TLS=m +# CONFIG_TLS_DEVICE is not set +CONFIG_XFRM=y +CONFIG_XFRM_OFFLOAD=y +CONFIG_XFRM_ALGO=m +CONFIG_XFRM_USER=m +CONFIG_XFRM_INTERFACE=m +CONFIG_XFRM_SUB_POLICY=y +CONFIG_XFRM_MIGRATE=y +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_IPCOMP=m +CONFIG_NET_KEY=m +CONFIG_NET_KEY_MIGRATE=y +# CONFIG_SMC is not set +CONFIG_XDP_SOCKETS=y +CONFIG_XDP_SOCKETS_DIAG=m +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_ROUTE_CLASSID=y +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE_DEMUX=m +CONFIG_NET_IP_TUNNEL=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE_COMMON=y +CONFIG_IP_MROUTE=y +CONFIG_IP_MROUTE_MULTIPLE_TABLES=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_SYN_COOKIES=y +CONFIG_NET_IPVTI=m +CONFIG_NET_UDP_TUNNEL=m +CONFIG_NET_FOU=m +CONFIG_NET_FOU_IP_TUNNELS=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_ESP_OFFLOAD=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_TUNNEL=m +CONFIG_INET_TUNNEL=m +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +CONFIG_INET_UDP_DIAG=m +CONFIG_INET_RAW_DIAG=m +# CONFIG_INET_DIAG_DESTROY 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_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_ESP_OFFLOAD=m +CONFIG_INET6_IPCOMP=m +CONFIG_IPV6_MIP6=m +# CONFIG_IPV6_ILA is not set +CONFIG_INET6_XFRM_TUNNEL=m +CONFIG_INET6_TUNNEL=m +CONFIG_IPV6_VTI=m +CONFIG_IPV6_SIT=m +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +CONFIG_IPV6_TUNNEL=m +CONFIG_IPV6_GRE=m +CONFIG_IPV6_FOU=m +CONFIG_IPV6_FOU_TUNNEL=m +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_IPV6_MROUTE=y +CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y +CONFIG_IPV6_PIMSM_V2=y +# CONFIG_IPV6_SEG6_LWTUNNEL is not set +# CONFIG_IPV6_SEG6_HMAC is not set +CONFIG_NETLABEL=y +CONFIG_NETWORK_SECMARK=y +CONFIG_NET_PTP_CLASSIFY=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +CONFIG_NETFILTER_ADVANCED=y +CONFIG_BRIDGE_NETFILTER=m + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_INGRESS=y +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_FAMILY_BRIDGE=y +CONFIG_NETFILTER_FAMILY_ARP=y +CONFIG_NETFILTER_NETLINK_ACCT=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +CONFIG_NETFILTER_NETLINK_LOG=m +CONFIG_NETFILTER_NETLINK_OSF=m +CONFIG_NF_CONNTRACK=m +CONFIG_NF_LOG_COMMON=m +CONFIG_NF_LOG_NETDEV=m +CONFIG_NETFILTER_CONNCOUNT=m +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_ZONES=y +# CONFIG_NF_CONNTRACK_PROCFS is not set +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_TIMEOUT=y +CONFIG_NF_CONNTRACK_TIMESTAMP=y +CONFIG_NF_CONNTRACK_LABELS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_GRE=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_BROADCAST=m +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_SNMP=m +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_SANE=m +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_NETLINK=m +CONFIG_NF_CT_NETLINK_TIMEOUT=m +CONFIG_NF_CT_NETLINK_HELPER=m +CONFIG_NETFILTER_NETLINK_GLUE_CT=y +CONFIG_NF_NAT=m +CONFIG_NF_NAT_AMANDA=m +CONFIG_NF_NAT_FTP=m +CONFIG_NF_NAT_IRC=m +CONFIG_NF_NAT_SIP=m +CONFIG_NF_NAT_TFTP=m +CONFIG_NF_NAT_REDIRECT=y +CONFIG_NF_NAT_MASQUERADE=y +CONFIG_NETFILTER_SYNPROXY=m +CONFIG_NF_TABLES=m +CONFIG_NF_TABLES_SET=m +# CONFIG_NF_TABLES_INET is not set +CONFIG_NF_TABLES_NETDEV=y +CONFIG_NFT_NUMGEN=m +CONFIG_NFT_CT=m +CONFIG_NFT_FLOW_OFFLOAD=m +CONFIG_NFT_COUNTER=m +CONFIG_NFT_CONNLIMIT=m +CONFIG_NFT_LOG=m +CONFIG_NFT_LIMIT=m +CONFIG_NFT_MASQ=m +CONFIG_NFT_REDIR=m +CONFIG_NFT_NAT=m +CONFIG_NFT_TUNNEL=m +CONFIG_NFT_OBJREF=m +CONFIG_NFT_QUEUE=m +CONFIG_NFT_QUOTA=m +CONFIG_NFT_REJECT=m +CONFIG_NFT_COMPAT=m +CONFIG_NFT_HASH=m +CONFIG_NFT_FIB=m +CONFIG_NFT_XFRM=m +CONFIG_NFT_SOCKET=m +CONFIG_NFT_OSF=m +CONFIG_NFT_TPROXY=m +CONFIG_NFT_SYNPROXY=m +CONFIG_NF_DUP_NETDEV=m +CONFIG_NFT_DUP_NETDEV=m +CONFIG_NFT_FWD_NETDEV=m +CONFIG_NFT_FIB_NETDEV=m +CONFIG_NF_FLOW_TABLE_INET=m +CONFIG_NF_FLOW_TABLE=m +CONFIG_NETFILTER_XTABLES=m + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=m +CONFIG_NETFILTER_XT_CONNMARK=m +CONFIG_NETFILTER_XT_SET=m + +# +# Xtables targets +# +CONFIG_NETFILTER_XT_TARGET_AUDIT=m +CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m +CONFIG_NETFILTER_XT_TARGET_CT=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_HL=m +CONFIG_NETFILTER_XT_TARGET_HMARK=m +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m +CONFIG_NETFILTER_XT_TARGET_LED=m +CONFIG_NETFILTER_XT_TARGET_LOG=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_NAT=m +CONFIG_NETFILTER_XT_TARGET_NETMAP=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set +CONFIG_NETFILTER_XT_TARGET_RATEEST=m +CONFIG_NETFILTER_XT_TARGET_REDIRECT=m +CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m +CONFIG_NETFILTER_XT_TARGET_TEE=m +CONFIG_NETFILTER_XT_TARGET_TPROXY=m +CONFIG_NETFILTER_XT_TARGET_TRACE=m +CONFIG_NETFILTER_XT_TARGET_SECMARK=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m + +# +# Xtables matches +# +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +CONFIG_NETFILTER_XT_MATCH_BPF=m +CONFIG_NETFILTER_XT_MATCH_CGROUP=m +CONFIG_NETFILTER_XT_MATCH_CLUSTER=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_CPU=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m +CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ECN=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_HL=m +CONFIG_NETFILTER_XT_MATCH_IPCOMP=m +CONFIG_NETFILTER_XT_MATCH_IPRANGE=m +CONFIG_NETFILTER_XT_MATCH_IPVS=m +CONFIG_NETFILTER_XT_MATCH_L2TP=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_NFACCT=m +CONFIG_NETFILTER_XT_MATCH_OSF=m +CONFIG_NETFILTER_XT_MATCH_OWNER=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_RATEEST=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_RECENT=m +CONFIG_NETFILTER_XT_MATCH_SCTP=m +CONFIG_NETFILTER_XT_MATCH_SOCKET=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_TIME=m +CONFIG_NETFILTER_XT_MATCH_U32=m +# end of Core Netfilter Configuration + +CONFIG_IP_SET=m +CONFIG_IP_SET_MAX=256 +CONFIG_IP_SET_BITMAP_IP=m +CONFIG_IP_SET_BITMAP_IPMAC=m +CONFIG_IP_SET_BITMAP_PORT=m +CONFIG_IP_SET_HASH_IP=m +CONFIG_IP_SET_HASH_IPMARK=m +CONFIG_IP_SET_HASH_IPPORT=m +CONFIG_IP_SET_HASH_IPPORTIP=m +CONFIG_IP_SET_HASH_IPPORTNET=m +CONFIG_IP_SET_HASH_IPMAC=m +CONFIG_IP_SET_HASH_MAC=m +CONFIG_IP_SET_HASH_NETPORTNET=m +CONFIG_IP_SET_HASH_NET=m +CONFIG_IP_SET_HASH_NETNET=m +CONFIG_IP_SET_HASH_NETPORT=m +CONFIG_IP_SET_HASH_NETIFACE=m +CONFIG_IP_SET_LIST_SET=m +CONFIG_IP_VS=m +CONFIG_IP_VS_IPV6=y +CONFIG_IP_VS_DEBUG=y +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_AH_ESP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_PROTO_SCTP=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_FO=m +CONFIG_IP_VS_OVF=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_MH=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_NQ=m + +# +# IPVS SH scheduler +# +CONFIG_IP_VS_SH_TAB_BITS=8 + +# +# IPVS MH scheduler +# +CONFIG_IP_VS_MH_TAB_INDEX=12 + +# +# IPVS application helper +# +CONFIG_IP_VS_FTP=m +CONFIG_IP_VS_NFCT=y +CONFIG_IP_VS_PE_SIP=m + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=m +CONFIG_NF_SOCKET_IPV4=m +CONFIG_NF_TPROXY_IPV4=m +CONFIG_NF_TABLES_IPV4=y +CONFIG_NFT_REJECT_IPV4=m +CONFIG_NFT_DUP_IPV4=m +CONFIG_NFT_FIB_IPV4=m +CONFIG_NF_TABLES_ARP=y +CONFIG_NF_FLOW_TABLE_IPV4=m +CONFIG_NF_DUP_IPV4=m +CONFIG_NF_LOG_ARP=m +CONFIG_NF_LOG_IPV4=m +CONFIG_NF_REJECT_IPV4=m +CONFIG_NF_NAT_SNMP_BASIC=m +CONFIG_NF_NAT_PPTP=m +CONFIG_NF_NAT_H323=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_RPFILTER=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_SYNPROXY=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_SECURITY=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m +# end of IP: Netfilter Configuration + +# +# IPv6: Netfilter Configuration +# +CONFIG_NF_SOCKET_IPV6=m +CONFIG_NF_TPROXY_IPV6=m +CONFIG_NF_TABLES_IPV6=y +CONFIG_NFT_REJECT_IPV6=m +CONFIG_NFT_DUP_IPV6=m +CONFIG_NFT_FIB_IPV6=m +CONFIG_NF_FLOW_TABLE_IPV6=m +CONFIG_NF_DUP_IPV6=m +CONFIG_NF_REJECT_IPV6=m +CONFIG_NF_LOG_IPV6=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_RPFILTER=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_SRH=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IP6_NF_TARGET_SYNPROXY=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_RAW=m +CONFIG_IP6_NF_SECURITY=m +CONFIG_IP6_NF_NAT=m +CONFIG_IP6_NF_TARGET_MASQUERADE=m +CONFIG_IP6_NF_TARGET_NPT=m +# end of IPv6: Netfilter Configuration + +CONFIG_NF_DEFRAG_IPV6=m + +# +# DECnet: Netfilter Configuration +# +CONFIG_DECNET_NF_GRABULATOR=m +# end of DECnet: Netfilter Configuration + +CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m +CONFIG_NFT_BRIDGE_REJECT=m +CONFIG_NF_LOG_BRIDGE=m +CONFIG_NF_CONNTRACK_BRIDGE=m +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_IP6=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_NFLOG=m +# CONFIG_BPFILTER is not set +CONFIG_IP_DCCP=m +CONFIG_INET_DCCP_DIAG=m + +# +# DCCP CCIDs Configuration +# +# CONFIG_IP_DCCP_CCID2_DEBUG is not set +CONFIG_IP_DCCP_CCID3=y +# CONFIG_IP_DCCP_CCID3_DEBUG is not set +CONFIG_IP_DCCP_TFRC_LIB=y +# end of DCCP CCIDs Configuration + +# +# DCCP Kernel Hacking +# +# CONFIG_IP_DCCP_DEBUG is not set +# end of DCCP Kernel Hacking + +CONFIG_IP_SCTP=m +# CONFIG_SCTP_DBG_OBJCNT is not set +CONFIG_SCTP_DEFAULT_COOKIE_HMAC_MD5=y +# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1 is not set +# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_NONE is not set +CONFIG_SCTP_COOKIE_HMAC_MD5=y +CONFIG_SCTP_COOKIE_HMAC_SHA1=y +CONFIG_INET_SCTP_DIAG=m +CONFIG_RDS=m +CONFIG_RDS_RDMA=m +CONFIG_RDS_TCP=m +# CONFIG_RDS_DEBUG is not set +CONFIG_TIPC=m +CONFIG_TIPC_MEDIA_IB=y +CONFIG_TIPC_MEDIA_UDP=y +CONFIG_TIPC_DIAG=m +CONFIG_ATM=m +CONFIG_ATM_CLIP=m +# CONFIG_ATM_CLIP_NO_ICMP is not set +CONFIG_ATM_LANE=m +CONFIG_ATM_MPOA=m +CONFIG_ATM_BR2684=m +CONFIG_ATM_BR2684_IPFILTER=y +CONFIG_L2TP=m +CONFIG_L2TP_DEBUGFS=m +# CONFIG_L2TP_V3 is not set +CONFIG_STP=m +CONFIG_GARP=m +CONFIG_MRP=m +CONFIG_BRIDGE=m +CONFIG_BRIDGE_IGMP_SNOOPING=y +CONFIG_BRIDGE_VLAN_FILTERING=y +CONFIG_HAVE_NET_DSA=y +CONFIG_NET_DSA=m +# CONFIG_NET_DSA_TAG_8021Q is not set +CONFIG_NET_DSA_TAG_BRCM_COMMON=m +CONFIG_NET_DSA_TAG_BRCM=m +CONFIG_NET_DSA_TAG_BRCM_PREPEND=m +CONFIG_NET_DSA_TAG_GSWIP=m +CONFIG_NET_DSA_TAG_DSA=m +CONFIG_NET_DSA_TAG_EDSA=m +# CONFIG_NET_DSA_TAG_MTK is not set +# CONFIG_NET_DSA_TAG_KSZ is not set +# CONFIG_NET_DSA_TAG_QCA is not set +# CONFIG_NET_DSA_TAG_LAN9303 is not set +# CONFIG_NET_DSA_TAG_SJA1105 is not set +CONFIG_NET_DSA_TAG_TRAILER=m +CONFIG_VLAN_8021Q=m +CONFIG_VLAN_8021Q_GVRP=y +CONFIG_VLAN_8021Q_MVRP=y +CONFIG_DECNET=m +# CONFIG_DECNET_ROUTER is not set +CONFIG_LLC=m +CONFIG_LLC2=m +CONFIG_ATALK=m +CONFIG_DEV_APPLETALK=m +CONFIG_IPDDP=m +CONFIG_IPDDP_ENCAP=y +CONFIG_X25=m +CONFIG_LAPB=m +CONFIG_PHONET=m +CONFIG_6LOWPAN=m +# CONFIG_6LOWPAN_DEBUGFS is not set +CONFIG_6LOWPAN_NHC=m +CONFIG_6LOWPAN_NHC_DEST=m +CONFIG_6LOWPAN_NHC_FRAGMENT=m +CONFIG_6LOWPAN_NHC_HOP=m +CONFIG_6LOWPAN_NHC_IPV6=m +CONFIG_6LOWPAN_NHC_MOBILITY=m +CONFIG_6LOWPAN_NHC_ROUTING=m +CONFIG_6LOWPAN_NHC_UDP=m +CONFIG_6LOWPAN_GHC_EXT_HDR_HOP=m +CONFIG_6LOWPAN_GHC_UDP=m +CONFIG_6LOWPAN_GHC_ICMPV6=m +CONFIG_6LOWPAN_GHC_EXT_HDR_DEST=m +CONFIG_6LOWPAN_GHC_EXT_HDR_FRAG=m +CONFIG_6LOWPAN_GHC_EXT_HDR_ROUTE=m +CONFIG_IEEE802154=m +CONFIG_IEEE802154_NL802154_EXPERIMENTAL=y +CONFIG_IEEE802154_SOCKET=m +CONFIG_IEEE802154_6LOWPAN=m +CONFIG_MAC802154=m +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +# CONFIG_NET_SCH_ATM is not set +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_MULTIQ=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFB=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_CBS=m +CONFIG_NET_SCH_ETF=m +CONFIG_NET_SCH_TAPRIO=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_DRR=m +CONFIG_NET_SCH_MQPRIO=m +CONFIG_NET_SCH_SKBPRIO=m +CONFIG_NET_SCH_CHOKE=m +CONFIG_NET_SCH_QFQ=m +CONFIG_NET_SCH_CODEL=m +CONFIG_NET_SCH_FQ_CODEL=m +CONFIG_NET_SCH_CAKE=m +CONFIG_NET_SCH_FQ=m +CONFIG_NET_SCH_HHF=m +CONFIG_NET_SCH_PIE=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_SCH_PLUG=m +# CONFIG_NET_SCH_DEFAULT is not set + +# +# Classification +# +CONFIG_NET_CLS=y +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CLS_U32_MARK is not set +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_FLOW=m +CONFIG_NET_CLS_CGROUP=y +CONFIG_NET_CLS_BPF=m +CONFIG_NET_CLS_FLOWER=m +CONFIG_NET_CLS_MATCHALL=m +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_NBYTE=m +CONFIG_NET_EMATCH_U32=m +CONFIG_NET_EMATCH_META=m +CONFIG_NET_EMATCH_TEXT=m +CONFIG_NET_EMATCH_CANID=m +CONFIG_NET_EMATCH_IPSET=m +CONFIG_NET_EMATCH_IPT=m +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=y +CONFIG_NET_ACT_GACT=m +CONFIG_GACT_PROB=y +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_SAMPLE=m +CONFIG_NET_ACT_IPT=m +CONFIG_NET_ACT_NAT=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_ACT_SIMP=m +CONFIG_NET_ACT_SKBEDIT=m +CONFIG_NET_ACT_CSUM=m +CONFIG_NET_ACT_MPLS=m +CONFIG_NET_ACT_VLAN=m +CONFIG_NET_ACT_BPF=m +CONFIG_NET_ACT_CONNMARK=m +CONFIG_NET_ACT_CTINFO=m +# CONFIG_NET_ACT_SKBMOD is not set +CONFIG_NET_ACT_IFE=m +# CONFIG_NET_ACT_TUNNEL_KEY is not set +CONFIG_NET_ACT_CT=m +CONFIG_NET_IFE_SKBMARK=m +CONFIG_NET_IFE_SKBPRIO=m +CONFIG_NET_IFE_SKBTCINDEX=m +# CONFIG_NET_TC_SKB_EXT is not set +CONFIG_NET_SCH_FIFO=y +CONFIG_DCB=y +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV is not set +CONFIG_OPENVSWITCH=m +CONFIG_OPENVSWITCH_GRE=m +CONFIG_OPENVSWITCH_VXLAN=m +CONFIG_OPENVSWITCH_GENEVE=m +CONFIG_VSOCKETS=m +CONFIG_VSOCKETS_DIAG=m +CONFIG_VMWARE_VMCI_VSOCKETS=m +CONFIG_VIRTIO_VSOCKETS=m +CONFIG_VIRTIO_VSOCKETS_COMMON=m +CONFIG_HYPERV_VSOCKETS=m +CONFIG_NETLINK_DIAG=m +CONFIG_MPLS=y +CONFIG_NET_MPLS_GSO=y +CONFIG_MPLS_ROUTING=m +CONFIG_MPLS_IPTUNNEL=m +CONFIG_NET_NSH=m +CONFIG_HSR=m +CONFIG_NET_SWITCHDEV=y +CONFIG_NET_L3_MASTER_DEV=y +# CONFIG_NET_NCSI is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_CGROUP_NET_PRIO is not set +CONFIG_CGROUP_NET_CLASSID=y +CONFIG_NET_RX_BUSY_POLL=y +CONFIG_BQL=y +CONFIG_BPF_JIT=y +CONFIG_BPF_STREAM_PARSER=y +CONFIG_NET_FLOW_LIMIT=y + +# +# Network testing +# +CONFIG_NET_PKTGEN=m +# CONFIG_NET_DROP_MONITOR is not set +# end of Network testing +# end of Networking options + +CONFIG_HAMRADIO=y + +# +# Packet Radio protocols +# +CONFIG_AX25=m +CONFIG_AX25_DAMA_SLAVE=y +CONFIG_NETROM=m +CONFIG_ROSE=m + +# +# AX.25 network device drivers +# +CONFIG_MKISS=m +CONFIG_6PACK=m +CONFIG_BPQETHER=m +CONFIG_BAYCOM_SER_FDX=m +CONFIG_BAYCOM_SER_HDX=m +CONFIG_BAYCOM_PAR=m +CONFIG_YAM=m +# end of AX.25 network device drivers + +CONFIG_CAN=m +CONFIG_CAN_RAW=m +CONFIG_CAN_BCM=m +CONFIG_CAN_GW=m +# CONFIG_CAN_J1939 is not set + +# +# CAN Device Drivers +# +CONFIG_CAN_VCAN=m +CONFIG_CAN_VXCAN=m +CONFIG_CAN_SLCAN=m +CONFIG_CAN_DEV=m +# CONFIG_CAN_CALC_BITTIMING is not set +# CONFIG_CAN_KVASER_PCIEFD is not set +CONFIG_CAN_C_CAN=m +CONFIG_CAN_C_CAN_PLATFORM=m +CONFIG_CAN_C_CAN_PCI=m +CONFIG_CAN_CC770=m +CONFIG_CAN_CC770_ISA=m +CONFIG_CAN_CC770_PLATFORM=m +CONFIG_CAN_IFI_CANFD=m +CONFIG_CAN_M_CAN=m +# CONFIG_CAN_M_CAN_PLATFORM is not set +# CONFIG_CAN_M_CAN_TCAN4X5X is not set +CONFIG_CAN_PEAK_PCIEFD=m +CONFIG_CAN_SJA1000=m +CONFIG_CAN_EMS_PCI=m +CONFIG_CAN_EMS_PCMCIA=m +# CONFIG_CAN_F81601 is not set +CONFIG_CAN_KVASER_PCI=m +CONFIG_CAN_PEAK_PCI=m +CONFIG_CAN_PEAK_PCIEC=y +CONFIG_CAN_PEAK_PCMCIA=m +CONFIG_CAN_PLX_PCI=m +CONFIG_CAN_SJA1000_ISA=m +# CONFIG_CAN_SJA1000_PLATFORM is not set +CONFIG_CAN_SOFTING=m +CONFIG_CAN_SOFTING_CS=m + +# +# CAN SPI interfaces +# +# CONFIG_CAN_HI311X is not set +CONFIG_CAN_MCP251X=m +# end of CAN SPI interfaces + +# +# CAN USB interfaces +# +CONFIG_CAN_8DEV_USB=m +CONFIG_CAN_EMS_USB=m +CONFIG_CAN_ESD_USB2=m +CONFIG_CAN_GS_USB=m +CONFIG_CAN_KVASER_USB=m +# CONFIG_CAN_MCBA_USB is not set +CONFIG_CAN_PEAK_USB=m +# CONFIG_CAN_UCAN is not set +# end of CAN USB interfaces + +# CONFIG_CAN_DEBUG_DEVICES is not set +# end of CAN Device Drivers + +CONFIG_BT=m +CONFIG_BT_BREDR=y +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_CMTP=m +CONFIG_BT_HIDP=m +CONFIG_BT_HS=y +CONFIG_BT_LE=y +CONFIG_BT_6LOWPAN=m +CONFIG_BT_LEDS=y +# CONFIG_BT_SELFTEST is not set +# CONFIG_BT_DEBUGFS is not set + +# +# Bluetooth device drivers +# +CONFIG_BT_INTEL=m +CONFIG_BT_BCM=m +CONFIG_BT_RTL=m +CONFIG_BT_QCA=m +CONFIG_BT_HCIBTUSB=m +# CONFIG_BT_HCIBTUSB_AUTOSUSPEND is not set +CONFIG_BT_HCIBTUSB_BCM=y +CONFIG_BT_HCIBTUSB_MTK=y +CONFIG_BT_HCIBTUSB_RTL=y +CONFIG_BT_HCIBTSDIO=m +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_SERDEV=y +CONFIG_BT_HCIUART_H4=y +# CONFIG_BT_HCIUART_NOKIA is not set +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_ATH3K=y +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIUART_3WIRE=y +CONFIG_BT_HCIUART_INTEL=y +CONFIG_BT_HCIUART_RTL=y +CONFIG_BT_HCIUART_QCA=y +CONFIG_BT_HCIUART_AG6XX=y +CONFIG_BT_HCIUART_MRVL=y +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBPA10X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIDTL1=m +CONFIG_BT_HCIBT3C=m +CONFIG_BT_HCIBLUECARD=m +CONFIG_BT_HCIVHCI=m +CONFIG_BT_MRVL=m +CONFIG_BT_MRVL_SDIO=m +CONFIG_BT_ATH3K=m +CONFIG_BT_WILINK=m +CONFIG_BT_MTKSDIO=m +CONFIG_BT_MTKUART=m +CONFIG_BT_HCIRSI=m +# end of Bluetooth device drivers + +CONFIG_AF_RXRPC=m +CONFIG_AF_RXRPC_IPV6=y +# CONFIG_AF_RXRPC_INJECT_LOSS is not set +# CONFIG_AF_RXRPC_DEBUG is not set +# CONFIG_RXKAD is not set +CONFIG_AF_KCM=m +CONFIG_STREAM_PARSER=y +CONFIG_FIB_RULES=y +CONFIG_WIRELESS=y +CONFIG_WIRELESS_EXT=y +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PROC=y +CONFIG_WEXT_SPY=y +CONFIG_WEXT_PRIV=y +CONFIG_CFG80211=m +# CONFIG_NL80211_TESTMODE is not set +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +# CONFIG_CFG80211_CERTIFICATION_ONUS is not set +CONFIG_CFG80211_REQUIRE_SIGNED_REGDB=y +CONFIG_CFG80211_USE_KERNEL_REGDB_KEYS=y +CONFIG_CFG80211_DEFAULT_PS=y +# CONFIG_CFG80211_DEBUGFS is not set +CONFIG_CFG80211_CRDA_SUPPORT=y +CONFIG_CFG80211_WEXT=y +CONFIG_CFG80211_WEXT_EXPORT=y +CONFIG_LIB80211=m +CONFIG_LIB80211_CRYPT_WEP=m +CONFIG_LIB80211_CRYPT_CCMP=m +CONFIG_LIB80211_CRYPT_TKIP=m +# CONFIG_LIB80211_DEBUG is not set +CONFIG_MAC80211=m +CONFIG_MAC80211_HAS_RC=y +CONFIG_MAC80211_RC_MINSTREL=y +CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y +CONFIG_MAC80211_RC_DEFAULT="minstrel_ht" +CONFIG_MAC80211_MESH=y +CONFIG_MAC80211_LEDS=y +# CONFIG_MAC80211_DEBUGFS is not set +# CONFIG_MAC80211_MESSAGE_TRACING is not set +# CONFIG_MAC80211_DEBUG_MENU is not set +CONFIG_MAC80211_STA_HASH_MAX_SIZE=0 +CONFIG_WIMAX=m +CONFIG_WIMAX_DEBUG_LEVEL=8 +CONFIG_RFKILL=m +CONFIG_RFKILL_LEDS=y +CONFIG_RFKILL_INPUT=y +CONFIG_RFKILL_GPIO=m +CONFIG_NET_9P=m +CONFIG_NET_9P_VIRTIO=m +CONFIG_NET_9P_XEN=m +CONFIG_NET_9P_RDMA=m +# CONFIG_NET_9P_DEBUG is not set +CONFIG_CAIF=m +# CONFIG_CAIF_DEBUG is not set +CONFIG_CAIF_NETDEV=m +CONFIG_CAIF_USB=m +CONFIG_CEPH_LIB=m +# CONFIG_CEPH_LIB_PRETTYDEBUG is not set +# CONFIG_CEPH_LIB_USE_DNS_RESOLVER is not set +CONFIG_NFC=m +CONFIG_NFC_DIGITAL=m +CONFIG_NFC_NCI=m +# CONFIG_NFC_NCI_SPI is not set +CONFIG_NFC_NCI_UART=m +CONFIG_NFC_HCI=m +CONFIG_NFC_SHDLC=y + +# +# Near Field Communication (NFC) devices +# +CONFIG_NFC_TRF7970A=m +CONFIG_NFC_MEI_PHY=m +CONFIG_NFC_SIM=m +CONFIG_NFC_PORT100=m +CONFIG_NFC_FDP=m +CONFIG_NFC_FDP_I2C=m +CONFIG_NFC_PN544=m +CONFIG_NFC_PN544_I2C=m +CONFIG_NFC_PN544_MEI=m +CONFIG_NFC_PN533=m +CONFIG_NFC_PN533_USB=m +CONFIG_NFC_PN533_I2C=m +CONFIG_NFC_MICROREAD=m +CONFIG_NFC_MICROREAD_I2C=m +CONFIG_NFC_MICROREAD_MEI=m +CONFIG_NFC_MRVL=m +CONFIG_NFC_MRVL_USB=m +CONFIG_NFC_MRVL_UART=m +CONFIG_NFC_MRVL_I2C=m +CONFIG_NFC_ST21NFCA=m +CONFIG_NFC_ST21NFCA_I2C=m +CONFIG_NFC_ST_NCI=m +CONFIG_NFC_ST_NCI_I2C=m +CONFIG_NFC_ST_NCI_SPI=m +# CONFIG_NFC_NXP_NCI is not set +CONFIG_NFC_S3FWRN5=m +CONFIG_NFC_S3FWRN5_I2C=m +CONFIG_NFC_ST95HF=m +# end of Near Field Communication (NFC) devices + +CONFIG_PSAMPLE=m +CONFIG_NET_IFE=m +CONFIG_LWTUNNEL=y +CONFIG_LWTUNNEL_BPF=y +CONFIG_DST_CACHE=y +CONFIG_GRO_CELLS=y +CONFIG_NET_SOCK_MSG=y +CONFIG_NET_DEVLINK=y +CONFIG_PAGE_POOL=y +CONFIG_FAILOVER=m +CONFIG_HAVE_EBPF_JIT=y + +# +# Device Drivers +# +CONFIG_HAVE_EISA=y +# CONFIG_EISA is not set +CONFIG_HAVE_PCI=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCIEPORTBUS=y +CONFIG_HOTPLUG_PCI_PCIE=y +CONFIG_PCIEAER=y +# CONFIG_PCIEAER_INJECT is not set +CONFIG_PCIE_ECRC=y +CONFIG_PCIEASPM=y +# CONFIG_PCIEASPM_DEBUG is not set +CONFIG_PCIEASPM_DEFAULT=y +# CONFIG_PCIEASPM_POWERSAVE is not set +# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set +# CONFIG_PCIEASPM_PERFORMANCE is not set +CONFIG_PCIE_PME=y +CONFIG_PCIE_DPC=y +# CONFIG_PCIE_PTM is not set +# CONFIG_PCIE_BW is not set +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PCI_QUIRKS=y +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +CONFIG_PCI_STUB=m +CONFIG_PCI_PF_STUB=m +CONFIG_XEN_PCIDEV_FRONTEND=m +CONFIG_PCI_ATS=y +CONFIG_PCI_LOCKLESS_CONFIG=y +CONFIG_PCI_IOV=y +CONFIG_PCI_PRI=y +CONFIG_PCI_PASID=y +CONFIG_PCI_LABEL=y +CONFIG_PCI_HYPERV=m +CONFIG_HOTPLUG_PCI=y +CONFIG_HOTPLUG_PCI_ACPI=y +CONFIG_HOTPLUG_PCI_ACPI_IBM=m +CONFIG_HOTPLUG_PCI_CPCI=y +CONFIG_HOTPLUG_PCI_CPCI_ZT5550=m +CONFIG_HOTPLUG_PCI_CPCI_GENERIC=m +# CONFIG_HOTPLUG_PCI_SHPC is not set + +# +# PCI controller drivers +# + +# +# Cadence PCIe controllers support +# +# end of Cadence PCIe controllers support + +CONFIG_VMD=m +CONFIG_PCI_HYPERV_INTERFACE=m + +# +# DesignWare PCI Core Support +# +CONFIG_PCIE_DW=y +CONFIG_PCIE_DW_HOST=y +CONFIG_PCIE_DW_PLAT=y +CONFIG_PCIE_DW_PLAT_HOST=y +# CONFIG_PCI_MESON is not set +# end of DesignWare PCI Core Support +# end of PCI controller drivers + +# +# PCI Endpoint +# +# CONFIG_PCI_ENDPOINT is not set +# end of PCI Endpoint + +# +# PCI switch controller drivers +# +# CONFIG_PCI_SW_SWITCHTEC is not set +# end of PCI switch controller drivers + +CONFIG_PCCARD=m +CONFIG_PCMCIA=m +CONFIG_PCMCIA_LOAD_CIS=y +CONFIG_CARDBUS=y + +# +# PC-card bridges +# +CONFIG_YENTA=m +CONFIG_YENTA_O2=y +CONFIG_YENTA_RICOH=y +CONFIG_YENTA_TI=y +CONFIG_YENTA_ENE_TUNE=y +CONFIG_YENTA_TOSHIBA=y +CONFIG_PD6729=m +CONFIG_I82092=m +CONFIG_PCCARD_NONSTATIC=y +CONFIG_RAPIDIO=y +CONFIG_RAPIDIO_TSI721=y +CONFIG_RAPIDIO_DISC_TIMEOUT=30 +# CONFIG_RAPIDIO_ENABLE_RX_TX_PORTS is not set +CONFIG_RAPIDIO_DMA_ENGINE=y +# CONFIG_RAPIDIO_DEBUG is not set +CONFIG_RAPIDIO_ENUM_BASIC=m +CONFIG_RAPIDIO_CHMAN=m +CONFIG_RAPIDIO_MPORT_CDEV=m + +# +# RapidIO Switch drivers +# +CONFIG_RAPIDIO_TSI57X=y +CONFIG_RAPIDIO_CPS_XX=y +CONFIG_RAPIDIO_TSI568=y +CONFIG_RAPIDIO_CPS_GEN2=y +CONFIG_RAPIDIO_RXS_GEN3=y +# end of RapidIO Switch drivers + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER=y +CONFIG_UEVENT_HELPER_PATH="" +CONFIG_DEVTMPFS=y +# CONFIG_DEVTMPFS_MOUNT is not set +# CONFIG_STANDALONE is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y + +# +# Firmware loader +# +CONFIG_FW_LOADER=y +CONFIG_FW_LOADER_PAGED_BUF=y +CONFIG_EXTRA_FIRMWARE="" +CONFIG_FW_LOADER_USER_HELPER=y +# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set +CONFIG_FW_LOADER_COMPRESS=y +# end of Firmware loader + +CONFIG_WANT_DEV_COREDUMP=y +CONFIG_ALLOW_DEV_COREDUMP=y +CONFIG_DEV_COREDUMP=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set +# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set +CONFIG_SYS_HYPERVISOR=y +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_CPU_VULNERABILITIES=y +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_SPI=y +CONFIG_REGMAP_SPMI=m +CONFIG_REGMAP_MMIO=y +CONFIG_REGMAP_IRQ=y +CONFIG_REGMAP_SCCB=m +CONFIG_DMA_SHARED_BUFFER=y +# CONFIG_DMA_FENCE_TRACE is not set +# end of Generic Driver Options + +# +# Bus devices +# +# end of Bus devices + +CONFIG_CONNECTOR=m +CONFIG_GNSS=m +CONFIG_GNSS_SERIAL=m +# CONFIG_GNSS_MTK_SERIAL is not set +CONFIG_GNSS_SIRF_SERIAL=m +CONFIG_GNSS_UBX_SERIAL=m +CONFIG_MTD=m +CONFIG_MTD_TESTS=m + +# +# Partition parsers +# +CONFIG_MTD_AR7_PARTS=m +# CONFIG_MTD_CMDLINE_PARTS is not set +CONFIG_MTD_REDBOOT_PARTS=m +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# end of Partition parsers + +# +# User Modules And Translation Layers +# +CONFIG_MTD_BLKDEVS=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK_RO=m +CONFIG_FTL=m +CONFIG_NFTL=m +# CONFIG_NFTL_RW is not set +CONFIG_INFTL=m +CONFIG_RFD_FTL=m +CONFIG_SSFDC=m +CONFIG_SM_FTL=m +CONFIG_MTD_OOPS=m +CONFIG_MTD_SWAP=m +# CONFIG_MTD_PARTITIONED_MASTER is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_GEN_PROBE=m +# 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_CFI_I1=y +CONFIG_MTD_CFI_I2=y +CONFIG_MTD_CFI_INTELEXT=m +CONFIG_MTD_CFI_AMDSTD=m +CONFIG_MTD_CFI_STAA=m +CONFIG_MTD_CFI_UTIL=m +CONFIG_MTD_RAM=m +CONFIG_MTD_ROM=m +CONFIG_MTD_ABSENT=m +# end of RAM/ROM/Flash chip drivers + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_AMD76XROM=m +CONFIG_MTD_ICHXROM=m +CONFIG_MTD_ESB2ROM=m +CONFIG_MTD_CK804XROM=m +CONFIG_MTD_SCB2_FLASH=m +CONFIG_MTD_NETtel=m +CONFIG_MTD_L440GX=m +CONFIG_MTD_INTEL_VR_NOR=m +# CONFIG_MTD_PLATRAM is not set +# end of Mapping drivers for chip access + +# +# Self-contained MTD device drivers +# +CONFIG_MTD_PMC551=m +# CONFIG_MTD_PMC551_BUGFIX is not set +# CONFIG_MTD_PMC551_DEBUG is not set +CONFIG_MTD_DATAFLASH=m +# CONFIG_MTD_DATAFLASH_WRITE_VERIFY is not set +# CONFIG_MTD_DATAFLASH_OTP is not set +# CONFIG_MTD_MCHP23K256 is not set +CONFIG_MTD_SST25L=m +CONFIG_MTD_SLRAM=m +CONFIG_MTD_PHRAM=m +CONFIG_MTD_MTDRAM=m +CONFIG_MTDRAM_TOTAL_SIZE=4096 +CONFIG_MTDRAM_ERASE_SIZE=128 +CONFIG_MTD_BLOCK2MTD=m + +# +# Disk-On-Chip Device Drivers +# +CONFIG_MTD_DOCG3=m +CONFIG_BCH_CONST_M=14 +CONFIG_BCH_CONST_T=4 +# end of Self-contained MTD device drivers + +CONFIG_MTD_NAND_CORE=m +CONFIG_MTD_ONENAND=m +# CONFIG_MTD_ONENAND_VERIFY_WRITE is not set +# CONFIG_MTD_ONENAND_GENERIC is not set +CONFIG_MTD_ONENAND_OTP=y +CONFIG_MTD_ONENAND_2X_PROGRAM=y +CONFIG_MTD_NAND_ECC_SW_HAMMING=m +# CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC is not set +CONFIG_MTD_RAW_NAND=m +CONFIG_MTD_NAND_ECC_SW_BCH=y + +# +# Raw/parallel NAND flash controllers +# +CONFIG_MTD_NAND_DENALI=m +CONFIG_MTD_NAND_DENALI_PCI=m +CONFIG_MTD_NAND_CAFE=m +CONFIG_MTD_NAND_MXIC=m +CONFIG_MTD_NAND_GPIO=m +# CONFIG_MTD_NAND_PLATFORM is not set + +# +# Misc +# +CONFIG_MTD_SM_COMMON=m +CONFIG_MTD_NAND_NANDSIM=m +CONFIG_MTD_NAND_RICOH=m +CONFIG_MTD_NAND_DISKONCHIP=m +# CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED is not set +CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0 +# CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE is not set +CONFIG_MTD_SPI_NAND=m + +# +# LPDDR & LPDDR2 PCM memory drivers +# +CONFIG_MTD_LPDDR=m +CONFIG_MTD_QINFO_PROBE=m +# end of LPDDR & LPDDR2 PCM memory drivers + +CONFIG_MTD_SPI_NOR=m +CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=y +# CONFIG_SPI_MTK_QUADSPI is not set +# CONFIG_SPI_INTEL_SPI_PCI is not set +# CONFIG_SPI_INTEL_SPI_PLATFORM is not set +CONFIG_MTD_UBI=m +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MTD_UBI_BEB_LIMIT=20 +# CONFIG_MTD_UBI_FASTMAP is not set +# CONFIG_MTD_UBI_GLUEBI is not set +# CONFIG_MTD_UBI_BLOCK is not set +# CONFIG_MTD_HYPERBUS is not set +# CONFIG_OF is not set +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_SERIAL=m +CONFIG_PARPORT_PC_FIFO=y +CONFIG_PARPORT_PC_SUPERIO=y +CONFIG_PARPORT_PC_PCMCIA=m +# CONFIG_PARPORT_AX88796 is not set +CONFIG_PARPORT_1284=y +CONFIG_PARPORT_NOT_PC=y +CONFIG_PNP=y +CONFIG_PNP_DEBUG_MESSAGES=y + +# +# Protocols +# +CONFIG_PNPACPI=y +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_NULL_BLK is not set +CONFIG_BLK_DEV_FD=m +CONFIG_CDROM=y +CONFIG_PARIDE=m + +# +# Parallel IDE high-level drivers +# +CONFIG_PARIDE_PD=m +CONFIG_PARIDE_PCD=m +CONFIG_PARIDE_PF=m +CONFIG_PARIDE_PT=m +CONFIG_PARIDE_PG=m + +# +# Parallel IDE protocol modules +# +CONFIG_PARIDE_ATEN=m +CONFIG_PARIDE_BPCK=m +CONFIG_PARIDE_COMM=m +CONFIG_PARIDE_DSTR=m +CONFIG_PARIDE_FIT2=m +CONFIG_PARIDE_FIT3=m +CONFIG_PARIDE_EPAT=m +CONFIG_PARIDE_EPATC8=y +CONFIG_PARIDE_EPIA=m +CONFIG_PARIDE_FRIQ=m +CONFIG_PARIDE_FRPW=m +CONFIG_PARIDE_KBIC=m +CONFIG_PARIDE_KTTI=m +CONFIG_PARIDE_ON20=m +CONFIG_PARIDE_ON26=m +CONFIG_BLK_DEV_PCIESSD_MTIP32XX=m +CONFIG_ZRAM=m +# CONFIG_ZRAM_WRITEBACK is not set +# CONFIG_ZRAM_MEMORY_TRACKING is not set +CONFIG_BLK_DEV_UMEM=m +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +CONFIG_BLK_DEV_CRYPTOLOOP=m +# CONFIG_BLK_DEV_DRBD is not set +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_SKD=m +CONFIG_BLK_DEV_SX8=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=32000 +CONFIG_CDROM_PKTCDVD=y +CONFIG_CDROM_PKTCDVD_BUFFERS=8 +# CONFIG_CDROM_PKTCDVD_WCACHE is not set +CONFIG_ATA_OVER_ETH=m +CONFIG_XEN_BLKDEV_FRONTEND=m +CONFIG_XEN_BLKDEV_BACKEND=m +CONFIG_VIRTIO_BLK=m +# CONFIG_VIRTIO_BLK_SCSI is not set +CONFIG_BLK_DEV_RBD=m +CONFIG_BLK_DEV_RSXX=m + +# +# NVME Support +# +CONFIG_NVME_CORE=y +CONFIG_BLK_DEV_NVME=y +# CONFIG_NVME_MULTIPATH is not set +CONFIG_NVME_FABRICS=m +CONFIG_NVME_RDMA=m +CONFIG_NVME_FC=m +CONFIG_NVME_TCP=m +CONFIG_NVME_TARGET=m +CONFIG_NVME_TARGET_LOOP=m +CONFIG_NVME_TARGET_RDMA=m +CONFIG_NVME_TARGET_FC=m +# CONFIG_NVME_TARGET_FCLOOP is not set +CONFIG_NVME_TARGET_TCP=m +# end of NVME Support + +# +# Misc devices +# +CONFIG_SENSORS_LIS3LV02D=m +# CONFIG_AD525X_DPOT is not set +CONFIG_DUMMY_IRQ=m +CONFIG_IBM_ASM=m +CONFIG_PHANTOM=m +CONFIG_TIFM_CORE=m +CONFIG_TIFM_7XX1=m +CONFIG_ICS932S401=m +CONFIG_ENCLOSURE_SERVICES=m +CONFIG_HP_ILO=m +CONFIG_APDS9802ALS=m +# CONFIG_ISL29003 is not set +CONFIG_ISL29020=m +CONFIG_SENSORS_TSL2550=m +CONFIG_SENSORS_BH1770=m +CONFIG_SENSORS_APDS990X=m +CONFIG_HMC6352=m +CONFIG_DS1682=m +CONFIG_VMWARE_BALLOON=m +CONFIG_LATTICE_ECP3_CONFIG=m +CONFIG_SRAM=y +# CONFIG_PCI_ENDPOINT_TEST is not set +# CONFIG_XILINX_SDFEC is not set +CONFIG_MISC_RTSX=m +CONFIG_PVPANIC=m +CONFIG_C2PORT=m +CONFIG_C2PORT_DURAMAR_2150=m + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +CONFIG_EEPROM_AT25=m +CONFIG_EEPROM_LEGACY=m +CONFIG_EEPROM_MAX6875=m +CONFIG_EEPROM_93CX6=m +CONFIG_EEPROM_93XX46=m +CONFIG_EEPROM_IDT_89HPESX=m +CONFIG_EEPROM_EE1004=m +# end of EEPROM support + +CONFIG_CB710_CORE=m +# CONFIG_CB710_DEBUG is not set +CONFIG_CB710_DEBUG_ASSUMPTIONS=y + +# +# Texas Instruments shared transport line discipline +# +CONFIG_TI_ST=m +# end of Texas Instruments shared transport line discipline + +CONFIG_SENSORS_LIS3_I2C=m +CONFIG_ALTERA_STAPL=m +CONFIG_INTEL_MEI=m +CONFIG_INTEL_MEI_ME=m +CONFIG_INTEL_MEI_TXE=m +CONFIG_INTEL_MEI_HDCP=m +CONFIG_VMWARE_VMCI=m + +# +# Intel MIC & related support +# + +# +# Intel MIC Bus Driver +# +CONFIG_INTEL_MIC_BUS=m + +# +# SCIF Bus Driver +# +CONFIG_SCIF_BUS=m + +# +# VOP Bus Driver +# +# CONFIG_VOP_BUS is not set + +# +# Intel MIC Host Driver +# + +# +# Intel MIC Card Driver +# + +# +# SCIF Driver +# +CONFIG_SCIF=m + +# +# Intel MIC Coprocessor State Management (COSM) Drivers +# +CONFIG_MIC_COSM=m + +# +# VOP Driver +# +CONFIG_VHOST_RING=m +# end of Intel MIC & related support + +CONFIG_GENWQE=m +CONFIG_GENWQE_PLATFORM_ERROR_RECOVERY=1 +CONFIG_ECHO=m +CONFIG_MISC_ALCOR_PCI=m +CONFIG_MISC_RTSX_PCI=m +CONFIG_MISC_RTSX_USB=m +# CONFIG_HABANA_AI is not set +# end of Misc devices + +CONFIG_HAVE_IDE=y +CONFIG_IDE=m + +# +# Please see Documentation/ide/ide.rst for help/info on IDE drives +# +CONFIG_IDE_XFER_MODE=y +CONFIG_IDE_TIMINGS=y +CONFIG_IDE_ATAPI=y +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_IDE_GD=m +CONFIG_IDE_GD_ATA=y +CONFIG_IDE_GD_ATAPI=y +CONFIG_BLK_DEV_IDECS=m +CONFIG_BLK_DEV_DELKIN=m +CONFIG_BLK_DEV_IDECD=m +CONFIG_BLK_DEV_IDECD_VERBOSE_ERRORS=y +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEACPI=y +CONFIG_IDE_TASK_IOCTL=y +CONFIG_IDE_PROC_FS=y + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=m +# CONFIG_BLK_DEV_PLATFORM is not set +CONFIG_BLK_DEV_CMD640=m +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_IDEPNP is not set +CONFIG_BLK_DEV_IDEDMA_SFF=y + +# +# PCI IDE chipsets support +# +CONFIG_BLK_DEV_IDEPCI=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_GENERIC=m +CONFIG_BLK_DEV_OPTI621=m +CONFIG_BLK_DEV_RZ1000=m +CONFIG_BLK_DEV_IDEDMA_PCI=y +CONFIG_BLK_DEV_AEC62XX=m +CONFIG_BLK_DEV_ALI15X3=m +CONFIG_BLK_DEV_AMD74XX=m +CONFIG_BLK_DEV_ATIIXP=m +CONFIG_BLK_DEV_CMD64X=m +CONFIG_BLK_DEV_TRIFLEX=m +CONFIG_BLK_DEV_HPT366=m +CONFIG_BLK_DEV_JMICRON=m +CONFIG_BLK_DEV_PIIX=m +CONFIG_BLK_DEV_IT8172=m +CONFIG_BLK_DEV_IT8213=m +CONFIG_BLK_DEV_IT821X=m +CONFIG_BLK_DEV_NS87415=m +CONFIG_BLK_DEV_PDC202XX_OLD=m +CONFIG_BLK_DEV_PDC202XX_NEW=m +CONFIG_BLK_DEV_SVWKS=m +CONFIG_BLK_DEV_SIIMAGE=m +CONFIG_BLK_DEV_SIS5513=m +CONFIG_BLK_DEV_SLC90E66=m +CONFIG_BLK_DEV_TRM290=m +CONFIG_BLK_DEV_VIA82CXXX=m +CONFIG_BLK_DEV_TC86C001=m +CONFIG_BLK_DEV_IDEDMA=y + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +CONFIG_RAID_ATTRS=m +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_NETLINK=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=m +CONFIG_BLK_DEV_SR=m +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=m +CONFIG_CHR_DEV_SCH=m +CONFIG_SCSI_ENCLOSURE=m +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_ISCSI_ATTRS=m +CONFIG_SCSI_SAS_ATTRS=m +CONFIG_SCSI_SAS_LIBSAS=m +CONFIG_SCSI_SAS_ATA=y +CONFIG_SCSI_SAS_HOST_SMP=y +CONFIG_SCSI_SRP_ATTRS=m +# end of SCSI Transports + +CONFIG_SCSI_LOWLEVEL=y +CONFIG_ISCSI_TCP=m +CONFIG_ISCSI_BOOT_SYSFS=m +CONFIG_SCSI_CXGB3_ISCSI=m +CONFIG_SCSI_CXGB4_ISCSI=m +CONFIG_SCSI_BNX2_ISCSI=m +CONFIG_SCSI_BNX2X_FCOE=m +CONFIG_BE2ISCSI=m +CONFIG_BLK_DEV_3W_XXXX_RAID=m +CONFIG_SCSI_HPSA=m +CONFIG_SCSI_3W_9XXX=m +CONFIG_SCSI_3W_SAS=m +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_AIC7XXX=m +CONFIG_AIC7XXX_CMDS_PER_DEVICE=253 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +# CONFIG_AIC7XXX_DEBUG_ENABLE is not set +CONFIG_AIC7XXX_DEBUG_MASK=0 +CONFIG_AIC7XXX_REG_PRETTY_PRINT=y +CONFIG_SCSI_AIC79XX=m +CONFIG_AIC79XX_CMDS_PER_DEVICE=32 +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +# CONFIG_AIC79XX_DEBUG_ENABLE is not set +CONFIG_AIC79XX_DEBUG_MASK=0 +CONFIG_AIC79XX_REG_PRETTY_PRINT=y +CONFIG_SCSI_AIC94XX=m +CONFIG_AIC94XX_DEBUG=y +CONFIG_SCSI_MVSAS=m +CONFIG_SCSI_MVSAS_DEBUG=y +# CONFIG_SCSI_MVSAS_TASKLET is not set +CONFIG_SCSI_MVUMI=m +CONFIG_SCSI_DPT_I2O=m +CONFIG_SCSI_ADVANSYS=m +CONFIG_SCSI_ARCMSR=m +CONFIG_SCSI_ESAS2R=m +CONFIG_MEGARAID_NEWGEN=y +CONFIG_MEGARAID_MM=m +CONFIG_MEGARAID_MAILBOX=m +CONFIG_MEGARAID_LEGACY=m +CONFIG_MEGARAID_SAS=m +CONFIG_SCSI_MPT3SAS=m +CONFIG_SCSI_MPT2SAS_MAX_SGE=128 +CONFIG_SCSI_MPT3SAS_MAX_SGE=128 +CONFIG_SCSI_MPT2SAS=m +CONFIG_SCSI_SMARTPQI=m +CONFIG_SCSI_UFSHCD=m +CONFIG_SCSI_UFSHCD_PCI=m +# CONFIG_SCSI_UFS_DWC_TC_PCI is not set +# CONFIG_SCSI_UFSHCD_PLATFORM is not set +CONFIG_SCSI_UFS_BSG=y +CONFIG_SCSI_HPTIOP=m +CONFIG_SCSI_BUSLOGIC=m +CONFIG_SCSI_FLASHPOINT=y +CONFIG_SCSI_MYRB=m +CONFIG_SCSI_MYRS=m +CONFIG_VMWARE_PVSCSI=m +CONFIG_XEN_SCSI_FRONTEND=m +CONFIG_HYPERV_STORAGE=m +CONFIG_LIBFC=m +CONFIG_LIBFCOE=m +CONFIG_FCOE=m +CONFIG_FCOE_FNIC=m +CONFIG_SCSI_SNIC=m +# CONFIG_SCSI_SNIC_DEBUG_FS is not set +CONFIG_SCSI_DMX3191D=m +CONFIG_SCSI_FDOMAIN=m +CONFIG_SCSI_FDOMAIN_PCI=m +CONFIG_SCSI_GDTH=m +CONFIG_SCSI_ISCI=m +CONFIG_SCSI_IPS=m +CONFIG_SCSI_INITIO=m +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_PPA=m +CONFIG_SCSI_IMM=m +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set +CONFIG_SCSI_STEX=m +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +CONFIG_SCSI_SYM53C8XX_MMIO=y +CONFIG_SCSI_IPR=m +# CONFIG_SCSI_IPR_TRACE is not set +# CONFIG_SCSI_IPR_DUMP is not set +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_QLA_FC=m +CONFIG_TCM_QLA2XXX=m +# CONFIG_TCM_QLA2XXX_DEBUG is not set +CONFIG_SCSI_QLA_ISCSI=m +CONFIG_QEDI=m +CONFIG_QEDF=m +CONFIG_SCSI_LPFC=m +# CONFIG_SCSI_LPFC_DEBUG_FS is not set +CONFIG_SCSI_DC395x=m +CONFIG_SCSI_AM53C974=m +CONFIG_SCSI_WD719X=m +CONFIG_SCSI_DEBUG=m +CONFIG_SCSI_PMCRAID=m +CONFIG_SCSI_PM8001=m +CONFIG_SCSI_BFA_FC=m +CONFIG_SCSI_VIRTIO=m +CONFIG_SCSI_CHELSIO_FCOE=m +CONFIG_SCSI_LOWLEVEL_PCMCIA=y +CONFIG_PCMCIA_AHA152X=m +CONFIG_PCMCIA_FDOMAIN=m +CONFIG_PCMCIA_QLOGIC=m +CONFIG_PCMCIA_SYM53C500=m +CONFIG_SCSI_DH=y +CONFIG_SCSI_DH_RDAC=m +CONFIG_SCSI_DH_HP_SW=m +CONFIG_SCSI_DH_EMC=m +CONFIG_SCSI_DH_ALUA=m +# end of SCSI device support + +CONFIG_ATA=y +CONFIG_ATA_VERBOSE_ERROR=y +CONFIG_ATA_ACPI=y +CONFIG_SATA_ZPODD=y +CONFIG_SATA_PMP=y + +# +# Controllers with non-SFF native interface +# +CONFIG_SATA_AHCI=y +CONFIG_SATA_MOBILE_LPM_POLICY=0 +CONFIG_SATA_AHCI_PLATFORM=y +# CONFIG_SATA_INIC162X is not set +CONFIG_SATA_ACARD_AHCI=m +CONFIG_SATA_SIL24=m +CONFIG_ATA_SFF=y + +# +# SFF controllers with custom DMA interface +# +CONFIG_PDC_ADMA=m +CONFIG_SATA_QSTOR=m +CONFIG_SATA_SX4=m +CONFIG_ATA_BMDMA=y + +# +# SATA SFF controllers with BMDMA +# +CONFIG_ATA_PIIX=m +# CONFIG_SATA_DWC is not set +CONFIG_SATA_MV=m +CONFIG_SATA_NV=m +CONFIG_SATA_PROMISE=m +CONFIG_SATA_SIL=m +CONFIG_SATA_SIS=m +CONFIG_SATA_SVW=m +CONFIG_SATA_ULI=m +CONFIG_SATA_VIA=m +CONFIG_SATA_VITESSE=m + +# +# PATA SFF controllers with BMDMA +# +CONFIG_PATA_ALI=m +CONFIG_PATA_AMD=m +CONFIG_PATA_ARTOP=m +CONFIG_PATA_ATIIXP=m +CONFIG_PATA_ATP867X=m +CONFIG_PATA_CMD64X=m +CONFIG_PATA_CYPRESS=m +CONFIG_PATA_EFAR=m +CONFIG_PATA_HPT366=m +CONFIG_PATA_HPT37X=m +CONFIG_PATA_HPT3X2N=m +CONFIG_PATA_HPT3X3=m +CONFIG_PATA_HPT3X3_DMA=y +CONFIG_PATA_IT8213=m +CONFIG_PATA_IT821X=m +CONFIG_PATA_JMICRON=m +CONFIG_PATA_MARVELL=m +CONFIG_PATA_NETCELL=m +CONFIG_PATA_NINJA32=m +CONFIG_PATA_NS87415=m +CONFIG_PATA_OLDPIIX=m +CONFIG_PATA_OPTIDMA=m +CONFIG_PATA_PDC2027X=m +CONFIG_PATA_PDC_OLD=m +CONFIG_PATA_RADISYS=m +CONFIG_PATA_RDC=m +CONFIG_PATA_SCH=m +CONFIG_PATA_SERVERWORKS=m +CONFIG_PATA_SIL680=m +CONFIG_PATA_SIS=m +CONFIG_PATA_TOSHIBA=m +CONFIG_PATA_TRIFLEX=m +CONFIG_PATA_VIA=m +CONFIG_PATA_WINBOND=m + +# +# PIO-only SFF controllers +# +CONFIG_PATA_CMD640_PCI=m +CONFIG_PATA_MPIIX=m +CONFIG_PATA_NS87410=m +CONFIG_PATA_OPTI=m +CONFIG_PATA_PCMCIA=m +# CONFIG_PATA_PLATFORM is not set +CONFIG_PATA_RZ1000=m + +# +# Generic fallback / legacy drivers +# +CONFIG_PATA_ACPI=m +CONFIG_ATA_GENERIC=m +CONFIG_PATA_LEGACY=m +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +# CONFIG_MD_AUTODETECT is not set +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +CONFIG_MD_MULTIPATH=m +CONFIG_MD_FAULTY=m +CONFIG_MD_CLUSTER=m +CONFIG_BCACHE=m +# CONFIG_BCACHE_DEBUG is not set +# CONFIG_BCACHE_CLOSURES_DEBUG is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=m +# CONFIG_DM_DEBUG is not set +CONFIG_DM_BUFIO=m +# CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING is not set +CONFIG_DM_BIO_PRISON=m +CONFIG_DM_PERSISTENT_DATA=m +CONFIG_DM_UNSTRIPED=m +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_THIN_PROVISIONING=m +CONFIG_DM_CACHE=m +CONFIG_DM_CACHE_SMQ=m +CONFIG_DM_WRITECACHE=m +CONFIG_DM_ERA=m +CONFIG_DM_CLONE=m +CONFIG_DM_MIRROR=m +CONFIG_DM_LOG_USERSPACE=m +CONFIG_DM_RAID=m +CONFIG_DM_ZERO=m +CONFIG_DM_MULTIPATH=m +CONFIG_DM_MULTIPATH_QL=m +CONFIG_DM_MULTIPATH_ST=m +# CONFIG_DM_DELAY is not set +# CONFIG_DM_DUST is not set +CONFIG_DM_UEVENT=y +CONFIG_DM_FLAKEY=m +CONFIG_DM_VERITY=m +# CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG is not set +# CONFIG_DM_VERITY_FEC is not set +CONFIG_DM_SWITCH=m +CONFIG_DM_LOG_WRITES=m +CONFIG_DM_INTEGRITY=m +CONFIG_TARGET_CORE=m +CONFIG_TCM_IBLOCK=m +CONFIG_TCM_FILEIO=m +CONFIG_TCM_PSCSI=m +CONFIG_TCM_USER2=m +CONFIG_LOOPBACK_TARGET=m +CONFIG_TCM_FC=m +CONFIG_ISCSI_TARGET=m +CONFIG_ISCSI_TARGET_CXGB4=m +CONFIG_SBP_TARGET=m +CONFIG_FUSION=y +CONFIG_FUSION_SPI=m +CONFIG_FUSION_FC=m +CONFIG_FUSION_SAS=m +CONFIG_FUSION_MAX_SGE=128 +CONFIG_FUSION_CTL=m +CONFIG_FUSION_LAN=m +CONFIG_FUSION_LOGGING=y + +# +# IEEE 1394 (FireWire) support +# +CONFIG_FIREWIRE=m +CONFIG_FIREWIRE_OHCI=m +CONFIG_FIREWIRE_SBP2=m +CONFIG_FIREWIRE_NET=m +CONFIG_FIREWIRE_NOSY=m +# end of IEEE 1394 (FireWire) support + +CONFIG_MACINTOSH_DRIVERS=y +CONFIG_MAC_EMUMOUSEBTN=y +CONFIG_NETDEVICES=y +CONFIG_MII=m +CONFIG_NET_CORE=y +CONFIG_BONDING=m +CONFIG_DUMMY=m +CONFIG_EQUALIZER=m +CONFIG_NET_FC=y +CONFIG_IFB=m +CONFIG_NET_TEAM=m +CONFIG_NET_TEAM_MODE_BROADCAST=m +CONFIG_NET_TEAM_MODE_ROUNDROBIN=m +CONFIG_NET_TEAM_MODE_RANDOM=m +CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m +CONFIG_NET_TEAM_MODE_LOADBALANCE=m +CONFIG_MACVLAN=m +CONFIG_MACVTAP=m +CONFIG_IPVLAN_L3S=y +CONFIG_IPVLAN=m +CONFIG_IPVTAP=m +CONFIG_VXLAN=m +CONFIG_GENEVE=m +CONFIG_GTP=m +CONFIG_MACSEC=m +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_NETPOLL=y +CONFIG_NET_POLL_CONTROLLER=y +CONFIG_NTB_NETDEV=m +CONFIG_RIONET=m +CONFIG_RIONET_TX_SIZE=128 +CONFIG_RIONET_RX_SIZE=128 +CONFIG_TUN=m +CONFIG_TAP=m +# CONFIG_TUN_VNET_CROSS_LE is not set +CONFIG_VETH=m +CONFIG_VIRTIO_NET=m +CONFIG_NLMON=m +CONFIG_NET_VRF=m +CONFIG_VSOCKMON=m +CONFIG_SUNGEM_PHY=m +CONFIG_ARCNET=m +CONFIG_ARCNET_1201=m +CONFIG_ARCNET_1051=m +CONFIG_ARCNET_RAW=m +CONFIG_ARCNET_CAP=m +CONFIG_ARCNET_COM90xx=m +CONFIG_ARCNET_COM90xxIO=m +CONFIG_ARCNET_RIM_I=m +CONFIG_ARCNET_COM20020=m +CONFIG_ARCNET_COM20020_PCI=m +CONFIG_ARCNET_COM20020_CS=m +CONFIG_ATM_DRIVERS=y +# CONFIG_ATM_DUMMY is not set +CONFIG_ATM_TCP=m +CONFIG_ATM_LANAI=m +CONFIG_ATM_ENI=m +# CONFIG_ATM_ENI_DEBUG is not set +# CONFIG_ATM_ENI_TUNE_BURST is not set +CONFIG_ATM_FIRESTREAM=m +CONFIG_ATM_ZATM=m +# CONFIG_ATM_ZATM_DEBUG is not set +# CONFIG_ATM_NICSTAR is not set +CONFIG_ATM_IDT77252=m +# CONFIG_ATM_IDT77252_DEBUG is not set +# CONFIG_ATM_IDT77252_RCV_ALL is not set +CONFIG_ATM_IDT77252_USE_SUNI=y +CONFIG_ATM_AMBASSADOR=m +# CONFIG_ATM_AMBASSADOR_DEBUG is not set +CONFIG_ATM_HORIZON=m +# CONFIG_ATM_HORIZON_DEBUG is not set +CONFIG_ATM_IA=m +# CONFIG_ATM_IA_DEBUG is not set +CONFIG_ATM_FORE200E=m +CONFIG_ATM_FORE200E_USE_TASKLET=y +CONFIG_ATM_FORE200E_TX_RETRY=16 +CONFIG_ATM_FORE200E_DEBUG=0 +CONFIG_ATM_HE=m +CONFIG_ATM_HE_USE_SUNI=y +CONFIG_ATM_SOLOS=m + +# +# CAIF transport drivers +# +CONFIG_CAIF_TTY=m +CONFIG_CAIF_SPI_SLAVE=m +# CONFIG_CAIF_SPI_SYNC is not set +CONFIG_CAIF_HSI=m +CONFIG_CAIF_VIRTIO=m + +# +# Distributed Switch Architecture drivers +# +CONFIG_B53=m +CONFIG_B53_SPI_DRIVER=m +CONFIG_B53_MDIO_DRIVER=m +CONFIG_B53_MMAP_DRIVER=m +CONFIG_B53_SRAB_DRIVER=m +CONFIG_B53_SERDES=m +CONFIG_NET_DSA_BCM_SF2=m +# CONFIG_NET_DSA_LOOP is not set +CONFIG_NET_DSA_LANTIQ_GSWIP=m +# CONFIG_NET_DSA_MT7530 is not set +CONFIG_NET_DSA_MV88E6060=m +# CONFIG_NET_DSA_MICROCHIP_KSZ9477 is not set +# CONFIG_NET_DSA_MICROCHIP_KSZ8795 is not set +# CONFIG_NET_DSA_MV88E6XXX is not set +# CONFIG_NET_DSA_SJA1105 is not set +# CONFIG_NET_DSA_QCA8K is not set +CONFIG_NET_DSA_REALTEK_SMI=m +# CONFIG_NET_DSA_SMSC_LAN9303_I2C is not set +# CONFIG_NET_DSA_SMSC_LAN9303_MDIO is not set +# end of Distributed Switch Architecture drivers + +CONFIG_ETHERNET=y +CONFIG_MDIO=m +CONFIG_NET_VENDOR_3COM=y +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_3C589=m +CONFIG_VORTEX=m +CONFIG_TYPHOON=m +CONFIG_NET_VENDOR_ADAPTEC=y +CONFIG_ADAPTEC_STARFIRE=m +CONFIG_NET_VENDOR_AGERE=y +CONFIG_ET131X=m +CONFIG_NET_VENDOR_ALACRITECH=y +CONFIG_SLICOSS=m +CONFIG_NET_VENDOR_ALTEON=y +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +CONFIG_ALTERA_TSE=m +CONFIG_NET_VENDOR_AMAZON=y +CONFIG_ENA_ETHERNET=m +CONFIG_NET_VENDOR_AMD=y +CONFIG_AMD8111_ETH=m +CONFIG_PCNET32=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_AMD_XGBE=m +CONFIG_AMD_XGBE_DCB=y +CONFIG_AMD_XGBE_HAVE_ECC=y +CONFIG_NET_VENDOR_AQUANTIA=y +CONFIG_AQTION=m +CONFIG_NET_VENDOR_ARC=y +CONFIG_NET_VENDOR_ATHEROS=y +CONFIG_ATL2=m +CONFIG_ATL1=m +CONFIG_ATL1E=m +CONFIG_ATL1C=m +CONFIG_ALX=m +CONFIG_NET_VENDOR_AURORA=y +CONFIG_AURORA_NB8800=m +CONFIG_NET_VENDOR_BROADCOM=y +CONFIG_B44=m +CONFIG_B44_PCI_AUTOSELECT=y +CONFIG_B44_PCICORE_AUTOSELECT=y +CONFIG_B44_PCI=y +CONFIG_BCMGENET=m +CONFIG_BNX2=m +CONFIG_CNIC=m +CONFIG_TIGON3=m +CONFIG_TIGON3_HWMON=y +CONFIG_BNX2X=m +CONFIG_BNX2X_SRIOV=y +CONFIG_SYSTEMPORT=m +CONFIG_BNXT=m +CONFIG_BNXT_SRIOV=y +CONFIG_BNXT_FLOWER_OFFLOAD=y +CONFIG_BNXT_DCB=y +CONFIG_BNXT_HWMON=y +CONFIG_NET_VENDOR_BROCADE=y +CONFIG_BNA=m +CONFIG_NET_VENDOR_CADENCE=y +CONFIG_MACB=m +CONFIG_MACB_USE_HWSTAMP=y +CONFIG_MACB_PCI=m +CONFIG_NET_VENDOR_CAVIUM=y +CONFIG_THUNDER_NIC_PF=m +CONFIG_THUNDER_NIC_VF=m +CONFIG_THUNDER_NIC_BGX=m +CONFIG_THUNDER_NIC_RGX=m +CONFIG_CAVIUM_PTP=m +CONFIG_LIQUIDIO=m +CONFIG_LIQUIDIO_VF=m +CONFIG_NET_VENDOR_CHELSIO=y +CONFIG_CHELSIO_T1=m +CONFIG_CHELSIO_T1_1G=y +CONFIG_CHELSIO_T3=m +CONFIG_CHELSIO_T4=m +CONFIG_CHELSIO_T4_DCB=y +CONFIG_CHELSIO_T4_FCOE=y +CONFIG_CHELSIO_T4VF=m +CONFIG_CHELSIO_LIB=m +CONFIG_NET_VENDOR_CISCO=y +CONFIG_ENIC=m +CONFIG_NET_VENDOR_CORTINA=y +CONFIG_CX_ECAT=m +# CONFIG_DNET is not set +CONFIG_NET_VENDOR_DEC=y +CONFIG_NET_TULIP=y +CONFIG_DE2104X=m +CONFIG_DE2104X_DSL=0 +CONFIG_TULIP=m +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_MMIO is not set +# CONFIG_TULIP_NAPI is not set +CONFIG_DE4X5=m +CONFIG_WINBOND_840=m +CONFIG_DM9102=m +CONFIG_ULI526X=m +CONFIG_PCMCIA_XIRCOM=m +CONFIG_NET_VENDOR_DLINK=y +CONFIG_DL2K=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set +CONFIG_NET_VENDOR_EMULEX=y +CONFIG_BE2NET=m +CONFIG_BE2NET_HWMON=y +CONFIG_BE2NET_BE2=y +CONFIG_BE2NET_BE3=y +CONFIG_BE2NET_LANCER=y +CONFIG_BE2NET_SKYHAWK=y +CONFIG_NET_VENDOR_EZCHIP=y +CONFIG_NET_VENDOR_FUJITSU=y +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_NET_VENDOR_GOOGLE=y +CONFIG_GVE=m +CONFIG_NET_VENDOR_HP=y +CONFIG_HP100=m +CONFIG_NET_VENDOR_HUAWEI=y +CONFIG_HINIC=m +CONFIG_NET_VENDOR_I825XX=y +CONFIG_NET_VENDOR_INTEL=y +CONFIG_E100=m +CONFIG_E1000=m +CONFIG_E1000E=m +CONFIG_E1000E_HWTS=y +CONFIG_IGB=m +CONFIG_IGB_HWMON=y +CONFIG_IGB_DCA=y +CONFIG_IGBVF=m +CONFIG_IXGB=m +CONFIG_IXGBE=m +CONFIG_IXGBE_HWMON=y +CONFIG_IXGBE_DCA=y +CONFIG_IXGBE_DCB=y +CONFIG_IXGBE_IPSEC=y +CONFIG_IXGBEVF=m +CONFIG_IXGBEVF_IPSEC=y +CONFIG_I40E=m +CONFIG_I40E_DCB=y +CONFIG_IAVF=m +CONFIG_I40EVF=m +CONFIG_ICE=m +CONFIG_FM10K=m +CONFIG_IGC=m +CONFIG_JME=m +CONFIG_NET_VENDOR_MARVELL=y +CONFIG_MVMDIO=m +CONFIG_SKGE=m +# CONFIG_SKGE_DEBUG is not set +CONFIG_SKGE_GENESIS=y +CONFIG_SKY2=m +# CONFIG_SKY2_DEBUG is not set +CONFIG_NET_VENDOR_MELLANOX=y +CONFIG_MLX4_EN=m +CONFIG_MLX4_EN_DCB=y +CONFIG_MLX4_CORE=m +# CONFIG_MLX4_DEBUG is not set +CONFIG_MLX4_CORE_GEN2=y +CONFIG_MLX5_CORE=m +CONFIG_MLX5_ACCEL=y +CONFIG_MLX5_FPGA=y +CONFIG_MLX5_CORE_EN=y +CONFIG_MLX5_EN_ARFS=y +CONFIG_MLX5_EN_RXNFC=y +CONFIG_MLX5_MPFS=y +CONFIG_MLX5_ESWITCH=y +CONFIG_MLX5_CORE_EN_DCB=y +# CONFIG_MLX5_CORE_IPOIB is not set +CONFIG_MLX5_FPGA_IPSEC=y +# CONFIG_MLX5_EN_IPSEC is not set +CONFIG_MLX5_SW_STEERING=y +CONFIG_MLXSW_CORE=m +CONFIG_MLXSW_CORE_HWMON=y +CONFIG_MLXSW_CORE_THERMAL=y +CONFIG_MLXSW_PCI=m +CONFIG_MLXSW_I2C=m +CONFIG_MLXSW_SWITCHIB=m +CONFIG_MLXSW_SWITCHX2=m +CONFIG_MLXSW_SPECTRUM=m +CONFIG_MLXSW_SPECTRUM_DCB=y +CONFIG_MLXSW_MINIMAL=m +CONFIG_MLXFW=m +CONFIG_NET_VENDOR_MICREL=y +CONFIG_KS8842=m +CONFIG_KS8851=m +# CONFIG_KS8851_MLL is not set +CONFIG_KSZ884X_PCI=m +CONFIG_NET_VENDOR_MICROCHIP=y +CONFIG_ENC28J60=m +# CONFIG_ENC28J60_WRITEVERIFY is not set +CONFIG_ENCX24J600=m +CONFIG_LAN743X=m +CONFIG_NET_VENDOR_MICROSEMI=y +CONFIG_MSCC_OCELOT_SWITCH=m +CONFIG_NET_VENDOR_MYRI=y +CONFIG_MYRI10GE=m +CONFIG_MYRI10GE_DCA=y +CONFIG_FEALNX=m +CONFIG_NET_VENDOR_NATSEMI=y +CONFIG_NATSEMI=m +CONFIG_NS83820=m +CONFIG_NET_VENDOR_NETERION=y +CONFIG_S2IO=m +CONFIG_VXGE=m +# CONFIG_VXGE_DEBUG_TRACE_ALL is not set +CONFIG_NET_VENDOR_NETRONOME=y +CONFIG_NFP=m +# CONFIG_NFP_APP_FLOWER is not set +CONFIG_NFP_APP_ABM_NIC=y +# CONFIG_NFP_DEBUG is not set +CONFIG_NET_VENDOR_NI=y +CONFIG_NI_XGE_MANAGEMENT_ENET=m +CONFIG_NET_VENDOR_8390=y +CONFIG_PCMCIA_AXNET=m +CONFIG_NE2K_PCI=m +CONFIG_PCMCIA_PCNET=m +CONFIG_NET_VENDOR_NVIDIA=y +CONFIG_FORCEDETH=m +CONFIG_NET_VENDOR_OKI=y +CONFIG_ETHOC=m +CONFIG_NET_VENDOR_PACKET_ENGINES=y +CONFIG_HAMACHI=m +CONFIG_YELLOWFIN=m +CONFIG_NET_VENDOR_PENSANDO=y +CONFIG_IONIC=m +CONFIG_NET_VENDOR_QLOGIC=y +CONFIG_QLA3XXX=m +CONFIG_QLCNIC=m +CONFIG_QLCNIC_SRIOV=y +CONFIG_QLCNIC_DCB=y +CONFIG_QLCNIC_HWMON=y +CONFIG_NETXEN_NIC=m +CONFIG_QED=m +CONFIG_QED_LL2=y +CONFIG_QED_SRIOV=y +CONFIG_QEDE=m +CONFIG_QED_RDMA=y +CONFIG_QED_ISCSI=y +CONFIG_QED_FCOE=y +CONFIG_QED_OOO=y +CONFIG_NET_VENDOR_QUALCOMM=y +CONFIG_QCOM_EMAC=m +CONFIG_RMNET=m +CONFIG_NET_VENDOR_RDC=y +CONFIG_R6040=m +CONFIG_NET_VENDOR_REALTEK=y +CONFIG_ATP=m +CONFIG_8139CP=m +CONFIG_8139TOO=m +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +CONFIG_8139TOO_8129=y +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_R8169=m +CONFIG_NET_VENDOR_RENESAS=y +CONFIG_NET_VENDOR_ROCKER=y +# CONFIG_ROCKER is not set +CONFIG_NET_VENDOR_SAMSUNG=y +CONFIG_SXGBE_ETH=m +CONFIG_NET_VENDOR_SEEQ=y +CONFIG_NET_VENDOR_SOLARFLARE=y +CONFIG_SFC=m +CONFIG_SFC_MTD=y +CONFIG_SFC_MCDI_MON=y +CONFIG_SFC_SRIOV=y +CONFIG_SFC_MCDI_LOGGING=y +CONFIG_SFC_FALCON=m +CONFIG_SFC_FALCON_MTD=y +CONFIG_NET_VENDOR_SILAN=y +CONFIG_SC92031=m +CONFIG_NET_VENDOR_SIS=y +CONFIG_SIS900=m +CONFIG_SIS190=m +CONFIG_NET_VENDOR_SMSC=y +CONFIG_PCMCIA_SMC91C92=m +CONFIG_EPIC100=m +CONFIG_SMSC911X=m +CONFIG_SMSC9420=m +CONFIG_NET_VENDOR_SOCIONEXT=y +CONFIG_NET_VENDOR_STMICRO=y +CONFIG_STMMAC_ETH=m +# CONFIG_STMMAC_SELFTESTS is not set +CONFIG_STMMAC_PLATFORM=m +CONFIG_DWMAC_GENERIC=m +# CONFIG_STMMAC_PCI is not set +CONFIG_NET_VENDOR_SUN=y +CONFIG_HAPPYMEAL=m +CONFIG_SUNGEM=m +CONFIG_CASSINI=m +CONFIG_NIU=m +CONFIG_NET_VENDOR_SYNOPSYS=y +CONFIG_DWC_XLGMAC=m +CONFIG_DWC_XLGMAC_PCI=m +CONFIG_NET_VENDOR_TEHUTI=y +CONFIG_TEHUTI=m +CONFIG_NET_VENDOR_TI=y +# CONFIG_TI_CPSW_PHY_SEL is not set +CONFIG_TLAN=m +CONFIG_NET_VENDOR_VIA=y +CONFIG_VIA_RHINE=m +# CONFIG_VIA_RHINE_MMIO is not set +CONFIG_VIA_VELOCITY=m +CONFIG_NET_VENDOR_WIZNET=y +CONFIG_WIZNET_W5100=m +CONFIG_WIZNET_W5300=m +# CONFIG_WIZNET_BUS_DIRECT is not set +# CONFIG_WIZNET_BUS_INDIRECT is not set +CONFIG_WIZNET_BUS_ANY=y +CONFIG_WIZNET_W5100_SPI=m +CONFIG_NET_VENDOR_XILINX=y +CONFIG_XILINX_AXI_EMAC=m +# CONFIG_XILINX_LL_TEMAC is not set +CONFIG_NET_VENDOR_XIRCOM=y +CONFIG_PCMCIA_XIRC2PS=m +CONFIG_FDDI=y +CONFIG_DEFXX=m +# CONFIG_DEFXX_MMIO is not set +CONFIG_SKFP=m +# CONFIG_HIPPI is not set +CONFIG_NET_SB1000=m +CONFIG_MDIO_DEVICE=m +CONFIG_MDIO_BUS=m +CONFIG_MDIO_BCM_UNIMAC=m +CONFIG_MDIO_BITBANG=m +CONFIG_MDIO_CAVIUM=m +CONFIG_MDIO_GPIO=m +CONFIG_MDIO_I2C=m +CONFIG_MDIO_MSCC_MIIM=m +CONFIG_MDIO_THUNDER=m +CONFIG_PHYLINK=m +CONFIG_PHYLIB=m +CONFIG_SWPHY=y +# CONFIG_LED_TRIGGER_PHY is not set + +# +# MII PHY device drivers +# +CONFIG_SFP=m +CONFIG_ADIN_PHY=m +CONFIG_AMD_PHY=m +CONFIG_AQUANTIA_PHY=m +# CONFIG_AX88796B_PHY is not set +CONFIG_AT803X_PHY=m +CONFIG_BCM7XXX_PHY=m +CONFIG_BCM87XX_PHY=m +CONFIG_BCM_NET_PHYLIB=m +CONFIG_BROADCOM_PHY=m +CONFIG_CICADA_PHY=m +CONFIG_CORTINA_PHY=m +CONFIG_DAVICOM_PHY=m +# CONFIG_DP83822_PHY is not set +# CONFIG_DP83TC811_PHY is not set +CONFIG_DP83848_PHY=m +CONFIG_DP83867_PHY=m +CONFIG_FIXED_PHY=m +CONFIG_ICPLUS_PHY=m +CONFIG_INTEL_XWAY_PHY=m +CONFIG_LSI_ET1011C_PHY=m +CONFIG_LXT_PHY=m +CONFIG_MARVELL_PHY=m +CONFIG_MARVELL_10G_PHY=m +CONFIG_MICREL_PHY=m +CONFIG_MICROCHIP_PHY=m +CONFIG_MICROCHIP_T1_PHY=m +CONFIG_MICROSEMI_PHY=m +CONFIG_NATIONAL_PHY=m +CONFIG_NXP_TJA11XX_PHY=m +CONFIG_QSEMI_PHY=m +CONFIG_REALTEK_PHY=m +# CONFIG_RENESAS_PHY is not set +CONFIG_ROCKCHIP_PHY=m +CONFIG_SMSC_PHY=m +CONFIG_STE10XP=m +CONFIG_TERANETICS_PHY=m +CONFIG_VITESSE_PHY=m +CONFIG_XILINX_GMII2RGMII=m +CONFIG_MICREL_KS8995MA=m +CONFIG_PLIP=m +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOATM=m +CONFIG_PPPOE=m +CONFIG_PPTP=m +CONFIG_PPPOL2TP=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_SLIP=m +CONFIG_SLHC=m +CONFIG_SLIP_COMPRESSED=y +CONFIG_SLIP_SMART=y +CONFIG_SLIP_MODE_SLIP6=y + +# +# Host-side USB support is needed for USB Network Adapter support +# +CONFIG_USB_NET_DRIVERS=m +CONFIG_USB_CATC=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_RTL8152=m +CONFIG_USB_LAN78XX=m +CONFIG_USB_USBNET=m +CONFIG_USB_NET_AX8817X=m +CONFIG_USB_NET_AX88179_178A=m +CONFIG_USB_NET_CDCETHER=m +CONFIG_USB_NET_CDC_EEM=m +CONFIG_USB_NET_CDC_NCM=m +CONFIG_USB_NET_HUAWEI_CDC_NCM=m +CONFIG_USB_NET_CDC_MBIM=m +CONFIG_USB_NET_DM9601=m +CONFIG_USB_NET_SR9700=m +CONFIG_USB_NET_SR9800=m +CONFIG_USB_NET_SMSC75XX=m +CONFIG_USB_NET_SMSC95XX=m +CONFIG_USB_NET_GL620A=m +CONFIG_USB_NET_NET1080=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_MCS7830=m +CONFIG_USB_NET_RNDIS_HOST=m +CONFIG_USB_NET_CDC_SUBSET_ENABLE=m +CONFIG_USB_NET_CDC_SUBSET=m +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +CONFIG_USB_EPSON2888=y +CONFIG_USB_KC2190=y +CONFIG_USB_NET_ZAURUS=m +CONFIG_USB_NET_CX82310_ETH=m +CONFIG_USB_NET_KALMIA=m +CONFIG_USB_NET_QMI_WWAN=m +CONFIG_USB_HSO=m +CONFIG_USB_NET_INT51X1=m +CONFIG_USB_CDC_PHONET=m +CONFIG_USB_IPHETH=m +CONFIG_USB_SIERRA_NET=m +CONFIG_USB_VL600=m +CONFIG_USB_NET_CH9200=m +CONFIG_USB_NET_AQC111=m +CONFIG_WLAN=y +# CONFIG_WIRELESS_WDS is not set +CONFIG_WLAN_VENDOR_ADMTEK=y +CONFIG_ADM8211=m +CONFIG_ATH_COMMON=m +CONFIG_WLAN_VENDOR_ATH=y +CONFIG_ATH_DEBUG=y +# CONFIG_ATH_TRACEPOINTS is not set +CONFIG_ATH5K=m +CONFIG_ATH5K_DEBUG=y +# CONFIG_ATH5K_TRACER is not set +CONFIG_ATH5K_PCI=y +CONFIG_ATH9K_HW=m +CONFIG_ATH9K_COMMON=m +CONFIG_ATH9K_BTCOEX_SUPPORT=y +CONFIG_ATH9K=m +CONFIG_ATH9K_PCI=y +CONFIG_ATH9K_AHB=y +# CONFIG_ATH9K_DEBUGFS is not set +# CONFIG_ATH9K_DYNACK is not set +CONFIG_ATH9K_WOW=y +CONFIG_ATH9K_RFKILL=y +# CONFIG_ATH9K_CHANNEL_CONTEXT is not set +CONFIG_ATH9K_PCOEM=y +CONFIG_ATH9K_PCI_NO_EEPROM=m +CONFIG_ATH9K_HTC=m +# CONFIG_ATH9K_HTC_DEBUGFS is not set +CONFIG_ATH9K_HWRNG=y +CONFIG_CARL9170=m +CONFIG_CARL9170_LEDS=y +CONFIG_CARL9170_WPC=y +CONFIG_CARL9170_HWRNG=y +CONFIG_ATH6KL=m +CONFIG_ATH6KL_SDIO=m +CONFIG_ATH6KL_USB=m +# CONFIG_ATH6KL_DEBUG is not set +# CONFIG_ATH6KL_TRACING is not set +CONFIG_AR5523=m +CONFIG_WIL6210=m +CONFIG_WIL6210_ISR_COR=y +CONFIG_WIL6210_TRACING=y +# CONFIG_WIL6210_DEBUGFS is not set +CONFIG_ATH10K=m +CONFIG_ATH10K_CE=y +CONFIG_ATH10K_PCI=m +CONFIG_ATH10K_SDIO=m +CONFIG_ATH10K_USB=m +CONFIG_ATH10K_DEBUG=y +# CONFIG_ATH10K_DEBUGFS is not set +# CONFIG_ATH10K_TRACING is not set +CONFIG_WCN36XX=m +# CONFIG_WCN36XX_DEBUGFS is not set +CONFIG_WLAN_VENDOR_ATMEL=y +CONFIG_ATMEL=m +CONFIG_PCI_ATMEL=m +CONFIG_PCMCIA_ATMEL=m +CONFIG_AT76C50X_USB=m +CONFIG_WLAN_VENDOR_BROADCOM=y +CONFIG_B43=m +CONFIG_B43_BCMA=y +CONFIG_B43_SSB=y +CONFIG_B43_BUSES_BCMA_AND_SSB=y +# CONFIG_B43_BUSES_BCMA is not set +# CONFIG_B43_BUSES_SSB is not set +CONFIG_B43_PCI_AUTOSELECT=y +CONFIG_B43_PCICORE_AUTOSELECT=y +CONFIG_B43_SDIO=y +CONFIG_B43_BCMA_PIO=y +CONFIG_B43_PIO=y +CONFIG_B43_PHY_G=y +CONFIG_B43_PHY_N=y +CONFIG_B43_PHY_LP=y +CONFIG_B43_PHY_HT=y +CONFIG_B43_LEDS=y +CONFIG_B43_HWRNG=y +CONFIG_B43_DEBUG=y +CONFIG_B43LEGACY=m +CONFIG_B43LEGACY_PCI_AUTOSELECT=y +CONFIG_B43LEGACY_PCICORE_AUTOSELECT=y +CONFIG_B43LEGACY_LEDS=y +CONFIG_B43LEGACY_HWRNG=y +CONFIG_B43LEGACY_DEBUG=y +CONFIG_B43LEGACY_DMA=y +CONFIG_B43LEGACY_PIO=y +CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y +# CONFIG_B43LEGACY_DMA_MODE is not set +# CONFIG_B43LEGACY_PIO_MODE is not set +CONFIG_BRCMUTIL=m +CONFIG_BRCMSMAC=m +CONFIG_BRCMFMAC=m +CONFIG_BRCMFMAC_PROTO_BCDC=y +CONFIG_BRCMFMAC_PROTO_MSGBUF=y +CONFIG_BRCMFMAC_SDIO=y +CONFIG_BRCMFMAC_USB=y +CONFIG_BRCMFMAC_PCIE=y +# CONFIG_BRCM_TRACING is not set +# CONFIG_BRCMDBG is not set +CONFIG_WLAN_VENDOR_CISCO=y +CONFIG_AIRO=m +CONFIG_AIRO_CS=m +CONFIG_WLAN_VENDOR_INTEL=y +CONFIG_IPW2100=m +CONFIG_IPW2100_MONITOR=y +# CONFIG_IPW2100_DEBUG is not set +CONFIG_IPW2200=m +CONFIG_IPW2200_MONITOR=y +CONFIG_IPW2200_RADIOTAP=y +CONFIG_IPW2200_PROMISCUOUS=y +CONFIG_IPW2200_QOS=y +# CONFIG_IPW2200_DEBUG is not set +CONFIG_LIBIPW=m +# CONFIG_LIBIPW_DEBUG is not set +CONFIG_IWLEGACY=m +CONFIG_IWL4965=m +CONFIG_IWL3945=m + +# +# iwl3945 / iwl4965 Debugging Options +# +# CONFIG_IWLEGACY_DEBUG is not set +# end of iwl3945 / iwl4965 Debugging Options + +CONFIG_IWLWIFI=m +CONFIG_IWLWIFI_LEDS=y +CONFIG_IWLDVM=m +CONFIG_IWLMVM=m +CONFIG_IWLWIFI_OPMODE_MODULAR=y +# CONFIG_IWLWIFI_BCAST_FILTERING is not set + +# +# Debugging Options +# +CONFIG_IWLWIFI_DEBUG=y +# CONFIG_IWLWIFI_DEVICE_TRACING is not set +# end of Debugging Options + +CONFIG_WLAN_VENDOR_INTERSIL=y +CONFIG_HOSTAP=m +CONFIG_HOSTAP_FIRMWARE=y +CONFIG_HOSTAP_FIRMWARE_NVRAM=y +CONFIG_HOSTAP_PLX=m +CONFIG_HOSTAP_PCI=m +CONFIG_HOSTAP_CS=m +CONFIG_HERMES=m +CONFIG_HERMES_PRISM=y +CONFIG_HERMES_CACHE_FW_ON_INIT=y +CONFIG_PLX_HERMES=m +CONFIG_TMD_HERMES=m +CONFIG_NORTEL_HERMES=m +CONFIG_PCI_HERMES=m +CONFIG_PCMCIA_HERMES=m +CONFIG_PCMCIA_SPECTRUM=m +CONFIG_ORINOCO_USB=m +CONFIG_P54_COMMON=m +CONFIG_P54_USB=m +CONFIG_P54_PCI=m +CONFIG_P54_SPI=m +CONFIG_P54_SPI_DEFAULT_EEPROM=y +CONFIG_P54_LEDS=y +CONFIG_PRISM54=m +CONFIG_WLAN_VENDOR_MARVELL=y +CONFIG_LIBERTAS=m +CONFIG_LIBERTAS_USB=m +CONFIG_LIBERTAS_CS=m +CONFIG_LIBERTAS_SDIO=m +CONFIG_LIBERTAS_SPI=m +# CONFIG_LIBERTAS_DEBUG is not set +CONFIG_LIBERTAS_MESH=y +# CONFIG_LIBERTAS_THINFIRM is not set +CONFIG_MWIFIEX=m +CONFIG_MWIFIEX_SDIO=m +CONFIG_MWIFIEX_PCIE=m +CONFIG_MWIFIEX_USB=m +CONFIG_MWL8K=m +CONFIG_WLAN_VENDOR_MEDIATEK=y +CONFIG_MT7601U=m +CONFIG_MT76_CORE=m +CONFIG_MT76_LEDS=y +CONFIG_MT76_USB=m +CONFIG_MT76x02_LIB=m +CONFIG_MT76x02_USB=m +CONFIG_MT76x0_COMMON=m +CONFIG_MT76x0U=m +CONFIG_MT76x0E=m +CONFIG_MT76x2_COMMON=m +CONFIG_MT76x2E=m +CONFIG_MT76x2U=m +CONFIG_MT7603E=m +CONFIG_MT7615E=m +CONFIG_WLAN_VENDOR_RALINK=y +CONFIG_RT2X00=m +CONFIG_RT2400PCI=m +CONFIG_RT2500PCI=m +CONFIG_RT61PCI=m +CONFIG_RT2800PCI=m +CONFIG_RT2800PCI_RT33XX=y +CONFIG_RT2800PCI_RT35XX=y +CONFIG_RT2800PCI_RT53XX=y +CONFIG_RT2800PCI_RT3290=y +CONFIG_RT2500USB=m +CONFIG_RT73USB=m +CONFIG_RT2800USB=m +CONFIG_RT2800USB_RT33XX=y +CONFIG_RT2800USB_RT35XX=y +CONFIG_RT2800USB_RT3573=y +CONFIG_RT2800USB_RT53XX=y +CONFIG_RT2800USB_RT55XX=y +CONFIG_RT2800USB_UNKNOWN=y +CONFIG_RT2800_LIB=m +CONFIG_RT2800_LIB_MMIO=m +CONFIG_RT2X00_LIB_MMIO=m +CONFIG_RT2X00_LIB_PCI=m +CONFIG_RT2X00_LIB_USB=m +CONFIG_RT2X00_LIB=m +CONFIG_RT2X00_LIB_FIRMWARE=y +CONFIG_RT2X00_LIB_CRYPTO=y +CONFIG_RT2X00_LIB_LEDS=y +# CONFIG_RT2X00_DEBUG is not set +CONFIG_WLAN_VENDOR_REALTEK=y +CONFIG_RTL8180=m +CONFIG_RTL8187=m +CONFIG_RTL8187_LEDS=y +CONFIG_RTL_CARDS=m +CONFIG_RTL8192CE=m +CONFIG_RTL8192SE=m +CONFIG_RTL8192DE=m +CONFIG_RTL8723AE=m +CONFIG_RTL8723BE=m +CONFIG_RTL8188EE=m +CONFIG_RTL8192EE=m +CONFIG_RTL8821AE=m +CONFIG_RTL8192CU=m +CONFIG_RTLWIFI=m +CONFIG_RTLWIFI_PCI=m +CONFIG_RTLWIFI_USB=m +CONFIG_RTLWIFI_DEBUG=y +CONFIG_RTL8192C_COMMON=m +CONFIG_RTL8723_COMMON=m +CONFIG_RTLBTCOEXIST=m +CONFIG_RTL8XXXU=m +# CONFIG_RTL8XXXU_UNTESTED is not set +CONFIG_RTW88=m +CONFIG_RTW88_CORE=m +CONFIG_RTW88_PCI=m +CONFIG_RTW88_8822BE=y +CONFIG_RTW88_8822CE=y +CONFIG_RTW88_DEBUG=y +CONFIG_RTW88_DEBUGFS=y +CONFIG_WLAN_VENDOR_RSI=y +CONFIG_RSI_91X=m +CONFIG_RSI_DEBUGFS=y +CONFIG_RSI_SDIO=m +CONFIG_RSI_USB=m +CONFIG_RSI_COEX=y +CONFIG_WLAN_VENDOR_ST=y +CONFIG_CW1200=m +CONFIG_CW1200_WLAN_SDIO=m +CONFIG_CW1200_WLAN_SPI=m +CONFIG_WLAN_VENDOR_TI=y +CONFIG_WL1251=m +CONFIG_WL1251_SPI=m +CONFIG_WL1251_SDIO=m +CONFIG_WL12XX=m +CONFIG_WL18XX=m +CONFIG_WLCORE=m +CONFIG_WLCORE_SDIO=m +CONFIG_WILINK_PLATFORM_DATA=y +CONFIG_WLAN_VENDOR_ZYDAS=y +CONFIG_USB_ZD1201=m +CONFIG_ZD1211RW=m +# CONFIG_ZD1211RW_DEBUG is not set +CONFIG_WLAN_VENDOR_QUANTENNA=y +CONFIG_QTNFMAC=m +CONFIG_QTNFMAC_PCIE=m +CONFIG_PCMCIA_RAYCS=m +CONFIG_PCMCIA_WL3501=m +CONFIG_MAC80211_HWSIM=m +CONFIG_USB_NET_RNDIS_WLAN=m +# CONFIG_VIRT_WIFI is not set + +# +# WiMAX Wireless Broadband devices +# +CONFIG_WIMAX_I2400M=m +CONFIG_WIMAX_I2400M_USB=m +CONFIG_WIMAX_I2400M_DEBUG_LEVEL=8 +# end of WiMAX Wireless Broadband devices + +CONFIG_WAN=y +CONFIG_LANMEDIA=m +CONFIG_HDLC=m +CONFIG_HDLC_RAW=m +CONFIG_HDLC_RAW_ETH=m +CONFIG_HDLC_CISCO=m +CONFIG_HDLC_FR=m +CONFIG_HDLC_PPP=m +CONFIG_HDLC_X25=m +CONFIG_PCI200SYN=m +CONFIG_WANXL=m +CONFIG_PC300TOO=m +CONFIG_FARSYNC=m +CONFIG_DLCI=m +CONFIG_DLCI_MAX=8 +CONFIG_LAPBETHER=m +CONFIG_X25_ASY=m +CONFIG_SBNI=m +CONFIG_SBNI_MULTILINE=y +CONFIG_IEEE802154_DRIVERS=m +CONFIG_IEEE802154_FAKELB=m +CONFIG_IEEE802154_AT86RF230=m +# CONFIG_IEEE802154_AT86RF230_DEBUGFS is not set +CONFIG_IEEE802154_MRF24J40=m +CONFIG_IEEE802154_CC2520=m +CONFIG_IEEE802154_ATUSB=m +CONFIG_IEEE802154_ADF7242=m +CONFIG_IEEE802154_CA8210=m +# CONFIG_IEEE802154_CA8210_DEBUGFS is not set +# CONFIG_IEEE802154_MCR20A is not set +# CONFIG_IEEE802154_HWSIM is not set +CONFIG_XEN_NETDEV_FRONTEND=m +CONFIG_XEN_NETDEV_BACKEND=m +CONFIG_VMXNET3=m +CONFIG_FUJITSU_ES=m +CONFIG_THUNDERBOLT_NET=m +CONFIG_HYPERV_NET=m +# CONFIG_NETDEVSIM is not set +CONFIG_NET_FAILOVER=m +CONFIG_ISDN=y +CONFIG_ISDN_CAPI=m +# CONFIG_CAPI_TRACE is not set +CONFIG_ISDN_CAPI_CAPI20=m +CONFIG_ISDN_CAPI_MIDDLEWARE=y +CONFIG_MISDN=m +CONFIG_MISDN_DSP=m +CONFIG_MISDN_L1OIP=m + +# +# mISDN hardware drivers +# +CONFIG_MISDN_HFCPCI=m +CONFIG_MISDN_HFCMULTI=m +CONFIG_MISDN_HFCUSB=m +CONFIG_MISDN_AVMFRITZ=m +CONFIG_MISDN_SPEEDFAX=m +CONFIG_MISDN_INFINEON=m +CONFIG_MISDN_W6692=m +CONFIG_MISDN_NETJET=m +CONFIG_MISDN_HDLC=m +CONFIG_MISDN_IPAC=m +CONFIG_MISDN_ISAR=m +CONFIG_NVM=y +# CONFIG_NVM_PBLK is not set + +# +# Input device support +# +CONFIG_INPUT=y +CONFIG_INPUT_LEDS=m +CONFIG_INPUT_FF_MEMLESS=m +CONFIG_INPUT_POLLDEV=m +CONFIG_INPUT_SPARSEKMAP=m +CONFIG_INPUT_MATRIXKMAP=m + +# +# 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=m +CONFIG_INPUT_EVDEV=m +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ADC is not set +CONFIG_KEYBOARD_ADP5520=m +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +CONFIG_KEYBOARD_APPLESPI=m +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_QT1050 is not set +# CONFIG_KEYBOARD_QT1070 is not set +CONFIG_KEYBOARD_QT2160=m +CONFIG_KEYBOARD_DLINK_DIR685=m +CONFIG_KEYBOARD_LKKBD=m +CONFIG_KEYBOARD_GPIO=m +CONFIG_KEYBOARD_GPIO_POLLED=m +CONFIG_KEYBOARD_TCA6416=m +CONFIG_KEYBOARD_TCA8418=m +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_LM8323 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=m +# CONFIG_KEYBOARD_OPENCORES is not set +CONFIG_KEYBOARD_SAMSUNG=m +CONFIG_KEYBOARD_STOWAWAY=m +CONFIG_KEYBOARD_SUNKBD=m +# CONFIG_KEYBOARD_TM2_TOUCHKEY is not set +CONFIG_KEYBOARD_TWL4030=m +CONFIG_KEYBOARD_XTKBD=m +CONFIG_KEYBOARD_CROS_EC=m +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=m +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_BYD=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS=y +CONFIG_MOUSE_PS2_CYPRESS=y +CONFIG_MOUSE_PS2_LIFEBOOK=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +CONFIG_MOUSE_PS2_ELANTECH=y +CONFIG_MOUSE_PS2_ELANTECH_SMBUS=y +CONFIG_MOUSE_PS2_SENTELIC=y +CONFIG_MOUSE_PS2_TOUCHKIT=y +CONFIG_MOUSE_PS2_FOCALTECH=y +CONFIG_MOUSE_PS2_VMMOUSE=y +CONFIG_MOUSE_PS2_SMBUS=y +CONFIG_MOUSE_SERIAL=m +CONFIG_MOUSE_APPLETOUCH=m +CONFIG_MOUSE_BCM5974=m +CONFIG_MOUSE_CYAPA=m +CONFIG_MOUSE_ELAN_I2C=m +CONFIG_MOUSE_ELAN_I2C_I2C=y +CONFIG_MOUSE_ELAN_I2C_SMBUS=y +CONFIG_MOUSE_VSXXXAA=m +# CONFIG_MOUSE_GPIO is not set +# CONFIG_MOUSE_SYNAPTICS_I2C is not set +CONFIG_MOUSE_SYNAPTICS_USB=m +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_ANALOG=m +CONFIG_JOYSTICK_A3D=m +CONFIG_JOYSTICK_ADI=m +CONFIG_JOYSTICK_COBRA=m +CONFIG_JOYSTICK_GF2K=m +CONFIG_JOYSTICK_GRIP=m +CONFIG_JOYSTICK_GRIP_MP=m +CONFIG_JOYSTICK_GUILLEMOT=m +CONFIG_JOYSTICK_INTERACT=m +CONFIG_JOYSTICK_SIDEWINDER=m +CONFIG_JOYSTICK_TMDC=m +CONFIG_JOYSTICK_IFORCE=m +CONFIG_JOYSTICK_IFORCE_USB=m +CONFIG_JOYSTICK_IFORCE_232=m +CONFIG_JOYSTICK_WARRIOR=m +CONFIG_JOYSTICK_MAGELLAN=m +CONFIG_JOYSTICK_SPACEORB=m +CONFIG_JOYSTICK_SPACEBALL=m +CONFIG_JOYSTICK_STINGER=m +CONFIG_JOYSTICK_TWIDJOY=m +CONFIG_JOYSTICK_ZHENHUA=m +CONFIG_JOYSTICK_DB9=m +CONFIG_JOYSTICK_GAMECON=m +CONFIG_JOYSTICK_TURBOGRAFX=m +CONFIG_JOYSTICK_AS5011=m +CONFIG_JOYSTICK_JOYDUMP=m +CONFIG_JOYSTICK_XPAD=m +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_JOYSTICK_WALKERA0701=m +# CONFIG_JOYSTICK_PSXPAD_SPI is not set +CONFIG_JOYSTICK_PXRC=m +# CONFIG_JOYSTICK_FSIA6B is not set +CONFIG_INPUT_TABLET=y +CONFIG_TABLET_USB_ACECAD=m +CONFIG_TABLET_USB_AIPTEK=m +CONFIG_TABLET_USB_GTCO=m +CONFIG_TABLET_USB_HANWANG=m +CONFIG_TABLET_USB_KBTAB=m +CONFIG_TABLET_USB_PEGASUS=m +CONFIG_TABLET_SERIAL_WACOM4=m +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_PROPERTIES=y +CONFIG_TOUCHSCREEN_88PM860X=m +CONFIG_TOUCHSCREEN_ADS7846=m +CONFIG_TOUCHSCREEN_AD7877=m +CONFIG_TOUCHSCREEN_AD7879=m +CONFIG_TOUCHSCREEN_AD7879_I2C=m +CONFIG_TOUCHSCREEN_AD7879_SPI=m +CONFIG_TOUCHSCREEN_ADC=m +CONFIG_TOUCHSCREEN_ATMEL_MXT=m +# CONFIG_TOUCHSCREEN_ATMEL_MXT_T37 is not set +CONFIG_TOUCHSCREEN_AUO_PIXCIR=m +CONFIG_TOUCHSCREEN_BU21013=m +CONFIG_TOUCHSCREEN_BU21029=m +# CONFIG_TOUCHSCREEN_CHIPONE_ICN8505 is not set +CONFIG_TOUCHSCREEN_CY8CTMG110=m +CONFIG_TOUCHSCREEN_CYTTSP_CORE=m +CONFIG_TOUCHSCREEN_CYTTSP_I2C=m +CONFIG_TOUCHSCREEN_CYTTSP_SPI=m +CONFIG_TOUCHSCREEN_CYTTSP4_CORE=m +CONFIG_TOUCHSCREEN_CYTTSP4_I2C=m +CONFIG_TOUCHSCREEN_CYTTSP4_SPI=m +CONFIG_TOUCHSCREEN_DA9034=m +CONFIG_TOUCHSCREEN_DA9052=m +CONFIG_TOUCHSCREEN_DYNAPRO=m +CONFIG_TOUCHSCREEN_HAMPSHIRE=m +CONFIG_TOUCHSCREEN_EETI=m +CONFIG_TOUCHSCREEN_EGALAX_SERIAL=m +# CONFIG_TOUCHSCREEN_EXC3000 is not set +CONFIG_TOUCHSCREEN_FUJITSU=m +CONFIG_TOUCHSCREEN_GOODIX=m +# CONFIG_TOUCHSCREEN_HIDEEP is not set +CONFIG_TOUCHSCREEN_ILI210X=m +# CONFIG_TOUCHSCREEN_S6SY761 is not set +CONFIG_TOUCHSCREEN_GUNZE=m +CONFIG_TOUCHSCREEN_EKTF2127=m +CONFIG_TOUCHSCREEN_ELAN=m +CONFIG_TOUCHSCREEN_ELO=m +CONFIG_TOUCHSCREEN_WACOM_W8001=m +CONFIG_TOUCHSCREEN_WACOM_I2C=m +CONFIG_TOUCHSCREEN_MAX11801=m +CONFIG_TOUCHSCREEN_MCS5000=m +CONFIG_TOUCHSCREEN_MMS114=m +CONFIG_TOUCHSCREEN_MELFAS_MIP4=m +CONFIG_TOUCHSCREEN_MTOUCH=m +CONFIG_TOUCHSCREEN_INEXIO=m +CONFIG_TOUCHSCREEN_MK712=m +CONFIG_TOUCHSCREEN_PENMOUNT=m +CONFIG_TOUCHSCREEN_EDT_FT5X06=m +CONFIG_TOUCHSCREEN_TOUCHRIGHT=m +CONFIG_TOUCHSCREEN_TOUCHWIN=m +CONFIG_TOUCHSCREEN_TI_AM335X_TSC=m +CONFIG_TOUCHSCREEN_PIXCIR=m +CONFIG_TOUCHSCREEN_WDT87XX_I2C=m +CONFIG_TOUCHSCREEN_WM831X=m +CONFIG_TOUCHSCREEN_WM97XX=m +CONFIG_TOUCHSCREEN_WM9705=y +CONFIG_TOUCHSCREEN_WM9712=y +CONFIG_TOUCHSCREEN_WM9713=y +CONFIG_TOUCHSCREEN_USB_COMPOSITE=m +CONFIG_TOUCHSCREEN_MC13783=m +CONFIG_TOUCHSCREEN_USB_EGALAX=y +CONFIG_TOUCHSCREEN_USB_PANJIT=y +CONFIG_TOUCHSCREEN_USB_3M=y +CONFIG_TOUCHSCREEN_USB_ITM=y +CONFIG_TOUCHSCREEN_USB_ETURBO=y +CONFIG_TOUCHSCREEN_USB_GUNZE=y +CONFIG_TOUCHSCREEN_USB_DMC_TSC10=y +CONFIG_TOUCHSCREEN_USB_IRTOUCH=y +CONFIG_TOUCHSCREEN_USB_IDEALTEK=y +CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH=y +CONFIG_TOUCHSCREEN_USB_GOTOP=y +CONFIG_TOUCHSCREEN_USB_JASTEC=y +CONFIG_TOUCHSCREEN_USB_ELO=y +CONFIG_TOUCHSCREEN_USB_E2I=y +CONFIG_TOUCHSCREEN_USB_ZYTRONIC=y +CONFIG_TOUCHSCREEN_USB_ETT_TC45USB=y +CONFIG_TOUCHSCREEN_USB_NEXIO=y +CONFIG_TOUCHSCREEN_USB_EASYTOUCH=y +CONFIG_TOUCHSCREEN_TOUCHIT213=m +CONFIG_TOUCHSCREEN_TSC_SERIO=m +CONFIG_TOUCHSCREEN_TSC200X_CORE=m +CONFIG_TOUCHSCREEN_TSC2004=m +CONFIG_TOUCHSCREEN_TSC2005=m +CONFIG_TOUCHSCREEN_TSC2007=m +# CONFIG_TOUCHSCREEN_TSC2007_IIO is not set +CONFIG_TOUCHSCREEN_PCAP=m +CONFIG_TOUCHSCREEN_RM_TS=m +CONFIG_TOUCHSCREEN_SILEAD=m +CONFIG_TOUCHSCREEN_SIS_I2C=m +CONFIG_TOUCHSCREEN_ST1232=m +CONFIG_TOUCHSCREEN_STMFTS=m +CONFIG_TOUCHSCREEN_SUR40=m +CONFIG_TOUCHSCREEN_SURFACE3_SPI=m +# CONFIG_TOUCHSCREEN_SX8654 is not set +CONFIG_TOUCHSCREEN_TPS6507X=m +CONFIG_TOUCHSCREEN_ZET6223=m +CONFIG_TOUCHSCREEN_ZFORCE=m +CONFIG_TOUCHSCREEN_ROHM_BU21023=m +# CONFIG_TOUCHSCREEN_IQS5XX is not set +CONFIG_INPUT_MISC=y +CONFIG_INPUT_88PM860X_ONKEY=m +CONFIG_INPUT_88PM80X_ONKEY=m +CONFIG_INPUT_AD714X=m +CONFIG_INPUT_AD714X_I2C=m +CONFIG_INPUT_AD714X_SPI=m +# CONFIG_INPUT_ARIZONA_HAPTICS is not set +CONFIG_INPUT_BMA150=m +# CONFIG_INPUT_E3X0_BUTTON is not set +# CONFIG_INPUT_MSM_VIBRATOR is not set +CONFIG_INPUT_PCSPKR=m +CONFIG_INPUT_MAX77693_HAPTIC=m +CONFIG_INPUT_MAX8925_ONKEY=m +CONFIG_INPUT_MAX8997_HAPTIC=m +CONFIG_INPUT_MC13783_PWRBUTTON=m +# CONFIG_INPUT_MMA8450 is not set +CONFIG_INPUT_APANEL=m +CONFIG_INPUT_GP2A=m +CONFIG_INPUT_GPIO_BEEPER=m +# CONFIG_INPUT_GPIO_DECODER is not set +# CONFIG_INPUT_GPIO_VIBRA is not set +CONFIG_INPUT_ATLAS_BTNS=m +CONFIG_INPUT_ATI_REMOTE2=m +CONFIG_INPUT_KEYSPAN_REMOTE=m +# CONFIG_INPUT_KXTJ9 is not set +CONFIG_INPUT_POWERMATE=m +CONFIG_INPUT_YEALINK=m +CONFIG_INPUT_CM109=m +CONFIG_INPUT_REGULATOR_HAPTIC=m +CONFIG_INPUT_RETU_PWRBUTTON=m +# CONFIG_INPUT_AXP20X_PEK is not set +CONFIG_INPUT_TWL4030_PWRBUTTON=m +CONFIG_INPUT_TWL4030_VIBRA=m +CONFIG_INPUT_TWL6040_VIBRA=m +CONFIG_INPUT_UINPUT=m +CONFIG_INPUT_PALMAS_PWRBUTTON=m +CONFIG_INPUT_PCF8574=m +CONFIG_INPUT_PWM_BEEPER=m +CONFIG_INPUT_PWM_VIBRA=m +CONFIG_INPUT_GPIO_ROTARY_ENCODER=m +CONFIG_INPUT_DA9052_ONKEY=m +CONFIG_INPUT_DA9055_ONKEY=m +CONFIG_INPUT_DA9063_ONKEY=m +CONFIG_INPUT_WM831X_ON=m +CONFIG_INPUT_PCAP=m +# CONFIG_INPUT_ADXL34X is not set +CONFIG_INPUT_IMS_PCU=m +CONFIG_INPUT_CMA3000=m +CONFIG_INPUT_CMA3000_I2C=m +CONFIG_INPUT_XEN_KBDDEV_FRONTEND=y +CONFIG_INPUT_IDEAPAD_SLIDEBAR=m +CONFIG_INPUT_SOC_BUTTON_ARRAY=m +CONFIG_INPUT_DRV260X_HAPTICS=m +CONFIG_INPUT_DRV2665_HAPTICS=m +CONFIG_INPUT_DRV2667_HAPTICS=m +CONFIG_RMI4_CORE=m +CONFIG_RMI4_I2C=m +CONFIG_RMI4_SPI=m +CONFIG_RMI4_SMB=m +CONFIG_RMI4_F03=y +CONFIG_RMI4_F03_SERIO=m +CONFIG_RMI4_2D_SENSOR=y +CONFIG_RMI4_F11=y +CONFIG_RMI4_F12=y +CONFIG_RMI4_F30=y +CONFIG_RMI4_F34=y +CONFIG_RMI4_F54=y +CONFIG_RMI4_F55=y + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=m +CONFIG_SERIO_CT82C710=m +CONFIG_SERIO_PARKBD=m +CONFIG_SERIO_PCIPS2=m +CONFIG_SERIO_LIBPS2=y +CONFIG_SERIO_RAW=m +CONFIG_SERIO_ALTERA_PS2=m +CONFIG_SERIO_PS2MULT=m +CONFIG_SERIO_ARC_PS2=m +CONFIG_HYPERV_KEYBOARD=m +CONFIG_SERIO_GPIO_PS2=m +CONFIG_USERIO=m +CONFIG_GAMEPORT=m +CONFIG_GAMEPORT_NS558=m +CONFIG_GAMEPORT_L4=m +CONFIG_GAMEPORT_EMU10K1=m +CONFIG_GAMEPORT_FM801=m +# end of Hardware I/O ports +# end of Input device support + +# +# Character devices +# +CONFIG_TTY=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=0 +CONFIG_SERIAL_NONSTANDARD=y +CONFIG_ROCKETPORT=m +CONFIG_CYCLADES=m +# CONFIG_CYZ_INTR is not set +CONFIG_MOXA_INTELLIO=m +CONFIG_MOXA_SMARTIO=m +CONFIG_SYNCLINK=m +CONFIG_SYNCLINKMP=m +CONFIG_SYNCLINK_GT=m +CONFIG_NOZOMI=m +CONFIG_ISI=m +CONFIG_N_HDLC=m +CONFIG_N_GSM=m +CONFIG_TRACE_ROUTER=m +CONFIG_TRACE_SINK=m +# CONFIG_NULL_TTY is not set +CONFIG_LDISC_AUTOLOAD=y +CONFIG_DEVMEM=y +# CONFIG_DEVKMEM is not set + +# +# Serial drivers +# +CONFIG_SERIAL_EARLYCON=y +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +CONFIG_SERIAL_8250_PNP=y +CONFIG_SERIAL_8250_FINTEK=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_DMA=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_EXAR=y +CONFIG_SERIAL_8250_CS=m +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +# CONFIG_SERIAL_8250_MANY_PORTS is not set +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +CONFIG_SERIAL_8250_RSA=y +CONFIG_SERIAL_8250_DWLIB=y +CONFIG_SERIAL_8250_DW=m +CONFIG_SERIAL_8250_RT288X=y +CONFIG_SERIAL_8250_LPSS=m +CONFIG_SERIAL_8250_MID=m + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_MAX3100=m +CONFIG_SERIAL_MAX310X=m +CONFIG_SERIAL_UARTLITE=m +CONFIG_SERIAL_UARTLITE_NR_UARTS=1 +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_JSM=m +CONFIG_SERIAL_SCCNXP=m +CONFIG_SERIAL_SC16IS7XX_CORE=m +CONFIG_SERIAL_SC16IS7XX=m +CONFIG_SERIAL_SC16IS7XX_I2C=y +# CONFIG_SERIAL_SC16IS7XX_SPI is not set +CONFIG_SERIAL_ALTERA_JTAGUART=m +CONFIG_SERIAL_ALTERA_UART=m +CONFIG_SERIAL_ALTERA_UART_MAXPORTS=4 +CONFIG_SERIAL_ALTERA_UART_BAUDRATE=115200 +CONFIG_SERIAL_IFX6X60=m +CONFIG_SERIAL_ARC=m +CONFIG_SERIAL_ARC_NR_PORTS=1 +CONFIG_SERIAL_RP2=m +CONFIG_SERIAL_RP2_NR_UARTS=32 +CONFIG_SERIAL_FSL_LPUART=m +# CONFIG_SERIAL_FSL_LINFLEXUART is not set +# end of Serial drivers + +CONFIG_SERIAL_MCTRL_GPIO=y +CONFIG_SERIAL_DEV_BUS=m +# CONFIG_TTY_PRINTK is not set +CONFIG_PRINTER=m +CONFIG_LP_CONSOLE=y +CONFIG_PPDEV=m +CONFIG_HVC_DRIVER=y +CONFIG_HVC_IRQ=y +CONFIG_HVC_XEN=y +CONFIG_HVC_XEN_FRONTEND=y +CONFIG_VIRTIO_CONSOLE=m +CONFIG_IPMI_HANDLER=m +CONFIG_IPMI_DMI_DECODE=y +CONFIG_IPMI_PLAT_DATA=y +CONFIG_IPMI_PANIC_EVENT=y +CONFIG_IPMI_PANIC_STRING=y +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_SI=m +CONFIG_IPMI_SSIF=m +CONFIG_IPMI_WATCHDOG=m +CONFIG_IPMI_POWEROFF=m +CONFIG_IPMB_DEVICE_INTERFACE=m +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_TIMERIOMEM=m +CONFIG_HW_RANDOM_INTEL=m +CONFIG_HW_RANDOM_AMD=m +CONFIG_HW_RANDOM_VIA=m +CONFIG_HW_RANDOM_VIRTIO=m +CONFIG_NVRAM=m +CONFIG_APPLICOM=m + +# +# PCMCIA character devices +# +CONFIG_SYNCLINK_CS=m +CONFIG_CARDMAN_4000=m +CONFIG_CARDMAN_4040=m +CONFIG_SCR24X=m +CONFIG_IPWIRELESS=m +# end of PCMCIA character devices + +CONFIG_MWAVE=m +CONFIG_RAW_DRIVER=m +CONFIG_MAX_RAW_DEVS=256 +CONFIG_HPET=y +CONFIG_HPET_MMAP=y +CONFIG_HPET_MMAP_DEFAULT=y +CONFIG_HANGCHECK_TIMER=m +CONFIG_TCG_TPM=m +CONFIG_HW_RANDOM_TPM=y +CONFIG_TCG_TIS_CORE=m +CONFIG_TCG_TIS=m +CONFIG_TCG_TIS_SPI=m +CONFIG_TCG_TIS_I2C_ATMEL=m +CONFIG_TCG_TIS_I2C_INFINEON=m +CONFIG_TCG_TIS_I2C_NUVOTON=m +CONFIG_TCG_NSC=m +CONFIG_TCG_ATMEL=m +CONFIG_TCG_INFINEON=m +CONFIG_TCG_XEN=m +CONFIG_TCG_CRB=m +CONFIG_TCG_VTPM_PROXY=m +CONFIG_TCG_TIS_ST33ZP24=m +CONFIG_TCG_TIS_ST33ZP24_I2C=m +CONFIG_TCG_TIS_ST33ZP24_SPI=m +CONFIG_TELCLOCK=m +CONFIG_DEVPORT=y +CONFIG_XILLYBUS=m +CONFIG_XILLYBUS_PCIE=m +# end of Character devices + +CONFIG_RANDOM_TRUST_CPU=y +CONFIG_RANDOM_TRUST_BOOTLOADER=y + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_ACPI_I2C_OPREGION=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=m +CONFIG_I2C_MUX=m + +# +# Multiplexer I2C Chip support +# +CONFIG_I2C_MUX_GPIO=m +CONFIG_I2C_MUX_LTC4306=m +CONFIG_I2C_MUX_PCA9541=m +CONFIG_I2C_MUX_PCA954x=m +CONFIG_I2C_MUX_REG=m +CONFIG_I2C_MUX_MLXCPLD=m +# end of Multiplexer I2C Chip support + +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_SMBUS=m +CONFIG_I2C_ALGOBIT=m + +# +# I2C Hardware Bus support +# + +# +# PC SMBus host controller drivers +# +CONFIG_I2C_ALI1535=m +CONFIG_I2C_ALI1563=m +CONFIG_I2C_ALI15X3=m +CONFIG_I2C_AMD756=m +CONFIG_I2C_AMD756_S4882=m +CONFIG_I2C_AMD8111=m +CONFIG_I2C_AMD_MP2=m +CONFIG_I2C_I801=m +CONFIG_I2C_ISCH=m +CONFIG_I2C_ISMT=m +CONFIG_I2C_PIIX4=m +CONFIG_I2C_CHT_WC=m +CONFIG_I2C_NFORCE2=m +CONFIG_I2C_NFORCE2_S4985=m +CONFIG_I2C_NVIDIA_GPU=m +CONFIG_I2C_SIS5595=m +CONFIG_I2C_SIS630=m +CONFIG_I2C_SIS96X=m +CONFIG_I2C_VIA=m +CONFIG_I2C_VIAPRO=m + +# +# ACPI drivers +# +CONFIG_I2C_SCMI=m + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +CONFIG_I2C_CBUS_GPIO=m +CONFIG_I2C_DESIGNWARE_CORE=y +CONFIG_I2C_DESIGNWARE_PLATFORM=y +CONFIG_I2C_DESIGNWARE_SLAVE=y +CONFIG_I2C_DESIGNWARE_PCI=m +CONFIG_I2C_DESIGNWARE_BAYTRAIL=y +CONFIG_I2C_EMEV2=m +# CONFIG_I2C_GPIO is not set +CONFIG_I2C_KEMPLD=m +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_SIMTEC is not set +CONFIG_I2C_XILINX=m + +# +# External I2C/SMBus adapter drivers +# +CONFIG_I2C_DIOLAN_U2C=m +CONFIG_I2C_DLN2=m +CONFIG_I2C_PARPORT=m +CONFIG_I2C_PARPORT_LIGHT=m +CONFIG_I2C_ROBOTFUZZ_OSIF=m +CONFIG_I2C_TAOS_EVM=m +CONFIG_I2C_TINY_USB=m +CONFIG_I2C_VIPERBOARD=m + +# +# Other I2C/SMBus bus drivers +# +CONFIG_I2C_MLXCPLD=m +CONFIG_I2C_CROS_EC_TUNNEL=m +# end of I2C Hardware Bus support + +# CONFIG_I2C_STUB is not set +CONFIG_I2C_SLAVE=y +CONFIG_I2C_SLAVE_EEPROM=m +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# end of I2C support + +CONFIG_I3C=m +CONFIG_CDNS_I3C_MASTER=m +CONFIG_DW_I3C_MASTER=m +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y +CONFIG_SPI_MEM=y + +# +# SPI Master Controller Drivers +# +CONFIG_SPI_ALTERA=m +CONFIG_SPI_AXI_SPI_ENGINE=m +CONFIG_SPI_BITBANG=m +CONFIG_SPI_BUTTERFLY=m +# CONFIG_SPI_CADENCE is not set +CONFIG_SPI_DESIGNWARE=m +CONFIG_SPI_DW_PCI=m +CONFIG_SPI_DW_MID_DMA=y +CONFIG_SPI_DW_MMIO=m +# CONFIG_SPI_DLN2 is not set +# CONFIG_SPI_NXP_FLEXSPI is not set +CONFIG_SPI_GPIO=m +CONFIG_SPI_LM70_LLP=m +CONFIG_SPI_OC_TINY=m +CONFIG_SPI_PXA2XX=m +CONFIG_SPI_PXA2XX_PCI=m +CONFIG_SPI_ROCKCHIP=m +CONFIG_SPI_SC18IS602=m +# CONFIG_SPI_SIFIVE is not set +# CONFIG_SPI_MXIC is not set +CONFIG_SPI_XCOMM=m +CONFIG_SPI_XILINX=m +CONFIG_SPI_ZYNQMP_GQSPI=m + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=m +CONFIG_SPI_LOOPBACK_TEST=m +CONFIG_SPI_TLE62X0=m +# CONFIG_SPI_SLAVE is not set +CONFIG_SPMI=m +CONFIG_HSI=m +CONFIG_HSI_BOARDINFO=y + +# +# HSI controllers +# + +# +# HSI clients +# +CONFIG_HSI_CHAR=m +CONFIG_PPS=m +# CONFIG_PPS_DEBUG is not set + +# +# PPS clients support +# +CONFIG_PPS_CLIENT_KTIMER=m +CONFIG_PPS_CLIENT_LDISC=m +CONFIG_PPS_CLIENT_PARPORT=m +CONFIG_PPS_CLIENT_GPIO=m + +# +# PPS generators support +# + +# +# PTP clock support +# +CONFIG_PTP_1588_CLOCK=m + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +CONFIG_PTP_1588_CLOCK_KVM=m +# end of PTP clock support + +CONFIG_PINCTRL=y +CONFIG_PINMUX=y +CONFIG_PINCONF=y +CONFIG_GENERIC_PINCONF=y +# CONFIG_DEBUG_PINCTRL is not set +CONFIG_PINCTRL_AMD=y +# CONFIG_PINCTRL_MCP23S08 is not set +CONFIG_PINCTRL_SX150X=y +CONFIG_PINCTRL_BAYTRAIL=y +CONFIG_PINCTRL_CHERRYVIEW=m +CONFIG_PINCTRL_INTEL=m +CONFIG_PINCTRL_BROXTON=m +CONFIG_PINCTRL_CANNONLAKE=m +CONFIG_PINCTRL_CEDARFORK=m +CONFIG_PINCTRL_DENVERTON=m +CONFIG_PINCTRL_GEMINILAKE=m +CONFIG_PINCTRL_ICELAKE=m +CONFIG_PINCTRL_LEWISBURG=m +CONFIG_PINCTRL_SUNRISEPOINT=m +CONFIG_PINCTRL_MADERA=m +CONFIG_PINCTRL_CS47L15=y +CONFIG_PINCTRL_CS47L35=y +CONFIG_PINCTRL_CS47L85=y +CONFIG_PINCTRL_CS47L90=y +CONFIG_PINCTRL_CS47L92=y +CONFIG_GPIOLIB=y +CONFIG_GPIOLIB_FASTPATH_LIMIT=512 +CONFIG_GPIO_ACPI=y +CONFIG_GPIOLIB_IRQCHIP=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_GENERIC=m +CONFIG_GPIO_MAX730X=m + +# +# Memory mapped GPIO drivers +# +CONFIG_GPIO_AMDPT=m +# CONFIG_GPIO_DWAPB is not set +CONFIG_GPIO_EXAR=m +CONFIG_GPIO_GENERIC_PLATFORM=m +CONFIG_GPIO_ICH=m +CONFIG_GPIO_LYNXPOINT=y +# CONFIG_GPIO_MB86S7X is not set +CONFIG_GPIO_VX855=m +CONFIG_GPIO_XILINX=m +CONFIG_GPIO_AMD_FCH=m +# end of Memory mapped GPIO drivers + +# +# Port-mapped I/O GPIO drivers +# +CONFIG_GPIO_F7188X=m +CONFIG_GPIO_IT87=m +CONFIG_GPIO_SCH=m +CONFIG_GPIO_SCH311X=m +CONFIG_GPIO_WINBOND=m +CONFIG_GPIO_WS16C48=m +# end of Port-mapped I/O GPIO drivers + +# +# I2C GPIO expanders +# +CONFIG_GPIO_ADP5588=m +CONFIG_GPIO_MAX7300=m +CONFIG_GPIO_MAX732X=m +CONFIG_GPIO_PCA953X=m +CONFIG_GPIO_PCF857X=m +CONFIG_GPIO_TPIC2810=m +# end of I2C GPIO expanders + +# +# MFD GPIO expanders +# +CONFIG_GPIO_ADP5520=m +CONFIG_GPIO_ARIZONA=m +CONFIG_GPIO_BD9571MWV=m +CONFIG_GPIO_CRYSTAL_COVE=y +CONFIG_GPIO_DA9052=m +CONFIG_GPIO_DA9055=m +CONFIG_GPIO_DLN2=m +CONFIG_GPIO_KEMPLD=m +CONFIG_GPIO_LP3943=m +CONFIG_GPIO_MADERA=m +CONFIG_GPIO_PALMAS=y +CONFIG_GPIO_RC5T583=y +CONFIG_GPIO_TPS65086=m +CONFIG_GPIO_TPS6586X=y +CONFIG_GPIO_TPS65910=y +CONFIG_GPIO_TPS65912=m +CONFIG_GPIO_TPS68470=y +CONFIG_GPIO_TWL4030=m +CONFIG_GPIO_TWL6040=m +CONFIG_GPIO_WHISKEY_COVE=m +CONFIG_GPIO_WM831X=m +CONFIG_GPIO_WM8350=m +CONFIG_GPIO_WM8994=m +# end of MFD GPIO expanders + +# +# PCI GPIO expanders +# +CONFIG_GPIO_AMD8111=m +CONFIG_GPIO_ML_IOH=m +CONFIG_GPIO_PCI_IDIO_16=m +# CONFIG_GPIO_PCIE_IDIO_24 is not set +CONFIG_GPIO_RDC321X=m +# end of PCI GPIO expanders + +# +# SPI GPIO expanders +# +# CONFIG_GPIO_MAX3191X is not set +CONFIG_GPIO_MAX7301=m +CONFIG_GPIO_MC33880=m +CONFIG_GPIO_PISOSR=m +# CONFIG_GPIO_XRA1403 is not set +# end of SPI GPIO expanders + +# +# USB GPIO expanders +# +CONFIG_GPIO_VIPERBOARD=m +# end of USB GPIO expanders + +# CONFIG_GPIO_MOCKUP is not set +CONFIG_W1=m +CONFIG_W1_CON=y + +# +# 1-wire Bus Masters +# +CONFIG_W1_MASTER_MATROX=m +CONFIG_W1_MASTER_DS2490=m +CONFIG_W1_MASTER_DS2482=m +CONFIG_W1_MASTER_DS1WM=m +# CONFIG_W1_MASTER_GPIO is not set +CONFIG_W1_MASTER_SGI=m +# end of 1-wire Bus Masters + +# +# 1-wire Slaves +# +CONFIG_W1_SLAVE_THERM=m +CONFIG_W1_SLAVE_SMEM=m +# CONFIG_W1_SLAVE_DS2405 is not set +CONFIG_W1_SLAVE_DS2408=m +CONFIG_W1_SLAVE_DS2408_READBACK=y +CONFIG_W1_SLAVE_DS2413=m +CONFIG_W1_SLAVE_DS2406=m +CONFIG_W1_SLAVE_DS2423=m +# CONFIG_W1_SLAVE_DS2805 is not set +CONFIG_W1_SLAVE_DS2431=m +CONFIG_W1_SLAVE_DS2433=m +# CONFIG_W1_SLAVE_DS2433_CRC is not set +# CONFIG_W1_SLAVE_DS2438 is not set +# CONFIG_W1_SLAVE_DS250X is not set +CONFIG_W1_SLAVE_DS2780=m +CONFIG_W1_SLAVE_DS2781=m +CONFIG_W1_SLAVE_DS28E04=m +# CONFIG_W1_SLAVE_DS28E17 is not set +# end of 1-wire Slaves + +CONFIG_POWER_AVS=y +# CONFIG_POWER_RESET is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +CONFIG_POWER_SUPPLY_HWMON=y +# CONFIG_PDA_POWER is not set +CONFIG_GENERIC_ADC_BATTERY=m +CONFIG_MAX8925_POWER=m +CONFIG_WM831X_BACKUP=m +CONFIG_WM831X_POWER=m +CONFIG_WM8350_POWER=m +# CONFIG_TEST_POWER is not set +CONFIG_BATTERY_88PM860X=m +CONFIG_CHARGER_ADP5061=m +CONFIG_BATTERY_DS2760=m +CONFIG_BATTERY_DS2780=m +CONFIG_BATTERY_DS2781=m +CONFIG_BATTERY_DS2782=m +CONFIG_BATTERY_SBS=m +CONFIG_CHARGER_SBS=m +# CONFIG_MANAGER_SBS is not set +CONFIG_BATTERY_BQ27XXX=m +CONFIG_BATTERY_BQ27XXX_I2C=m +CONFIG_BATTERY_BQ27XXX_HDQ=m +# CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM is not set +CONFIG_BATTERY_DA9030=m +CONFIG_BATTERY_DA9052=m +CONFIG_AXP20X_POWER=m +CONFIG_AXP288_CHARGER=m +CONFIG_AXP288_FUEL_GAUGE=m +# CONFIG_BATTERY_MAX17040 is not set +CONFIG_BATTERY_MAX17042=m +# CONFIG_BATTERY_MAX1721X is not set +CONFIG_BATTERY_TWL4030_MADC=m +CONFIG_CHARGER_88PM860X=m +CONFIG_BATTERY_RX51=m +CONFIG_CHARGER_ISP1704=m +CONFIG_CHARGER_MAX8903=m +CONFIG_CHARGER_TWL4030=m +CONFIG_CHARGER_LP8727=m +CONFIG_CHARGER_LP8788=m +CONFIG_CHARGER_GPIO=m +CONFIG_CHARGER_MANAGER=y +CONFIG_CHARGER_LT3651=m +CONFIG_CHARGER_MAX14577=m +# CONFIG_CHARGER_MAX77693 is not set +CONFIG_CHARGER_MAX8997=m +CONFIG_CHARGER_MAX8998=m +CONFIG_CHARGER_BQ2415X=m +CONFIG_CHARGER_BQ24190=m +CONFIG_CHARGER_BQ24257=m +CONFIG_CHARGER_BQ24735=m +CONFIG_CHARGER_BQ25890=m +CONFIG_CHARGER_SMB347=m +CONFIG_CHARGER_TPS65090=m +# CONFIG_BATTERY_GAUGE_LTC2941 is not set +CONFIG_CHARGER_RT9455=m +CONFIG_CHARGER_CROS_USBPD=m +CONFIG_CHARGER_WILCO=m +CONFIG_HWMON=y +CONFIG_HWMON_VID=m +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +CONFIG_SENSORS_ABITUGURU=m +CONFIG_SENSORS_ABITUGURU3=m +CONFIG_SENSORS_AD7314=m +CONFIG_SENSORS_AD7414=m +CONFIG_SENSORS_AD7418=m +CONFIG_SENSORS_ADM1021=m +CONFIG_SENSORS_ADM1025=m +CONFIG_SENSORS_ADM1026=m +CONFIG_SENSORS_ADM1029=m +CONFIG_SENSORS_ADM1031=m +CONFIG_SENSORS_ADM9240=m +CONFIG_SENSORS_ADT7X10=m +CONFIG_SENSORS_ADT7310=m +CONFIG_SENSORS_ADT7410=m +CONFIG_SENSORS_ADT7411=m +CONFIG_SENSORS_ADT7462=m +CONFIG_SENSORS_ADT7470=m +CONFIG_SENSORS_ADT7475=m +CONFIG_SENSORS_AS370=m +CONFIG_SENSORS_ASC7621=m +CONFIG_SENSORS_K8TEMP=m +CONFIG_SENSORS_K10TEMP=m +CONFIG_SENSORS_FAM15H_POWER=m +CONFIG_SENSORS_APPLESMC=m +CONFIG_SENSORS_ASB100=m +CONFIG_SENSORS_ASPEED=m +CONFIG_SENSORS_ATXP1=m +CONFIG_SENSORS_DS620=m +CONFIG_SENSORS_DS1621=m +CONFIG_SENSORS_DELL_SMM=m +CONFIG_SENSORS_DA9052_ADC=m +CONFIG_SENSORS_DA9055=m +CONFIG_SENSORS_I5K_AMB=m +CONFIG_SENSORS_F71805F=m +CONFIG_SENSORS_F71882FG=m +CONFIG_SENSORS_F75375S=m +CONFIG_SENSORS_MC13783_ADC=m +CONFIG_SENSORS_FSCHMD=m +CONFIG_SENSORS_FTSTEUTATES=m +CONFIG_SENSORS_GL518SM=m +CONFIG_SENSORS_GL520SM=m +# CONFIG_SENSORS_G760A is not set +CONFIG_SENSORS_G762=m +CONFIG_SENSORS_HIH6130=m +CONFIG_SENSORS_IBMAEM=m +CONFIG_SENSORS_IBMPEX=m +CONFIG_SENSORS_IIO_HWMON=m +CONFIG_SENSORS_I5500=m +CONFIG_SENSORS_CORETEMP=m +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_JC42=m +CONFIG_SENSORS_POWR1220=m +CONFIG_SENSORS_LINEAGE=m +CONFIG_SENSORS_LTC2945=m +CONFIG_SENSORS_LTC2990=m +CONFIG_SENSORS_LTC4151=m +# CONFIG_SENSORS_LTC4215 is not set +CONFIG_SENSORS_LTC4222=m +CONFIG_SENSORS_LTC4245=m +CONFIG_SENSORS_LTC4260=m +CONFIG_SENSORS_LTC4261=m +CONFIG_SENSORS_MAX1111=m +CONFIG_SENSORS_MAX16065=m +CONFIG_SENSORS_MAX1619=m +CONFIG_SENSORS_MAX1668=m +CONFIG_SENSORS_MAX197=m +CONFIG_SENSORS_MAX31722=m +# CONFIG_SENSORS_MAX6621 is not set +CONFIG_SENSORS_MAX6639=m +CONFIG_SENSORS_MAX6642=m +CONFIG_SENSORS_MAX6650=m +# CONFIG_SENSORS_MAX6697 is not set +CONFIG_SENSORS_MAX31790=m +CONFIG_SENSORS_MCP3021=m +CONFIG_SENSORS_MLXREG_FAN=m +CONFIG_SENSORS_TC654=m +CONFIG_SENSORS_MENF21BMC_HWMON=m +CONFIG_SENSORS_ADCXX=m +CONFIG_SENSORS_LM63=m +CONFIG_SENSORS_LM70=m +CONFIG_SENSORS_LM73=m +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM77=m +CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM80=m +CONFIG_SENSORS_LM83=m +CONFIG_SENSORS_LM85=m +CONFIG_SENSORS_LM87=m +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_LM92=m +CONFIG_SENSORS_LM93=m +CONFIG_SENSORS_LM95234=m +CONFIG_SENSORS_LM95241=m +CONFIG_SENSORS_LM95245=m +CONFIG_SENSORS_PC87360=m +CONFIG_SENSORS_PC87427=m +CONFIG_SENSORS_NTC_THERMISTOR=m +CONFIG_SENSORS_NCT6683=m +CONFIG_SENSORS_NCT6775=m +CONFIG_SENSORS_NCT7802=m +CONFIG_SENSORS_NCT7904=m +CONFIG_SENSORS_NPCM7XX=m +CONFIG_SENSORS_PCF8591=m +CONFIG_PMBUS=m +CONFIG_SENSORS_PMBUS=m +CONFIG_SENSORS_ADM1275=m +CONFIG_SENSORS_IBM_CFFPS=m +CONFIG_SENSORS_INSPUR_IPSPS=m +CONFIG_SENSORS_IR35221=m +CONFIG_SENSORS_IR38064=m +CONFIG_SENSORS_IRPS5401=m +CONFIG_SENSORS_ISL68137=m +CONFIG_SENSORS_LM25066=m +CONFIG_SENSORS_LTC2978=m +CONFIG_SENSORS_LTC2978_REGULATOR=y +CONFIG_SENSORS_LTC3815=m +CONFIG_SENSORS_MAX16064=m +CONFIG_SENSORS_MAX20751=m +# CONFIG_SENSORS_MAX31785 is not set +CONFIG_SENSORS_MAX34440=m +CONFIG_SENSORS_MAX8688=m +CONFIG_SENSORS_PXE1610=m +CONFIG_SENSORS_TPS40422=m +CONFIG_SENSORS_TPS53679=m +CONFIG_SENSORS_UCD9000=m +CONFIG_SENSORS_UCD9200=m +CONFIG_SENSORS_ZL6100=m +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SHT3x is not set +CONFIG_SENSORS_SHTC1=m +CONFIG_SENSORS_SIS5595=m +CONFIG_SENSORS_DME1737=m +CONFIG_SENSORS_EMC1403=m +CONFIG_SENSORS_EMC2103=m +CONFIG_SENSORS_EMC6W201=m +CONFIG_SENSORS_SMSC47M1=m +CONFIG_SENSORS_SMSC47M192=m +CONFIG_SENSORS_SMSC47B397=m +CONFIG_SENSORS_SCH56XX_COMMON=m +CONFIG_SENSORS_SCH5627=m +CONFIG_SENSORS_SCH5636=m +CONFIG_SENSORS_STTS751=m +CONFIG_SENSORS_SMM665=m +CONFIG_SENSORS_ADC128D818=m +# CONFIG_SENSORS_ADS7828 is not set +CONFIG_SENSORS_ADS7871=m +# CONFIG_SENSORS_AMC6821 is not set +CONFIG_SENSORS_INA209=m +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_INA3221 is not set +CONFIG_SENSORS_TC74=m +CONFIG_SENSORS_THMC50=m +CONFIG_SENSORS_TMP102=m +CONFIG_SENSORS_TMP103=m +CONFIG_SENSORS_TMP108=m +CONFIG_SENSORS_TMP401=m +CONFIG_SENSORS_TMP421=m +CONFIG_SENSORS_VIA_CPUTEMP=m +CONFIG_SENSORS_VIA686A=m +CONFIG_SENSORS_VT1211=m +CONFIG_SENSORS_VT8231=m +CONFIG_SENSORS_W83773G=m +CONFIG_SENSORS_W83781D=m +CONFIG_SENSORS_W83791D=m +CONFIG_SENSORS_W83792D=m +CONFIG_SENSORS_W83793=m +CONFIG_SENSORS_W83795=m +# CONFIG_SENSORS_W83795_FANCTRL is not set +CONFIG_SENSORS_W83L785TS=m +CONFIG_SENSORS_W83L786NG=m +CONFIG_SENSORS_W83627HF=m +CONFIG_SENSORS_W83627EHF=m +CONFIG_SENSORS_WM831X=m +CONFIG_SENSORS_WM8350=m +CONFIG_SENSORS_XGENE=m + +# +# ACPI drivers +# +CONFIG_SENSORS_ACPI_POWER=m +CONFIG_SENSORS_ATK0110=m +CONFIG_THERMAL=y +# CONFIG_THERMAL_STATISTICS is not set +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR is not set +CONFIG_THERMAL_GOV_FAIR_SHARE=y +CONFIG_THERMAL_GOV_STEP_WISE=y +CONFIG_THERMAL_GOV_BANG_BANG=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_POWER_ALLOCATOR=y +CONFIG_CLOCK_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_THERMAL_EMULATION=y + +# +# Intel thermal drivers +# +CONFIG_INTEL_POWERCLAMP=m +CONFIG_X86_PKG_TEMP_THERMAL=m +CONFIG_INTEL_SOC_DTS_IOSF_CORE=m +CONFIG_INTEL_SOC_DTS_THERMAL=m + +# +# ACPI INT340X thermal drivers +# +CONFIG_INT340X_THERMAL=m +CONFIG_ACPI_THERMAL_REL=m +CONFIG_INT3406_THERMAL=m +CONFIG_PROC_THERMAL_MMIO_RAPL=y +# end of ACPI INT340X thermal drivers + +CONFIG_INTEL_BXT_PMIC_THERMAL=m +CONFIG_INTEL_PCH_THERMAL=m +# end of Intel thermal drivers + +CONFIG_GENERIC_ADC_THERMAL=m +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_CORE=y +CONFIG_WATCHDOG_NOWAYOUT=y +CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED=y +CONFIG_WATCHDOG_OPEN_TIMEOUT=0 +CONFIG_WATCHDOG_SYSFS=y + +# +# Watchdog Pretimeout Governors +# +# CONFIG_WATCHDOG_PRETIMEOUT_GOV is not set + +# +# Watchdog Device Drivers +# +CONFIG_SOFT_WATCHDOG=m +CONFIG_DA9052_WATCHDOG=m +CONFIG_DA9055_WATCHDOG=m +CONFIG_DA9063_WATCHDOG=m +CONFIG_DA9062_WATCHDOG=m +CONFIG_MENF21BMC_WATCHDOG=m +CONFIG_WDAT_WDT=m +CONFIG_WM831X_WATCHDOG=m +CONFIG_WM8350_WATCHDOG=m +# CONFIG_XILINX_WATCHDOG is not set +CONFIG_ZIIRAVE_WATCHDOG=m +CONFIG_MLX_WDT=m +# CONFIG_CADENCE_WATCHDOG is not set +CONFIG_DW_WATCHDOG=m +CONFIG_TWL4030_WATCHDOG=m +CONFIG_MAX63XX_WATCHDOG=m +CONFIG_RETU_WATCHDOG=m +CONFIG_ACQUIRE_WDT=m +CONFIG_ADVANTECH_WDT=m +CONFIG_ALIM1535_WDT=m +CONFIG_ALIM7101_WDT=m +CONFIG_EBC_C384_WDT=m +CONFIG_F71808E_WDT=m +CONFIG_SP5100_TCO=m +CONFIG_SBC_FITPC2_WATCHDOG=m +CONFIG_EUROTECH_WDT=m +CONFIG_IB700_WDT=m +CONFIG_IBMASR=m +CONFIG_WAFER_WDT=m +CONFIG_I6300ESB_WDT=m +CONFIG_IE6XX_WDT=m +CONFIG_ITCO_WDT=m +CONFIG_ITCO_VENDOR_SUPPORT=y +CONFIG_IT8712F_WDT=m +CONFIG_IT87_WDT=m +CONFIG_HP_WATCHDOG=m +# CONFIG_HPWDT_NMI_DECODING is not set +CONFIG_KEMPLD_WDT=m +CONFIG_SC1200_WDT=m +CONFIG_PC87413_WDT=m +CONFIG_NV_TCO=m +CONFIG_60XX_WDT=m +CONFIG_CPU5_WDT=m +CONFIG_SMSC_SCH311X_WDT=m +CONFIG_SMSC37B787_WDT=m +# CONFIG_TQMX86_WDT is not set +CONFIG_VIA_WDT=m +CONFIG_W83627HF_WDT=m +CONFIG_W83877F_WDT=m +CONFIG_W83977F_WDT=m +CONFIG_MACHZ_WDT=m +CONFIG_SBC_EPX_C3_WATCHDOG=m +CONFIG_INTEL_MEI_WDT=m +CONFIG_NI903X_WDT=m +CONFIG_NIC7018_WDT=m +CONFIG_MEN_A21_WDT=m +CONFIG_XEN_WDT=m + +# +# PCI-based Watchdog Cards +# +CONFIG_PCIPCWATCHDOG=m +CONFIG_WDTPCI=m + +# +# USB-based Watchdog Cards +# +CONFIG_USBPCWATCHDOG=m +CONFIG_SSB_POSSIBLE=y +CONFIG_SSB=m +CONFIG_SSB_SPROM=y +CONFIG_SSB_BLOCKIO=y +CONFIG_SSB_PCIHOST_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +CONFIG_SSB_B43_PCI_BRIDGE=y +CONFIG_SSB_PCMCIAHOST_POSSIBLE=y +CONFIG_SSB_PCMCIAHOST=y +CONFIG_SSB_SDIOHOST_POSSIBLE=y +CONFIG_SSB_SDIOHOST=y +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +CONFIG_SSB_DRIVER_PCICORE=y +CONFIG_SSB_DRIVER_GPIO=y +CONFIG_BCMA_POSSIBLE=y +CONFIG_BCMA=m +CONFIG_BCMA_BLOCKIO=y +CONFIG_BCMA_HOST_PCI_POSSIBLE=y +CONFIG_BCMA_HOST_PCI=y +CONFIG_BCMA_HOST_SOC=y +CONFIG_BCMA_DRIVER_PCI=y +CONFIG_BCMA_SFLASH=y +CONFIG_BCMA_DRIVER_GMAC_CMN=y +CONFIG_BCMA_DRIVER_GPIO=y +# CONFIG_BCMA_DEBUG is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=y +CONFIG_MFD_AS3711=y +CONFIG_PMIC_ADP5520=y +CONFIG_MFD_AAT2870_CORE=y +CONFIG_MFD_BCM590XX=m +CONFIG_MFD_BD9571MWV=m +CONFIG_MFD_AXP20X=m +CONFIG_MFD_AXP20X_I2C=m +CONFIG_MFD_CROS_EC_DEV=m +CONFIG_MFD_MADERA=m +CONFIG_MFD_MADERA_I2C=m +CONFIG_MFD_MADERA_SPI=m +CONFIG_MFD_CS47L15=y +CONFIG_MFD_CS47L35=y +CONFIG_MFD_CS47L85=y +CONFIG_MFD_CS47L90=y +CONFIG_MFD_CS47L92=y +CONFIG_PMIC_DA903X=y +CONFIG_PMIC_DA9052=y +CONFIG_MFD_DA9052_SPI=y +CONFIG_MFD_DA9052_I2C=y +CONFIG_MFD_DA9055=y +CONFIG_MFD_DA9062=m +CONFIG_MFD_DA9063=y +# CONFIG_MFD_DA9150 is not set +CONFIG_MFD_DLN2=m +CONFIG_MFD_MC13XXX=m +CONFIG_MFD_MC13XXX_SPI=m +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_HTC_PASIC3 is not set +CONFIG_HTC_I2CPLD=y +CONFIG_MFD_INTEL_QUARK_I2C_GPIO=m +CONFIG_LPC_ICH=m +CONFIG_LPC_SCH=m +CONFIG_INTEL_SOC_PMIC=y +CONFIG_INTEL_SOC_PMIC_BXTWC=m +CONFIG_INTEL_SOC_PMIC_CHTWC=y +CONFIG_INTEL_SOC_PMIC_CHTDC_TI=m +CONFIG_MFD_INTEL_LPSS=m +CONFIG_MFD_INTEL_LPSS_ACPI=m +CONFIG_MFD_INTEL_LPSS_PCI=m +# CONFIG_MFD_JANZ_CMODIO is not set +CONFIG_MFD_KEMPLD=m +CONFIG_MFD_88PM800=m +CONFIG_MFD_88PM805=m +CONFIG_MFD_88PM860X=y +CONFIG_MFD_MAX14577=y +CONFIG_MFD_MAX77693=y +# CONFIG_MFD_MAX77843 is not set +CONFIG_MFD_MAX8907=m +CONFIG_MFD_MAX8925=y +CONFIG_MFD_MAX8997=y +CONFIG_MFD_MAX8998=y +# CONFIG_MFD_MT6397 is not set +CONFIG_MFD_MENF21BMC=m +CONFIG_EZX_PCAP=y +CONFIG_MFD_VIPERBOARD=m +CONFIG_MFD_RETU=m +# CONFIG_MFD_PCF50633 is not set +# CONFIG_UCB1400_CORE is not set +CONFIG_MFD_RDC321X=m +# CONFIG_MFD_RT5033 is not set +CONFIG_MFD_RC5T583=y +CONFIG_MFD_SEC_CORE=y +CONFIG_MFD_SI476X_CORE=m +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SKY81452 is not set +CONFIG_MFD_SMSC=y +# CONFIG_ABX500_CORE is not set +CONFIG_MFD_SYSCON=y +CONFIG_MFD_TI_AM335X_TSCADC=m +CONFIG_MFD_LP3943=m +CONFIG_MFD_LP8788=y +CONFIG_MFD_TI_LMU=m +CONFIG_MFD_PALMAS=y +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +CONFIG_MFD_TPS65086=m +CONFIG_MFD_TPS65090=y +CONFIG_MFD_TPS68470=y +# CONFIG_MFD_TI_LP873X is not set +CONFIG_MFD_TPS6586X=y +CONFIG_MFD_TPS65910=y +CONFIG_MFD_TPS65912=y +CONFIG_MFD_TPS65912_I2C=y +CONFIG_MFD_TPS65912_SPI=y +CONFIG_MFD_TPS80031=y +CONFIG_TWL4030_CORE=y +CONFIG_MFD_TWL4030_AUDIO=y +CONFIG_TWL6040_CORE=y +CONFIG_MFD_WL1273_CORE=m +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TQMX86 is not set +CONFIG_MFD_VX855=m +CONFIG_MFD_ARIZONA=y +CONFIG_MFD_ARIZONA_I2C=m +CONFIG_MFD_ARIZONA_SPI=m +CONFIG_MFD_CS47L24=y +CONFIG_MFD_WM5102=y +CONFIG_MFD_WM5110=y +CONFIG_MFD_WM8997=y +# CONFIG_MFD_WM8998 is not set +CONFIG_MFD_WM8400=y +CONFIG_MFD_WM831X=y +CONFIG_MFD_WM831X_I2C=y +CONFIG_MFD_WM831X_SPI=y +CONFIG_MFD_WM8350=y +CONFIG_MFD_WM8350_I2C=y +CONFIG_MFD_WM8994=y +# CONFIG_RAVE_SP_CORE is not set +# end of Multifunction device drivers + +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +CONFIG_REGULATOR_FIXED_VOLTAGE=m +CONFIG_REGULATOR_VIRTUAL_CONSUMER=m +CONFIG_REGULATOR_USERSPACE_CONSUMER=m +# CONFIG_REGULATOR_88PG86X is not set +CONFIG_REGULATOR_88PM800=m +CONFIG_REGULATOR_88PM8607=m +CONFIG_REGULATOR_ACT8865=m +CONFIG_REGULATOR_AD5398=m +CONFIG_REGULATOR_ANATOP=m +CONFIG_REGULATOR_AAT2870=m +# CONFIG_REGULATOR_ARIZONA_LDO1 is not set +# CONFIG_REGULATOR_ARIZONA_MICSUPP is not set +CONFIG_REGULATOR_AS3711=m +CONFIG_REGULATOR_AXP20X=m +CONFIG_REGULATOR_BCM590XX=m +CONFIG_REGULATOR_BD9571MWV=m +CONFIG_REGULATOR_DA903X=m +CONFIG_REGULATOR_DA9052=m +CONFIG_REGULATOR_DA9055=m +CONFIG_REGULATOR_DA9062=m +CONFIG_REGULATOR_DA9210=m +CONFIG_REGULATOR_DA9211=m +CONFIG_REGULATOR_FAN53555=m +CONFIG_REGULATOR_GPIO=m +CONFIG_REGULATOR_ISL9305=m +CONFIG_REGULATOR_ISL6271A=m +# CONFIG_REGULATOR_LM363X is not set +CONFIG_REGULATOR_LP3971=m +CONFIG_REGULATOR_LP3972=m +CONFIG_REGULATOR_LP872X=m +CONFIG_REGULATOR_LP8755=m +CONFIG_REGULATOR_LP8788=m +CONFIG_REGULATOR_LTC3589=m +# CONFIG_REGULATOR_LTC3676 is not set +CONFIG_REGULATOR_MAX14577=m +CONFIG_REGULATOR_MAX1586=m +CONFIG_REGULATOR_MAX8649=m +CONFIG_REGULATOR_MAX8660=m +CONFIG_REGULATOR_MAX8907=m +CONFIG_REGULATOR_MAX8925=m +CONFIG_REGULATOR_MAX8952=m +CONFIG_REGULATOR_MAX8997=m +CONFIG_REGULATOR_MAX8998=m +CONFIG_REGULATOR_MAX77693=m +CONFIG_REGULATOR_MC13XXX_CORE=m +CONFIG_REGULATOR_MC13783=m +CONFIG_REGULATOR_MC13892=m +CONFIG_REGULATOR_MT6311=m +CONFIG_REGULATOR_PALMAS=m +CONFIG_REGULATOR_PCAP=m +CONFIG_REGULATOR_PFUZE100=m +CONFIG_REGULATOR_PV88060=m +CONFIG_REGULATOR_PV88080=m +CONFIG_REGULATOR_PV88090=m +CONFIG_REGULATOR_PWM=m +CONFIG_REGULATOR_QCOM_SPMI=m +CONFIG_REGULATOR_RC5T583=m +CONFIG_REGULATOR_S2MPA01=m +CONFIG_REGULATOR_S2MPS11=m +CONFIG_REGULATOR_S5M8767=m +# CONFIG_REGULATOR_SLG51000 is not set +CONFIG_REGULATOR_TPS51632=m +CONFIG_REGULATOR_TPS62360=m +CONFIG_REGULATOR_TPS65023=m +CONFIG_REGULATOR_TPS6507X=m +CONFIG_REGULATOR_TPS65086=m +CONFIG_REGULATOR_TPS65090=m +# CONFIG_REGULATOR_TPS65132 is not set +CONFIG_REGULATOR_TPS6524X=m +CONFIG_REGULATOR_TPS6586X=m +CONFIG_REGULATOR_TPS65910=m +CONFIG_REGULATOR_TPS65912=m +CONFIG_REGULATOR_TPS80031=m +CONFIG_REGULATOR_TWL4030=m +CONFIG_REGULATOR_WM831X=m +CONFIG_REGULATOR_WM8350=m +CONFIG_REGULATOR_WM8400=m +CONFIG_REGULATOR_WM8994=m +CONFIG_CEC_CORE=y +CONFIG_CEC_NOTIFIER=y +CONFIG_RC_CORE=m +CONFIG_RC_MAP=m +CONFIG_LIRC=y +CONFIG_RC_DECODERS=y +CONFIG_IR_NEC_DECODER=m +CONFIG_IR_RC5_DECODER=m +CONFIG_IR_RC6_DECODER=m +CONFIG_IR_JVC_DECODER=m +CONFIG_IR_SONY_DECODER=m +CONFIG_IR_SANYO_DECODER=m +CONFIG_IR_SHARP_DECODER=m +CONFIG_IR_MCE_KBD_DECODER=m +CONFIG_IR_XMP_DECODER=m +CONFIG_IR_IMON_DECODER=m +CONFIG_IR_RCMM_DECODER=m +CONFIG_RC_DEVICES=y +CONFIG_RC_ATI_REMOTE=m +CONFIG_IR_ENE=m +CONFIG_IR_IMON=m +CONFIG_IR_IMON_RAW=m +CONFIG_IR_MCEUSB=m +CONFIG_IR_ITE_CIR=m +CONFIG_IR_FINTEK=m +CONFIG_IR_NUVOTON=m +CONFIG_IR_REDRAT3=m +CONFIG_IR_STREAMZAP=m +CONFIG_IR_WINBOND_CIR=m +CONFIG_IR_IGORPLUGUSB=m +CONFIG_IR_IGUANA=m +CONFIG_IR_TTUSBIR=m +CONFIG_RC_LOOPBACK=m +# CONFIG_IR_SERIAL is not set +CONFIG_IR_SIR=m +CONFIG_RC_XBOX_DVD=m +CONFIG_MEDIA_SUPPORT=m + +# +# Multimedia core support +# +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_ANALOG_TV_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +CONFIG_MEDIA_RADIO_SUPPORT=y +CONFIG_MEDIA_SDR_SUPPORT=y +CONFIG_MEDIA_CEC_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_MEDIA_CONTROLLER_DVB=y +CONFIG_MEDIA_CONTROLLER_REQUEST_API=y +CONFIG_VIDEO_DEV=m +# CONFIG_VIDEO_V4L2_SUBDEV_API is not set +CONFIG_VIDEO_V4L2=m +CONFIG_VIDEO_V4L2_I2C=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +CONFIG_VIDEO_TUNER=m +CONFIG_V4L2_MEM2MEM_DEV=m +CONFIG_V4L2_FWNODE=m +CONFIG_VIDEOBUF_GEN=m +CONFIG_VIDEOBUF_DMA_SG=m +CONFIG_VIDEOBUF_VMALLOC=m +CONFIG_DVB_CORE=m +# CONFIG_DVB_MMAP is not set +CONFIG_DVB_NET=y +CONFIG_TTPCI_EEPROM=m +CONFIG_DVB_MAX_ADAPTERS=8 +# CONFIG_DVB_DYNAMIC_MINORS is not set +# CONFIG_DVB_DEMUX_SECTION_LOSS_LOG is not set +# CONFIG_DVB_ULE_DEBUG is not set + +# +# Media drivers +# +CONFIG_MEDIA_USB_SUPPORT=y + +# +# Webcam devices +# +CONFIG_USB_VIDEO_CLASS=m +CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y +CONFIG_USB_GSPCA=m +CONFIG_USB_M5602=m +CONFIG_USB_STV06XX=m +CONFIG_USB_GL860=m +CONFIG_USB_GSPCA_BENQ=m +CONFIG_USB_GSPCA_CONEX=m +CONFIG_USB_GSPCA_CPIA1=m +CONFIG_USB_GSPCA_DTCS033=m +CONFIG_USB_GSPCA_ETOMS=m +CONFIG_USB_GSPCA_FINEPIX=m +CONFIG_USB_GSPCA_JEILINJ=m +CONFIG_USB_GSPCA_JL2005BCD=m +CONFIG_USB_GSPCA_KINECT=m +CONFIG_USB_GSPCA_KONICA=m +CONFIG_USB_GSPCA_MARS=m +CONFIG_USB_GSPCA_MR97310A=m +CONFIG_USB_GSPCA_NW80X=m +CONFIG_USB_GSPCA_OV519=m +CONFIG_USB_GSPCA_OV534=m +CONFIG_USB_GSPCA_OV534_9=m +CONFIG_USB_GSPCA_PAC207=m +CONFIG_USB_GSPCA_PAC7302=m +CONFIG_USB_GSPCA_PAC7311=m +CONFIG_USB_GSPCA_SE401=m +CONFIG_USB_GSPCA_SN9C2028=m +CONFIG_USB_GSPCA_SN9C20X=m +CONFIG_USB_GSPCA_SONIXB=m +CONFIG_USB_GSPCA_SONIXJ=m +CONFIG_USB_GSPCA_SPCA500=m +CONFIG_USB_GSPCA_SPCA501=m +CONFIG_USB_GSPCA_SPCA505=m +CONFIG_USB_GSPCA_SPCA506=m +CONFIG_USB_GSPCA_SPCA508=m +CONFIG_USB_GSPCA_SPCA561=m +CONFIG_USB_GSPCA_SPCA1528=m +CONFIG_USB_GSPCA_SQ905=m +CONFIG_USB_GSPCA_SQ905C=m +CONFIG_USB_GSPCA_SQ930X=m +CONFIG_USB_GSPCA_STK014=m +CONFIG_USB_GSPCA_STK1135=m +CONFIG_USB_GSPCA_STV0680=m +CONFIG_USB_GSPCA_SUNPLUS=m +CONFIG_USB_GSPCA_T613=m +CONFIG_USB_GSPCA_TOPRO=m +CONFIG_USB_GSPCA_TOUPTEK=m +CONFIG_USB_GSPCA_TV8532=m +CONFIG_USB_GSPCA_VC032X=m +CONFIG_USB_GSPCA_VICAM=m +CONFIG_USB_GSPCA_XIRLINK_CIT=m +CONFIG_USB_GSPCA_ZC3XX=m +CONFIG_USB_PWC=m +# CONFIG_USB_PWC_DEBUG is not set +CONFIG_USB_PWC_INPUT_EVDEV=y +CONFIG_VIDEO_CPIA2=m +CONFIG_USB_ZR364XX=m +CONFIG_USB_STKWEBCAM=m +CONFIG_USB_S2255=m +CONFIG_VIDEO_USBTV=m + +# +# Analog TV USB devices +# +CONFIG_VIDEO_PVRUSB2=m +CONFIG_VIDEO_PVRUSB2_SYSFS=y +CONFIG_VIDEO_PVRUSB2_DVB=y +# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set +CONFIG_VIDEO_HDPVR=m +CONFIG_VIDEO_USBVISION=m +CONFIG_VIDEO_STK1160_COMMON=m +CONFIG_VIDEO_STK1160=m +CONFIG_VIDEO_GO7007=m +CONFIG_VIDEO_GO7007_USB=m +CONFIG_VIDEO_GO7007_LOADER=m +CONFIG_VIDEO_GO7007_USB_S2250_BOARD=m + +# +# Analog/digital TV USB devices +# +CONFIG_VIDEO_AU0828=m +CONFIG_VIDEO_AU0828_V4L2=y +CONFIG_VIDEO_AU0828_RC=y +CONFIG_VIDEO_CX231XX=m +CONFIG_VIDEO_CX231XX_RC=y +CONFIG_VIDEO_CX231XX_ALSA=m +CONFIG_VIDEO_CX231XX_DVB=m +CONFIG_VIDEO_TM6000=m +CONFIG_VIDEO_TM6000_ALSA=m +CONFIG_VIDEO_TM6000_DVB=m + +# +# Digital TV USB devices +# +CONFIG_DVB_USB=m +# CONFIG_DVB_USB_DEBUG is not set +CONFIG_DVB_USB_DIB3000MC=m +CONFIG_DVB_USB_A800=m +CONFIG_DVB_USB_DIBUSB_MB=m +# CONFIG_DVB_USB_DIBUSB_MB_FAULTY is not set +CONFIG_DVB_USB_DIBUSB_MC=m +CONFIG_DVB_USB_DIB0700=m +CONFIG_DVB_USB_UMT_010=m +CONFIG_DVB_USB_CXUSB=m +# CONFIG_DVB_USB_CXUSB_ANALOG is not set +CONFIG_DVB_USB_M920X=m +CONFIG_DVB_USB_DIGITV=m +CONFIG_DVB_USB_VP7045=m +CONFIG_DVB_USB_VP702X=m +CONFIG_DVB_USB_GP8PSK=m +CONFIG_DVB_USB_NOVA_T_USB2=m +CONFIG_DVB_USB_TTUSB2=m +CONFIG_DVB_USB_DTT200U=m +CONFIG_DVB_USB_OPERA1=m +CONFIG_DVB_USB_AF9005=m +CONFIG_DVB_USB_AF9005_REMOTE=m +CONFIG_DVB_USB_PCTV452E=m +CONFIG_DVB_USB_DW2102=m +CONFIG_DVB_USB_CINERGY_T2=m +CONFIG_DVB_USB_DTV5100=m +CONFIG_DVB_USB_AZ6027=m +CONFIG_DVB_USB_TECHNISAT_USB2=m +CONFIG_DVB_USB_V2=m +CONFIG_DVB_USB_AF9015=m +CONFIG_DVB_USB_AF9035=m +CONFIG_DVB_USB_ANYSEE=m +CONFIG_DVB_USB_AU6610=m +CONFIG_DVB_USB_AZ6007=m +CONFIG_DVB_USB_CE6230=m +CONFIG_DVB_USB_EC168=m +CONFIG_DVB_USB_GL861=m +CONFIG_DVB_USB_LME2510=m +CONFIG_DVB_USB_MXL111SF=m +CONFIG_DVB_USB_RTL28XXU=m +CONFIG_DVB_USB_DVBSKY=m +CONFIG_DVB_USB_ZD1301=m +CONFIG_DVB_TTUSB_BUDGET=m +# CONFIG_DVB_TTUSB_DEC is not set +CONFIG_SMS_USB_DRV=m +CONFIG_DVB_B2C2_FLEXCOP_USB=m +# CONFIG_DVB_B2C2_FLEXCOP_USB_DEBUG is not set +CONFIG_DVB_AS102=m + +# +# Webcam, TV (analog/digital) USB devices +# +CONFIG_VIDEO_EM28XX=m +CONFIG_VIDEO_EM28XX_V4L2=m +CONFIG_VIDEO_EM28XX_ALSA=m +CONFIG_VIDEO_EM28XX_DVB=m +CONFIG_VIDEO_EM28XX_RC=m + +# +# Software defined radio USB devices +# +CONFIG_USB_AIRSPY=m +CONFIG_USB_HACKRF=m +CONFIG_USB_MSI2500=m + +# +# USB HDMI CEC adapters +# +CONFIG_USB_PULSE8_CEC=m +CONFIG_USB_RAINSHADOW_CEC=m +CONFIG_MEDIA_PCI_SUPPORT=y + +# +# Media capture support +# +CONFIG_VIDEO_MEYE=m +CONFIG_VIDEO_SOLO6X10=m +CONFIG_VIDEO_TW5864=m +CONFIG_VIDEO_TW68=m +CONFIG_VIDEO_TW686X=m + +# +# Media capture/analog TV support +# +CONFIG_VIDEO_IVTV=m +# CONFIG_VIDEO_IVTV_DEPRECATED_IOCTLS is not set +CONFIG_VIDEO_IVTV_ALSA=m +CONFIG_VIDEO_FB_IVTV=m +# CONFIG_VIDEO_FB_IVTV_FORCE_PAT is not set +CONFIG_VIDEO_HEXIUM_GEMINI=m +CONFIG_VIDEO_HEXIUM_ORION=m +CONFIG_VIDEO_MXB=m +CONFIG_VIDEO_DT3155=m + +# +# Media capture/analog/hybrid TV support +# +CONFIG_VIDEO_CX18=m +CONFIG_VIDEO_CX18_ALSA=m +CONFIG_VIDEO_CX23885=m +CONFIG_MEDIA_ALTERA_CI=m +CONFIG_VIDEO_CX25821=m +CONFIG_VIDEO_CX25821_ALSA=m +CONFIG_VIDEO_CX88=m +CONFIG_VIDEO_CX88_ALSA=m +CONFIG_VIDEO_CX88_BLACKBIRD=m +CONFIG_VIDEO_CX88_DVB=m +CONFIG_VIDEO_CX88_ENABLE_VP3054=y +CONFIG_VIDEO_CX88_VP3054=m +CONFIG_VIDEO_CX88_MPEG=m +CONFIG_VIDEO_BT848=m +CONFIG_DVB_BT8XX=m +CONFIG_VIDEO_SAA7134=m +CONFIG_VIDEO_SAA7134_ALSA=m +CONFIG_VIDEO_SAA7134_RC=y +CONFIG_VIDEO_SAA7134_DVB=m +CONFIG_VIDEO_SAA7134_GO7007=m +CONFIG_VIDEO_SAA7164=m + +# +# Media digital TV PCI Adapters +# +CONFIG_DVB_AV7110_IR=y +CONFIG_DVB_AV7110=m +CONFIG_DVB_AV7110_OSD=y +CONFIG_DVB_BUDGET_CORE=m +CONFIG_DVB_BUDGET=m +CONFIG_DVB_BUDGET_CI=m +CONFIG_DVB_BUDGET_AV=m +CONFIG_DVB_BUDGET_PATCH=m +CONFIG_DVB_B2C2_FLEXCOP_PCI=m +# CONFIG_DVB_B2C2_FLEXCOP_PCI_DEBUG is not set +CONFIG_DVB_PLUTO2=m +CONFIG_DVB_DM1105=m +CONFIG_DVB_PT1=m +CONFIG_DVB_PT3=m +CONFIG_MANTIS_CORE=m +CONFIG_DVB_MANTIS=m +CONFIG_DVB_HOPPER=m +CONFIG_DVB_NGENE=m +CONFIG_DVB_DDBRIDGE=m +# CONFIG_DVB_DDBRIDGE_MSIENABLE is not set +CONFIG_DVB_SMIPCIE=m +CONFIG_DVB_NETUP_UNIDVB=m +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_VIDEO_CAFE_CCIC=m +CONFIG_VIDEO_VIA_CAMERA=m +CONFIG_VIDEO_CADENCE=y +CONFIG_VIDEO_ASPEED=m +CONFIG_V4L_MEM2MEM_DRIVERS=y +CONFIG_VIDEO_MEM2MEM_DEINTERLACE=m +CONFIG_VIDEO_SH_VEU=m +CONFIG_V4L_TEST_DRIVERS=y +CONFIG_VIDEO_VIVID=m +# CONFIG_VIDEO_VIVID_CEC is not set +CONFIG_VIDEO_VIVID_MAX_DEVS=64 +CONFIG_VIDEO_VIM2M=m +CONFIG_VIDEO_VICODEC=m +CONFIG_DVB_PLATFORM_DRIVERS=y +CONFIG_CEC_PLATFORM_DRIVERS=y +CONFIG_VIDEO_CROS_EC_CEC=m +# CONFIG_VIDEO_SECO_CEC is not set +# CONFIG_SDR_PLATFORM_DRIVERS is not set + +# +# Supported MMC/SDIO adapters +# +CONFIG_SMS_SDIO_DRV=m +CONFIG_RADIO_ADAPTERS=y +CONFIG_RADIO_TEA575X=m +CONFIG_RADIO_SI470X=m +CONFIG_USB_SI470X=m +# CONFIG_I2C_SI470X is not set +# CONFIG_RADIO_SI4713 is not set +# CONFIG_RADIO_SI476X is not set +CONFIG_USB_MR800=m +CONFIG_USB_DSBR=m +CONFIG_RADIO_MAXIRADIO=m +CONFIG_RADIO_SHARK=m +CONFIG_RADIO_SHARK2=m +CONFIG_USB_KEENE=m +CONFIG_USB_RAREMONO=m +CONFIG_USB_MA901=m +CONFIG_RADIO_TEA5764=m +CONFIG_RADIO_SAA7706H=m +CONFIG_RADIO_TEF6862=m +CONFIG_RADIO_WL1273=m + +# +# Texas Instruments WL128x FM driver (ST based) +# +CONFIG_RADIO_WL128X=m +# end of Texas Instruments WL128x FM driver (ST based) + +# +# Supported FireWire (IEEE 1394) Adapters +# +CONFIG_DVB_FIREDTV=m +CONFIG_DVB_FIREDTV_INPUT=y +CONFIG_MEDIA_COMMON_OPTIONS=y + +# +# common driver options +# +CONFIG_VIDEO_CX2341X=m +CONFIG_VIDEO_TVEEPROM=m +CONFIG_CYPRESS_FIRMWARE=m +CONFIG_VIDEOBUF2_CORE=m +CONFIG_VIDEOBUF2_V4L2=m +CONFIG_VIDEOBUF2_MEMOPS=m +CONFIG_VIDEOBUF2_DMA_CONTIG=m +CONFIG_VIDEOBUF2_VMALLOC=m +CONFIG_VIDEOBUF2_DMA_SG=m +CONFIG_VIDEOBUF2_DVB=m +CONFIG_DVB_B2C2_FLEXCOP=m +CONFIG_VIDEO_SAA7146=m +CONFIG_VIDEO_SAA7146_VV=m +CONFIG_SMS_SIANO_MDTV=m +CONFIG_SMS_SIANO_RC=y +# CONFIG_SMS_SIANO_DEBUGFS is not set +CONFIG_VIDEO_V4L2_TPG=m + +# +# Media ancillary drivers (tuners, sensors, i2c, spi, frontends) +# +CONFIG_MEDIA_SUBDRV_AUTOSELECT=y +CONFIG_MEDIA_ATTACH=y +CONFIG_VIDEO_IR_I2C=m + +# +# I2C Encoders, decoders, sensors and other helper chips +# + +# +# Audio decoders, processors and mixers +# +CONFIG_VIDEO_TVAUDIO=m +CONFIG_VIDEO_TDA7432=m +CONFIG_VIDEO_TDA9840=m +CONFIG_VIDEO_TEA6415C=m +CONFIG_VIDEO_TEA6420=m +CONFIG_VIDEO_MSP3400=m +CONFIG_VIDEO_CS3308=m +CONFIG_VIDEO_CS5345=m +CONFIG_VIDEO_CS53L32A=m +CONFIG_VIDEO_TLV320AIC23B=m +CONFIG_VIDEO_UDA1342=m +CONFIG_VIDEO_WM8775=m +CONFIG_VIDEO_WM8739=m +CONFIG_VIDEO_VP27SMPX=m +CONFIG_VIDEO_SONY_BTF_MPX=m + +# +# RDS decoders +# +CONFIG_VIDEO_SAA6588=m + +# +# Video decoders +# +CONFIG_VIDEO_ADV7183=m +CONFIG_VIDEO_BT819=m +CONFIG_VIDEO_BT856=m +CONFIG_VIDEO_BT866=m +CONFIG_VIDEO_KS0127=m +CONFIG_VIDEO_ML86V7667=m +CONFIG_VIDEO_SAA7110=m +CONFIG_VIDEO_SAA711X=m +CONFIG_VIDEO_TVP514X=m +CONFIG_VIDEO_TVP5150=m +CONFIG_VIDEO_TVP7002=m +CONFIG_VIDEO_TW2804=m +CONFIG_VIDEO_TW9903=m +CONFIG_VIDEO_TW9906=m +CONFIG_VIDEO_TW9910=m +CONFIG_VIDEO_VPX3220=m + +# +# Video and audio decoders +# +CONFIG_VIDEO_SAA717X=m +CONFIG_VIDEO_CX25840=m + +# +# Video encoders +# +CONFIG_VIDEO_SAA7127=m +CONFIG_VIDEO_SAA7185=m +CONFIG_VIDEO_ADV7170=m +CONFIG_VIDEO_ADV7175=m +CONFIG_VIDEO_ADV7343=m +CONFIG_VIDEO_ADV7393=m +CONFIG_VIDEO_AK881X=m +CONFIG_VIDEO_THS8200=m + +# +# Camera sensor devices +# +CONFIG_VIDEO_OV2640=m +CONFIG_VIDEO_OV2659=m +CONFIG_VIDEO_OV2680=m +CONFIG_VIDEO_OV2685=m +CONFIG_VIDEO_OV6650=m +CONFIG_VIDEO_OV5695=m +CONFIG_VIDEO_OV772X=m +CONFIG_VIDEO_OV7640=m +CONFIG_VIDEO_OV7670=m +CONFIG_VIDEO_OV7740=m +CONFIG_VIDEO_OV9640=m +CONFIG_VIDEO_VS6624=m +CONFIG_VIDEO_MT9M111=m +CONFIG_VIDEO_MT9T112=m +CONFIG_VIDEO_MT9V011=m +CONFIG_VIDEO_MT9V111=m +CONFIG_VIDEO_SR030PC30=m +CONFIG_VIDEO_RJ54N1=m + +# +# Lens drivers +# +# CONFIG_VIDEO_AD5820 is not set + +# +# Flash devices +# +# CONFIG_VIDEO_ADP1653 is not set +# CONFIG_VIDEO_LM3560 is not set +# CONFIG_VIDEO_LM3646 is not set + +# +# Video improvement chips +# +CONFIG_VIDEO_UPD64031A=m +CONFIG_VIDEO_UPD64083=m + +# +# Audio/Video compression chips +# +CONFIG_VIDEO_SAA6752HS=m + +# +# SDR tuner chips +# +CONFIG_SDR_MAX2175=m + +# +# Miscellaneous helper chips +# +CONFIG_VIDEO_THS7303=m +CONFIG_VIDEO_M52790=m +CONFIG_VIDEO_I2C=m +# end of I2C Encoders, decoders, sensors and other helper chips + +# +# SPI helper chips +# +# end of SPI helper chips + +# +# Media SPI Adapters +# +# CONFIG_CXD2880_SPI_DRV is not set +# end of Media SPI Adapters + +CONFIG_MEDIA_TUNER=m + +# +# Customize TV tuners +# +CONFIG_MEDIA_TUNER_SIMPLE=m +CONFIG_MEDIA_TUNER_TDA18250=m +CONFIG_MEDIA_TUNER_TDA8290=m +CONFIG_MEDIA_TUNER_TDA827X=m +CONFIG_MEDIA_TUNER_TDA18271=m +CONFIG_MEDIA_TUNER_TDA9887=m +CONFIG_MEDIA_TUNER_TEA5761=m +CONFIG_MEDIA_TUNER_TEA5767=m +CONFIG_MEDIA_TUNER_MSI001=m +CONFIG_MEDIA_TUNER_MT20XX=m +CONFIG_MEDIA_TUNER_MT2060=m +CONFIG_MEDIA_TUNER_MT2063=m +CONFIG_MEDIA_TUNER_MT2266=m +CONFIG_MEDIA_TUNER_MT2131=m +CONFIG_MEDIA_TUNER_QT1010=m +CONFIG_MEDIA_TUNER_XC2028=m +CONFIG_MEDIA_TUNER_XC5000=m +CONFIG_MEDIA_TUNER_XC4000=m +CONFIG_MEDIA_TUNER_MXL5005S=m +CONFIG_MEDIA_TUNER_MXL5007T=m +CONFIG_MEDIA_TUNER_MC44S803=m +CONFIG_MEDIA_TUNER_MAX2165=m +CONFIG_MEDIA_TUNER_TDA18218=m +CONFIG_MEDIA_TUNER_FC0011=m +CONFIG_MEDIA_TUNER_FC0012=m +CONFIG_MEDIA_TUNER_FC0013=m +CONFIG_MEDIA_TUNER_TDA18212=m +CONFIG_MEDIA_TUNER_E4000=m +CONFIG_MEDIA_TUNER_FC2580=m +CONFIG_MEDIA_TUNER_M88RS6000T=m +CONFIG_MEDIA_TUNER_TUA9001=m +CONFIG_MEDIA_TUNER_SI2157=m +CONFIG_MEDIA_TUNER_IT913X=m +CONFIG_MEDIA_TUNER_R820T=m +CONFIG_MEDIA_TUNER_MXL301RF=m +CONFIG_MEDIA_TUNER_QM1D1C0042=m +CONFIG_MEDIA_TUNER_QM1D1B0004=m +# end of Customize TV tuners + +# +# Customise DVB Frontends +# + +# +# Multistandard (satellite) frontends +# +CONFIG_DVB_STB0899=m +CONFIG_DVB_STB6100=m +CONFIG_DVB_STV090x=m +CONFIG_DVB_STV0910=m +CONFIG_DVB_STV6110x=m +CONFIG_DVB_STV6111=m +CONFIG_DVB_MXL5XX=m +CONFIG_DVB_M88DS3103=m + +# +# Multistandard (cable + terrestrial) frontends +# +CONFIG_DVB_DRXK=m +CONFIG_DVB_TDA18271C2DD=m +CONFIG_DVB_SI2165=m +CONFIG_DVB_MN88472=m +CONFIG_DVB_MN88473=m + +# +# DVB-S (satellite) frontends +# +CONFIG_DVB_CX24110=m +CONFIG_DVB_CX24123=m +CONFIG_DVB_MT312=m +CONFIG_DVB_ZL10036=m +CONFIG_DVB_ZL10039=m +CONFIG_DVB_S5H1420=m +CONFIG_DVB_STV0288=m +CONFIG_DVB_STB6000=m +CONFIG_DVB_STV0299=m +CONFIG_DVB_STV6110=m +CONFIG_DVB_STV0900=m +CONFIG_DVB_TDA8083=m +CONFIG_DVB_TDA10086=m +CONFIG_DVB_TDA8261=m +CONFIG_DVB_VES1X93=m +CONFIG_DVB_TUNER_ITD1000=m +CONFIG_DVB_TUNER_CX24113=m +CONFIG_DVB_TDA826X=m +CONFIG_DVB_TUA6100=m +CONFIG_DVB_CX24116=m +CONFIG_DVB_CX24117=m +CONFIG_DVB_CX24120=m +CONFIG_DVB_SI21XX=m +CONFIG_DVB_TS2020=m +CONFIG_DVB_DS3000=m +CONFIG_DVB_MB86A16=m +CONFIG_DVB_TDA10071=m + +# +# DVB-T (terrestrial) frontends +# +CONFIG_DVB_SP8870=m +CONFIG_DVB_SP887X=m +CONFIG_DVB_CX22700=m +CONFIG_DVB_CX22702=m +CONFIG_DVB_S5H1432=m +CONFIG_DVB_DRXD=m +CONFIG_DVB_L64781=m +CONFIG_DVB_TDA1004X=m +CONFIG_DVB_NXT6000=m +CONFIG_DVB_MT352=m +CONFIG_DVB_ZL10353=m +CONFIG_DVB_DIB3000MB=m +CONFIG_DVB_DIB3000MC=m +CONFIG_DVB_DIB7000M=m +CONFIG_DVB_DIB7000P=m +CONFIG_DVB_DIB9000=m +CONFIG_DVB_TDA10048=m +CONFIG_DVB_AF9013=m +CONFIG_DVB_EC100=m +CONFIG_DVB_STV0367=m +CONFIG_DVB_CXD2820R=m +CONFIG_DVB_CXD2841ER=m +CONFIG_DVB_RTL2830=m +CONFIG_DVB_RTL2832=m +CONFIG_DVB_RTL2832_SDR=m +CONFIG_DVB_SI2168=m +CONFIG_DVB_AS102_FE=m +CONFIG_DVB_ZD1301_DEMOD=m +CONFIG_DVB_GP8PSK_FE=m +CONFIG_DVB_CXD2880=m + +# +# DVB-C (cable) frontends +# +CONFIG_DVB_VES1820=m +CONFIG_DVB_TDA10021=m +CONFIG_DVB_TDA10023=m +CONFIG_DVB_STV0297=m + +# +# ATSC (North American/Korean Terrestrial/Cable DTV) frontends +# +CONFIG_DVB_NXT200X=m +CONFIG_DVB_OR51211=m +CONFIG_DVB_OR51132=m +CONFIG_DVB_BCM3510=m +CONFIG_DVB_LGDT330X=m +CONFIG_DVB_LGDT3305=m +CONFIG_DVB_LGDT3306A=m +CONFIG_DVB_LG2160=m +CONFIG_DVB_S5H1409=m +CONFIG_DVB_AU8522=m +CONFIG_DVB_AU8522_DTV=m +CONFIG_DVB_AU8522_V4L=m +CONFIG_DVB_S5H1411=m + +# +# ISDB-T (terrestrial) frontends +# +CONFIG_DVB_S921=m +CONFIG_DVB_DIB8000=m +CONFIG_DVB_MB86A20S=m + +# +# ISDB-S (satellite) & ISDB-T (terrestrial) frontends +# +CONFIG_DVB_TC90522=m +CONFIG_DVB_MN88443X=m + +# +# Digital terrestrial only tuners/PLL +# +CONFIG_DVB_PLL=m +CONFIG_DVB_TUNER_DIB0070=m +CONFIG_DVB_TUNER_DIB0090=m + +# +# SEC control devices for DVB-S +# +CONFIG_DVB_DRX39XYJ=m +CONFIG_DVB_LNBH25=m +# CONFIG_DVB_LNBH29 is not set +CONFIG_DVB_LNBP21=m +CONFIG_DVB_LNBP22=m +CONFIG_DVB_ISL6405=m +CONFIG_DVB_ISL6421=m +CONFIG_DVB_ISL6423=m +CONFIG_DVB_A8293=m +CONFIG_DVB_LGS8GL5=m +CONFIG_DVB_LGS8GXX=m +CONFIG_DVB_ATBM8830=m +CONFIG_DVB_TDA665x=m +CONFIG_DVB_IX2505V=m +CONFIG_DVB_M88RS2000=m +CONFIG_DVB_AF9033=m +CONFIG_DVB_HORUS3A=m +CONFIG_DVB_ASCOT2E=m +CONFIG_DVB_HELENE=m + +# +# Common Interface (EN50221) controller drivers +# +CONFIG_DVB_CXD2099=m +CONFIG_DVB_SP2=m + +# +# Tools to develop new frontends +# +CONFIG_DVB_DUMMY_FE=m +# end of Customise DVB Frontends + +# +# Graphics support +# +CONFIG_AGP=y +CONFIG_AGP_AMD64=y +CONFIG_AGP_INTEL=y +CONFIG_AGP_SIS=y +CONFIG_AGP_VIA=y +CONFIG_INTEL_GTT=y +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +CONFIG_VGA_SWITCHEROO=y +CONFIG_DRM=m +CONFIG_DRM_MIPI_DSI=y +# CONFIG_DRM_DP_AUX_CHARDEV is not set +# CONFIG_DRM_DEBUG_SELFTEST is not set +CONFIG_DRM_KMS_HELPER=m +CONFIG_DRM_KMS_FB_HELPER=y +CONFIG_DRM_FBDEV_EMULATION=y +CONFIG_DRM_FBDEV_OVERALLOC=100 +# CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM is not set +# CONFIG_DRM_LOAD_EDID_FIRMWARE is not set +CONFIG_DRM_DP_CEC=y +CONFIG_DRM_TTM=m +CONFIG_DRM_VRAM_HELPER=m +CONFIG_DRM_GEM_SHMEM_HELPER=y +CONFIG_DRM_VM=y +CONFIG_DRM_SCHED=m + +# +# I2C encoder or helper chips +# +CONFIG_DRM_I2C_CH7006=m +CONFIG_DRM_I2C_SIL164=m +CONFIG_DRM_I2C_NXP_TDA998X=m +CONFIG_DRM_I2C_NXP_TDA9950=m +# end of I2C encoder or helper chips + +# +# ARM devices +# +# end of ARM devices + +CONFIG_DRM_RADEON=m +CONFIG_DRM_RADEON_USERPTR=y +CONFIG_DRM_AMDGPU=m +CONFIG_DRM_AMDGPU_SI=y +CONFIG_DRM_AMDGPU_CIK=y +CONFIG_DRM_AMDGPU_USERPTR=y +# CONFIG_DRM_AMDGPU_GART_DEBUGFS is not set + +# +# ACP (Audio CoProcessor) Configuration +# +CONFIG_DRM_AMD_ACP=y +# end of ACP (Audio CoProcessor) Configuration + +# +# Display Engine Configuration +# +CONFIG_DRM_AMD_DC=y +CONFIG_DRM_AMD_DC_DCN1_0=y +CONFIG_DRM_AMD_DC_DCN2_0=y +CONFIG_DRM_AMD_DC_DCN2_1=y +CONFIG_DRM_AMD_DC_DSC_SUPPORT=y +# CONFIG_DEBUG_KERNEL_DC is not set +# end of Display Engine Configuration + +CONFIG_HSA_AMD=y +CONFIG_DRM_NOUVEAU=m +# CONFIG_NOUVEAU_LEGACY_CTX_SUPPORT is not set +CONFIG_NOUVEAU_DEBUG=5 +CONFIG_NOUVEAU_DEBUG_DEFAULT=3 +# CONFIG_NOUVEAU_DEBUG_MMU is not set +CONFIG_DRM_NOUVEAU_BACKLIGHT=y +CONFIG_DRM_I915=m +CONFIG_DRM_I915_ALPHA_SUPPORT=y +CONFIG_DRM_I915_FORCE_PROBE="*" +CONFIG_DRM_I915_CAPTURE_ERROR=y +CONFIG_DRM_I915_COMPRESS_ERROR=y +CONFIG_DRM_I915_USERPTR=y +# CONFIG_DRM_I915_GVT is not set + +# +# drm/i915 Debugging +# +# CONFIG_DRM_I915_WERROR is not set +# CONFIG_DRM_I915_DEBUG is not set +# CONFIG_DRM_I915_DEBUG_MMIO is not set +# CONFIG_DRM_I915_SW_FENCE_DEBUG_OBJECTS is not set +# CONFIG_DRM_I915_SW_FENCE_CHECK_DAG is not set +# CONFIG_DRM_I915_DEBUG_GUC is not set +# CONFIG_DRM_I915_SELFTEST is not set +# CONFIG_DRM_I915_LOW_LEVEL_TRACEPOINTS is not set +# CONFIG_DRM_I915_DEBUG_VBLANK_EVADE is not set +# CONFIG_DRM_I915_DEBUG_RUNTIME_PM is not set +# end of drm/i915 Debugging + +# +# drm/i915 Profile Guided Optimisation +# +CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND=250 +CONFIG_DRM_I915_SPIN_REQUEST=5 +# end of drm/i915 Profile Guided Optimisation + +CONFIG_DRM_VGEM=m +# CONFIG_DRM_VKMS is not set +CONFIG_DRM_ATI_PCIGART=y +CONFIG_DRM_VMWGFX=m +# CONFIG_DRM_VMWGFX_FBCON is not set +CONFIG_DRM_GMA500=m +CONFIG_DRM_GMA600=y +CONFIG_DRM_GMA3600=y +CONFIG_DRM_UDL=m +CONFIG_DRM_AST=m +CONFIG_DRM_MGAG200=m +CONFIG_DRM_CIRRUS_QEMU=m +CONFIG_DRM_QXL=m +CONFIG_DRM_BOCHS=m +CONFIG_DRM_VIRTIO_GPU=m +CONFIG_DRM_PANEL=y + +# +# Display Panels +# +# CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN is not set +# end of Display Panels + +CONFIG_DRM_BRIDGE=y +CONFIG_DRM_PANEL_BRIDGE=y + +# +# Display Interface Bridges +# +# CONFIG_DRM_ANALOGIX_ANX78XX is not set +# end of Display Interface Bridges + +# CONFIG_DRM_ETNAVIV is not set +CONFIG_DRM_GM12U320=m +# CONFIG_TINYDRM_HX8357D is not set +# CONFIG_TINYDRM_ILI9225 is not set +# CONFIG_TINYDRM_ILI9341 is not set +# CONFIG_TINYDRM_MI0283QT is not set +# CONFIG_TINYDRM_REPAPER is not set +# CONFIG_TINYDRM_ST7586 is not set +# CONFIG_TINYDRM_ST7735R is not set +CONFIG_DRM_XEN=y +CONFIG_DRM_XEN_FRONTEND=m +CONFIG_DRM_VBOXVIDEO=m +CONFIG_DRM_LEGACY=y +CONFIG_DRM_TDFX=m +CONFIG_DRM_R128=m +CONFIG_DRM_I810=m +CONFIG_DRM_MGA=m +CONFIG_DRM_SIS=m +# CONFIG_DRM_VIA is not set +CONFIG_DRM_SAVAGE=m +CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y + +# +# Frame buffer Devices +# +CONFIG_FB_CMDLINE=y +CONFIG_FB_NOTIFY=y +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +CONFIG_FB_DDC=m +CONFIG_FB_BOOT_VESA_SUPPORT=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +CONFIG_FB_SYS_FILLRECT=y +CONFIG_FB_SYS_COPYAREA=y +CONFIG_FB_SYS_IMAGEBLIT=y +CONFIG_FB_FOREIGN_ENDIAN=y +CONFIG_FB_BOTH_ENDIAN=y +# CONFIG_FB_BIG_ENDIAN is not set +# CONFIG_FB_LITTLE_ENDIAN is not set +CONFIG_FB_SYS_FOPS=y +CONFIG_FB_DEFERRED_IO=y +CONFIG_FB_SVGALIB=m +CONFIG_FB_BACKLIGHT=m +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_TILEBLITTING=y + +# +# Frame buffer hardware drivers +# +CONFIG_FB_CIRRUS=m +CONFIG_FB_PM2=m +# CONFIG_FB_PM2_FIFO_DISCONNECT is not set +CONFIG_FB_CYBER2000=m +CONFIG_FB_CYBER2000_DDC=y +CONFIG_FB_ARC=m +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +CONFIG_FB_VGA16=m +CONFIG_FB_UVESA=m +CONFIG_FB_VESA=y +CONFIG_FB_EFI=y +# CONFIG_FB_N411 is not set +# CONFIG_FB_HGA is not set +CONFIG_FB_OPENCORES=m +# CONFIG_FB_S1D13XXX is not set +CONFIG_FB_NVIDIA=m +CONFIG_FB_NVIDIA_I2C=y +# CONFIG_FB_NVIDIA_DEBUG is not set +CONFIG_FB_NVIDIA_BACKLIGHT=y +CONFIG_FB_RIVA=m +# CONFIG_FB_RIVA_I2C is not set +# CONFIG_FB_RIVA_DEBUG is not set +CONFIG_FB_RIVA_BACKLIGHT=y +CONFIG_FB_I740=m +CONFIG_FB_LE80578=m +CONFIG_FB_CARILLO_RANCH=m +CONFIG_FB_INTEL=m +# CONFIG_FB_INTEL_DEBUG is not set +CONFIG_FB_INTEL_I2C=y +CONFIG_FB_MATROX=m +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_MATROX_G=y +CONFIG_FB_MATROX_I2C=m +CONFIG_FB_MATROX_MAVEN=m +CONFIG_FB_RADEON=m +CONFIG_FB_RADEON_I2C=y +CONFIG_FB_RADEON_BACKLIGHT=y +# CONFIG_FB_RADEON_DEBUG is not set +CONFIG_FB_ATY128=m +CONFIG_FB_ATY128_BACKLIGHT=y +CONFIG_FB_ATY=m +CONFIG_FB_ATY_CT=y +CONFIG_FB_ATY_GENERIC_LCD=y +CONFIG_FB_ATY_GX=y +CONFIG_FB_ATY_BACKLIGHT=y +CONFIG_FB_S3=m +CONFIG_FB_S3_DDC=y +CONFIG_FB_SAVAGE=m +CONFIG_FB_SAVAGE_I2C=y +CONFIG_FB_SAVAGE_ACCEL=y +CONFIG_FB_SIS=m +CONFIG_FB_SIS_300=y +CONFIG_FB_SIS_315=y +CONFIG_FB_VIA=m +# CONFIG_FB_VIA_DIRECT_PROCFS is not set +# CONFIG_FB_VIA_X_COMPATIBILITY is not set +CONFIG_FB_NEOMAGIC=m +CONFIG_FB_KYRO=m +CONFIG_FB_3DFX=m +# CONFIG_FB_3DFX_ACCEL is not set +CONFIG_FB_3DFX_I2C=y +CONFIG_FB_VOODOO1=m +CONFIG_FB_VT8623=m +CONFIG_FB_TRIDENT=m +CONFIG_FB_ARK=m +CONFIG_FB_PM3=m +CONFIG_FB_CARMINE=m +CONFIG_FB_CARMINE_DRAM_EVAL=y +# CONFIG_CARMINE_DRAM_CUSTOM is not set +CONFIG_FB_SMSCUFX=m +CONFIG_FB_UDL=m +CONFIG_FB_IBM_GXT4500=m +# CONFIG_FB_VIRTUAL is not set +CONFIG_XEN_FBDEV_FRONTEND=y +# CONFIG_FB_METRONOME is not set +CONFIG_FB_MB862XX=m +CONFIG_FB_MB862XX_PCI_GDC=y +CONFIG_FB_MB862XX_I2C=y +CONFIG_FB_HYPERV=m +CONFIG_FB_SIMPLE=y +CONFIG_FB_SM712=m +# end of Frame buffer Devices + +# +# Backlight & LCD device support +# +CONFIG_LCD_CLASS_DEVICE=m +CONFIG_LCD_L4F00242T03=m +CONFIG_LCD_LMS283GF05=m +CONFIG_LCD_LTV350QV=m +CONFIG_LCD_ILI922X=m +CONFIG_LCD_ILI9320=m +CONFIG_LCD_TDO24M=m +CONFIG_LCD_VGG2432A4=m +# CONFIG_LCD_PLATFORM is not set +CONFIG_LCD_AMS369FG06=m +CONFIG_LCD_LMS501KF03=m +CONFIG_LCD_HX8357=m +# CONFIG_LCD_OTM3225A is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_GENERIC is not set +CONFIG_BACKLIGHT_CARILLO_RANCH=m +CONFIG_BACKLIGHT_PWM=m +CONFIG_BACKLIGHT_DA903X=m +CONFIG_BACKLIGHT_DA9052=m +CONFIG_BACKLIGHT_MAX8925=m +CONFIG_BACKLIGHT_APPLE=m +CONFIG_BACKLIGHT_PM8941_WLED=m +CONFIG_BACKLIGHT_SAHARA=m +CONFIG_BACKLIGHT_WM831X=m +CONFIG_BACKLIGHT_ADP5520=m +CONFIG_BACKLIGHT_ADP8860=m +CONFIG_BACKLIGHT_ADP8870=m +CONFIG_BACKLIGHT_88PM860X=m +CONFIG_BACKLIGHT_AAT2870=m +CONFIG_BACKLIGHT_LM3630A=m +CONFIG_BACKLIGHT_LM3639=m +CONFIG_BACKLIGHT_LP855X=m +CONFIG_BACKLIGHT_LP8788=m +CONFIG_BACKLIGHT_PANDORA=m +CONFIG_BACKLIGHT_AS3711=m +CONFIG_BACKLIGHT_GPIO=m +CONFIG_BACKLIGHT_LV5207LP=m +CONFIG_BACKLIGHT_BD6107=m +CONFIG_BACKLIGHT_ARCXCNN=m +# end of Backlight & LCD device support + +CONFIG_VGASTATE=m +CONFIG_VIDEOMODE_HELPERS=y +CONFIG_HDMI=y + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +# CONFIG_VGACON_SOFT_SCROLLBACK is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_DUMMY_CONSOLE_COLUMNS=80 +CONFIG_DUMMY_CONSOLE_ROWS=25 +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +# CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER is not set +# end of Console display driver support + +# CONFIG_LOGO is not set +# end of Graphics support + +CONFIG_SOUND=m +CONFIG_SOUND_OSS_CORE=y +# CONFIG_SOUND_OSS_CORE_PRECLAIM is not set +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_PCM_ELD=y +CONFIG_SND_PCM_IEC958=y +CONFIG_SND_HWDEP=m +CONFIG_SND_SEQ_DEVICE=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_COMPRESS_OFFLOAD=m +CONFIG_SND_JACK=y +CONFIG_SND_JACK_INPUT_DEV=y +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +CONFIG_SND_PCM_OSS_PLUGINS=y +CONFIG_SND_PCM_TIMER=y +CONFIG_SND_HRTIMER=m +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_MAX_CARDS=32 +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_PROC_FS=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +CONFIG_SND_DEBUG=y +# CONFIG_SND_DEBUG_VERBOSE is not set +CONFIG_SND_PCM_XRUN_DEBUG=y +CONFIG_SND_VMASTER=y +CONFIG_SND_DMA_SGBUF=y +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_SEQUENCER_OSS=m +CONFIG_SND_SEQ_HRTIMER_DEFAULT=y +CONFIG_SND_SEQ_MIDI_EVENT=m +CONFIG_SND_SEQ_MIDI=m +CONFIG_SND_SEQ_MIDI_EMUL=m +CONFIG_SND_SEQ_VIRMIDI=m +CONFIG_SND_MPU401_UART=m +CONFIG_SND_OPL3_LIB=m +CONFIG_SND_OPL3_LIB_SEQ=m +CONFIG_SND_VX_LIB=m +CONFIG_SND_AC97_CODEC=m +CONFIG_SND_DRIVERS=y +# CONFIG_SND_PCSP is not set +CONFIG_SND_DUMMY=m +CONFIG_SND_ALOOP=m +CONFIG_SND_VIRMIDI=m +CONFIG_SND_MTPAV=m +CONFIG_SND_MTS64=m +CONFIG_SND_SERIAL_U16550=m +CONFIG_SND_MPU401=m +CONFIG_SND_PORTMAN2X4=m +CONFIG_SND_AC97_POWER_SAVE=y +CONFIG_SND_AC97_POWER_SAVE_DEFAULT=0 +CONFIG_SND_SB_COMMON=m +CONFIG_SND_PCI=y +CONFIG_SND_AD1889=m +CONFIG_SND_ALS300=m +CONFIG_SND_ALS4000=m +CONFIG_SND_ALI5451=m +CONFIG_SND_ASIHPI=m +CONFIG_SND_ATIIXP=m +CONFIG_SND_ATIIXP_MODEM=m +CONFIG_SND_AU8810=m +CONFIG_SND_AU8820=m +CONFIG_SND_AU8830=m +CONFIG_SND_AW2=m +CONFIG_SND_AZT3328=m +CONFIG_SND_BT87X=m +# CONFIG_SND_BT87X_OVERCLOCK is not set +CONFIG_SND_CA0106=m +CONFIG_SND_CMIPCI=m +CONFIG_SND_OXYGEN_LIB=m +CONFIG_SND_OXYGEN=m +CONFIG_SND_CS4281=m +CONFIG_SND_CS46XX=m +CONFIG_SND_CS46XX_NEW_DSP=y +CONFIG_SND_CTXFI=m +CONFIG_SND_DARLA20=m +CONFIG_SND_GINA20=m +CONFIG_SND_LAYLA20=m +CONFIG_SND_DARLA24=m +CONFIG_SND_GINA24=m +CONFIG_SND_LAYLA24=m +CONFIG_SND_MONA=m +CONFIG_SND_MIA=m +CONFIG_SND_ECHO3G=m +CONFIG_SND_INDIGO=m +CONFIG_SND_INDIGOIO=m +CONFIG_SND_INDIGODJ=m +CONFIG_SND_INDIGOIOX=m +CONFIG_SND_INDIGODJX=m +CONFIG_SND_EMU10K1=m +CONFIG_SND_EMU10K1_SEQ=m +CONFIG_SND_EMU10K1X=m +CONFIG_SND_ENS1370=m +CONFIG_SND_ENS1371=m +CONFIG_SND_ES1938=m +CONFIG_SND_ES1968=m +CONFIG_SND_ES1968_INPUT=y +CONFIG_SND_ES1968_RADIO=y +CONFIG_SND_FM801=m +CONFIG_SND_FM801_TEA575X_BOOL=y +CONFIG_SND_HDSP=m +CONFIG_SND_HDSPM=m +CONFIG_SND_ICE1712=m +CONFIG_SND_ICE1724=m +CONFIG_SND_INTEL8X0=m +CONFIG_SND_INTEL8X0M=m +CONFIG_SND_KORG1212=m +CONFIG_SND_LOLA=m +CONFIG_SND_LX6464ES=m +CONFIG_SND_MAESTRO3=m +CONFIG_SND_MAESTRO3_INPUT=y +CONFIG_SND_MIXART=m +CONFIG_SND_NM256=m +CONFIG_SND_PCXHR=m +CONFIG_SND_RIPTIDE=m +CONFIG_SND_RME32=m +CONFIG_SND_RME96=m +CONFIG_SND_RME9652=m +CONFIG_SND_SONICVIBES=m +CONFIG_SND_TRIDENT=m +CONFIG_SND_VIA82XX=m +CONFIG_SND_VIA82XX_MODEM=m +CONFIG_SND_VIRTUOSO=m +CONFIG_SND_VX222=m +CONFIG_SND_YMFPCI=m + +# +# HD-Audio +# +CONFIG_SND_HDA=m +CONFIG_SND_HDA_INTEL=m +# CONFIG_SND_HDA_INTEL_DETECT_DMIC is not set +CONFIG_SND_HDA_HWDEP=y +CONFIG_SND_HDA_RECONFIG=y +CONFIG_SND_HDA_INPUT_BEEP=y +CONFIG_SND_HDA_INPUT_BEEP_MODE=1 +CONFIG_SND_HDA_PATCH_LOADER=y +CONFIG_SND_HDA_CODEC_REALTEK=m +CONFIG_SND_HDA_CODEC_ANALOG=m +CONFIG_SND_HDA_CODEC_SIGMATEL=m +CONFIG_SND_HDA_CODEC_VIA=m +CONFIG_SND_HDA_CODEC_HDMI=m +CONFIG_SND_HDA_CODEC_CIRRUS=m +CONFIG_SND_HDA_CODEC_CONEXANT=m +CONFIG_SND_HDA_CODEC_CA0110=m +CONFIG_SND_HDA_CODEC_CA0132=m +CONFIG_SND_HDA_CODEC_CA0132_DSP=y +CONFIG_SND_HDA_CODEC_CMEDIA=m +CONFIG_SND_HDA_CODEC_SI3054=m +CONFIG_SND_HDA_GENERIC=m +CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0 +# end of HD-Audio + +CONFIG_SND_HDA_CORE=m +CONFIG_SND_HDA_DSP_LOADER=y +CONFIG_SND_HDA_COMPONENT=y +CONFIG_SND_HDA_I915=y +CONFIG_SND_HDA_EXT_CORE=m +CONFIG_SND_HDA_PREALLOC_SIZE=2048 +CONFIG_SND_INTEL_NHLT=m +CONFIG_SND_SPI=y +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=m +CONFIG_SND_USB_AUDIO_USE_MEDIA_CONTROLLER=y +CONFIG_SND_USB_UA101=m +CONFIG_SND_USB_USX2Y=m +CONFIG_SND_USB_CAIAQ=m +CONFIG_SND_USB_CAIAQ_INPUT=y +CONFIG_SND_USB_US122L=m +CONFIG_SND_USB_6FIRE=m +CONFIG_SND_USB_HIFACE=m +CONFIG_SND_BCD2000=m +CONFIG_SND_USB_LINE6=m +# CONFIG_SND_USB_POD is not set +# CONFIG_SND_USB_PODHD is not set +# CONFIG_SND_USB_TONEPORT is not set +CONFIG_SND_USB_VARIAX=m +CONFIG_SND_FIREWIRE=y +CONFIG_SND_FIREWIRE_LIB=m +CONFIG_SND_DICE=m +CONFIG_SND_OXFW=m +CONFIG_SND_ISIGHT=m +CONFIG_SND_FIREWORKS=m +CONFIG_SND_BEBOB=m +CONFIG_SND_FIREWIRE_DIGI00X=m +CONFIG_SND_FIREWIRE_TASCAM=m +CONFIG_SND_FIREWIRE_MOTU=m +CONFIG_SND_FIREFACE=m +CONFIG_SND_PCMCIA=y +CONFIG_SND_VXPOCKET=m +CONFIG_SND_PDAUDIOCF=m +CONFIG_SND_SOC=m +CONFIG_SND_SOC_AC97_BUS=y +CONFIG_SND_SOC_COMPRESS=y +CONFIG_SND_SOC_TOPOLOGY=y +CONFIG_SND_SOC_ACPI=m +CONFIG_SND_SOC_AMD_ACP=m +CONFIG_SND_SOC_AMD_CZ_DA7219MX98357_MACH=m +CONFIG_SND_SOC_AMD_CZ_RT5645_MACH=m +CONFIG_SND_SOC_AMD_ACP3x=m +# CONFIG_SND_ATMEL_SOC is not set +# CONFIG_SND_DESIGNWARE_I2S is not set + +# +# SoC Audio for Freescale CPUs +# + +# +# Common SoC Audio options for Freescale CPUs: +# +# CONFIG_SND_SOC_FSL_ASRC is not set +# CONFIG_SND_SOC_FSL_SAI is not set +# CONFIG_SND_SOC_FSL_AUDMIX is not set +# CONFIG_SND_SOC_FSL_SSI is not set +# CONFIG_SND_SOC_FSL_SPDIF is not set +# CONFIG_SND_SOC_FSL_ESAI is not set +# CONFIG_SND_SOC_FSL_MICFIL is not set +# CONFIG_SND_SOC_IMX_AUDMUX is not set +# end of SoC Audio for Freescale CPUs + +# CONFIG_SND_I2S_HI6210_I2S is not set +# CONFIG_SND_SOC_IMG is not set +CONFIG_SND_SOC_INTEL_SST_TOPLEVEL=y +CONFIG_SND_SST_IPC=m +CONFIG_SND_SST_IPC_PCI=m +CONFIG_SND_SST_IPC_ACPI=m +CONFIG_SND_SOC_INTEL_SST_ACPI=m +CONFIG_SND_SOC_INTEL_SST=m +CONFIG_SND_SOC_INTEL_SST_FIRMWARE=m +CONFIG_SND_SOC_INTEL_HASWELL=m +CONFIG_SND_SST_ATOM_HIFI2_PLATFORM=m +CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_PCI=m +CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI=m +CONFIG_SND_SOC_INTEL_SKYLAKE=m +CONFIG_SND_SOC_INTEL_SKL=m +CONFIG_SND_SOC_INTEL_APL=m +CONFIG_SND_SOC_INTEL_KBL=m +CONFIG_SND_SOC_INTEL_GLK=m +CONFIG_SND_SOC_INTEL_CNL=m +CONFIG_SND_SOC_INTEL_CFL=m +CONFIG_SND_SOC_INTEL_CML_H=m +CONFIG_SND_SOC_INTEL_CML_LP=m +CONFIG_SND_SOC_INTEL_SKYLAKE_FAMILY=m +CONFIG_SND_SOC_INTEL_SKYLAKE_SSP_CLK=m +CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC=y +CONFIG_SND_SOC_INTEL_SKYLAKE_COMMON=m +CONFIG_SND_SOC_ACPI_INTEL_MATCH=m +CONFIG_SND_SOC_INTEL_MACH=y +CONFIG_SND_SOC_INTEL_HASWELL_MACH=m +CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH=m +CONFIG_SND_SOC_INTEL_BROADWELL_MACH=m +CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH=m +CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH=m +CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH=m +CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH=m +CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH=m +CONFIG_SND_SOC_INTEL_CHT_BSW_NAU8824_MACH=m +CONFIG_SND_SOC_INTEL_BYT_CHT_CX2072X_MACH=m +CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH=m +CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH=m +CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH=m +CONFIG_SND_SOC_INTEL_SKL_RT286_MACH=m +CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH=m +CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH=m +CONFIG_SND_SOC_INTEL_DA7219_MAX98357A_GENERIC=m +CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH=m +CONFIG_SND_SOC_INTEL_BXT_RT298_MACH=m +CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH=m +CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH=m +CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH=m +CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH=m +CONFIG_SND_SOC_INTEL_KBL_RT5660_MACH=m +CONFIG_SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH=m +CONFIG_SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH=m +CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH=m +CONFIG_SND_SOC_INTEL_CML_LP_DA7219_MAX98357A_MACH=m +CONFIG_SND_SOC_MTK_BTCVSD=m +CONFIG_SND_SOC_SOF_TOPLEVEL=y +CONFIG_SND_SOC_SOF_PCI=m +CONFIG_SND_SOC_SOF_ACPI=m +CONFIG_SND_SOC_SOF_OPTIONS=m +# CONFIG_SND_SOC_SOF_NOCODEC_SUPPORT is not set +# CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS is not set +# CONFIG_SND_SOC_SOF_DEBUG is not set +CONFIG_SND_SOC_SOF=m +CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE=y +CONFIG_SND_SOC_SOF_INTEL_TOPLEVEL=y +CONFIG_SND_SOC_SOF_INTEL_ACPI=m +CONFIG_SND_SOC_SOF_INTEL_PCI=m +CONFIG_SND_SOC_SOF_INTEL_HIFI_EP_IPC=m +CONFIG_SND_SOC_SOF_INTEL_ATOM_HIFI_EP=m +CONFIG_SND_SOC_SOF_INTEL_COMMON=m +CONFIG_SND_SOC_SOF_BAYTRAIL_SUPPORT=y +CONFIG_SND_SOC_SOF_BAYTRAIL=m +CONFIG_SND_SOC_SOF_BROADWELL_SUPPORT=y +CONFIG_SND_SOC_SOF_BROADWELL=m +CONFIG_SND_SOC_SOF_MERRIFIELD_SUPPORT=y +CONFIG_SND_SOC_SOF_MERRIFIELD=m +CONFIG_SND_SOC_SOF_APOLLOLAKE_SUPPORT=y +CONFIG_SND_SOC_SOF_APOLLOLAKE=m +CONFIG_SND_SOC_SOF_GEMINILAKE_SUPPORT=y +CONFIG_SND_SOC_SOF_GEMINILAKE=m +CONFIG_SND_SOC_SOF_CANNONLAKE_SUPPORT=y +CONFIG_SND_SOC_SOF_CANNONLAKE=m +CONFIG_SND_SOC_SOF_COFFEELAKE_SUPPORT=y +CONFIG_SND_SOC_SOF_COFFEELAKE=m +CONFIG_SND_SOC_SOF_ICELAKE_SUPPORT=y +CONFIG_SND_SOC_SOF_ICELAKE=m +CONFIG_SND_SOC_SOF_COMETLAKE_LP=m +CONFIG_SND_SOC_SOF_COMETLAKE_LP_SUPPORT=y +CONFIG_SND_SOC_SOF_COMETLAKE_H=m +CONFIG_SND_SOC_SOF_COMETLAKE_H_SUPPORT=y +CONFIG_SND_SOC_SOF_TIGERLAKE_SUPPORT=y +CONFIG_SND_SOC_SOF_TIGERLAKE=m +CONFIG_SND_SOC_SOF_ELKHARTLAKE_SUPPORT=y +CONFIG_SND_SOC_SOF_ELKHARTLAKE=m +CONFIG_SND_SOC_SOF_HDA_COMMON=m +CONFIG_SND_SOC_SOF_HDA_LINK=y +CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC=y +# CONFIG_SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1 is not set +CONFIG_SND_SOC_SOF_HDA_LINK_BASELINE=m +CONFIG_SND_SOC_SOF_HDA=m +CONFIG_SND_SOC_SOF_XTENSA=m + +# +# STMicroelectronics STM32 SOC audio support +# +# end of STMicroelectronics STM32 SOC audio support + +CONFIG_SND_SOC_XILINX_I2S=m +# CONFIG_SND_SOC_XILINX_AUDIO_FORMATTER is not set +# CONFIG_SND_SOC_XILINX_SPDIF is not set +# CONFIG_SND_SOC_XTFPGA_I2S is not set +# CONFIG_ZX_TDM is not set +CONFIG_SND_SOC_I2C_AND_SPI=m + +# +# CODEC drivers +# +CONFIG_SND_SOC_AC97_CODEC=m +CONFIG_SND_SOC_ADAU_UTILS=m +# CONFIG_SND_SOC_ADAU1701 is not set +CONFIG_SND_SOC_ADAU17X1=m +CONFIG_SND_SOC_ADAU1761=m +CONFIG_SND_SOC_ADAU1761_I2C=m +CONFIG_SND_SOC_ADAU1761_SPI=m +CONFIG_SND_SOC_ADAU7002=m +# CONFIG_SND_SOC_AK4104 is not set +# CONFIG_SND_SOC_AK4118 is not set +# CONFIG_SND_SOC_AK4458 is not set +# CONFIG_SND_SOC_AK4554 is not set +# CONFIG_SND_SOC_AK4613 is not set +# CONFIG_SND_SOC_AK4642 is not set +# CONFIG_SND_SOC_AK5386 is not set +# CONFIG_SND_SOC_AK5558 is not set +# CONFIG_SND_SOC_ALC5623 is not set +# CONFIG_SND_SOC_BD28623 is not set +# CONFIG_SND_SOC_BT_SCO is not set +# CONFIG_SND_SOC_CROS_EC_CODEC is not set +# CONFIG_SND_SOC_CS35L32 is not set +# CONFIG_SND_SOC_CS35L33 is not set +CONFIG_SND_SOC_CS35L34=m +CONFIG_SND_SOC_CS35L35=m +CONFIG_SND_SOC_CS35L36=m +CONFIG_SND_SOC_CS42L42=m +# CONFIG_SND_SOC_CS42L51_I2C is not set +# CONFIG_SND_SOC_CS42L52 is not set +# CONFIG_SND_SOC_CS42L56 is not set +# CONFIG_SND_SOC_CS42L73 is not set +# CONFIG_SND_SOC_CS4265 is not set +# CONFIG_SND_SOC_CS4270 is not set +# CONFIG_SND_SOC_CS4271_I2C is not set +# CONFIG_SND_SOC_CS4271_SPI is not set +# CONFIG_SND_SOC_CS42XX8_I2C is not set +CONFIG_SND_SOC_CS43130=m +CONFIG_SND_SOC_CS4341=m +# CONFIG_SND_SOC_CS4349 is not set +# CONFIG_SND_SOC_CS53L30 is not set +CONFIG_SND_SOC_CX2072X=m +CONFIG_SND_SOC_DA7213=m +CONFIG_SND_SOC_DA7219=m +CONFIG_SND_SOC_DMIC=m +CONFIG_SND_SOC_HDMI_CODEC=m +# CONFIG_SND_SOC_ES7134 is not set +# CONFIG_SND_SOC_ES7241 is not set +CONFIG_SND_SOC_ES8316=m +# CONFIG_SND_SOC_ES8328_I2C is not set +# CONFIG_SND_SOC_ES8328_SPI is not set +# CONFIG_SND_SOC_GTM601 is not set +CONFIG_SND_SOC_HDAC_HDMI=m +CONFIG_SND_SOC_HDAC_HDA=m +# CONFIG_SND_SOC_INNO_RK3036 is not set +CONFIG_SND_SOC_MAX98088=m +CONFIG_SND_SOC_MAX98090=m +CONFIG_SND_SOC_MAX98357A=m +# CONFIG_SND_SOC_MAX98504 is not set +# CONFIG_SND_SOC_MAX9867 is not set +CONFIG_SND_SOC_MAX98927=m +CONFIG_SND_SOC_MAX98373=m +# CONFIG_SND_SOC_MAX9860 is not set +# CONFIG_SND_SOC_MSM8916_WCD_ANALOG is not set +# CONFIG_SND_SOC_MSM8916_WCD_DIGITAL is not set +# CONFIG_SND_SOC_PCM1681 is not set +# CONFIG_SND_SOC_PCM1789_I2C is not set +# CONFIG_SND_SOC_PCM179X_I2C is not set +# CONFIG_SND_SOC_PCM179X_SPI is not set +# CONFIG_SND_SOC_PCM186X_I2C is not set +# CONFIG_SND_SOC_PCM186X_SPI is not set +# CONFIG_SND_SOC_PCM3060_I2C is not set +# CONFIG_SND_SOC_PCM3060_SPI is not set +# CONFIG_SND_SOC_PCM3168A_I2C is not set +# CONFIG_SND_SOC_PCM3168A_SPI is not set +# CONFIG_SND_SOC_PCM512x_I2C is not set +# CONFIG_SND_SOC_PCM512x_SPI is not set +# CONFIG_SND_SOC_RK3328 is not set +CONFIG_SND_SOC_RL6231=m +CONFIG_SND_SOC_RL6347A=m +CONFIG_SND_SOC_RT286=m +CONFIG_SND_SOC_RT298=m +CONFIG_SND_SOC_RT5514=m +CONFIG_SND_SOC_RT5514_SPI=m +# CONFIG_SND_SOC_RT5616 is not set +# CONFIG_SND_SOC_RT5631 is not set +CONFIG_SND_SOC_RT5640=m +CONFIG_SND_SOC_RT5645=m +CONFIG_SND_SOC_RT5651=m +CONFIG_SND_SOC_RT5660=m +CONFIG_SND_SOC_RT5663=m +CONFIG_SND_SOC_RT5670=m +CONFIG_SND_SOC_RT5677=m +CONFIG_SND_SOC_RT5677_SPI=m +CONFIG_SND_SOC_RT5682=m +# CONFIG_SND_SOC_SGTL5000 is not set +CONFIG_SND_SOC_SIGMADSP=m +CONFIG_SND_SOC_SIGMADSP_REGMAP=m +# CONFIG_SND_SOC_SIMPLE_AMPLIFIER is not set +# CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set +# CONFIG_SND_SOC_SPDIF is not set +# CONFIG_SND_SOC_SSM2305 is not set +# CONFIG_SND_SOC_SSM2602_SPI is not set +# CONFIG_SND_SOC_SSM2602_I2C is not set +CONFIG_SND_SOC_SSM4567=m +# CONFIG_SND_SOC_STA32X is not set +# CONFIG_SND_SOC_STA350 is not set +# CONFIG_SND_SOC_STI_SAS is not set +# CONFIG_SND_SOC_TAS2552 is not set +# CONFIG_SND_SOC_TAS5086 is not set +# CONFIG_SND_SOC_TAS571X is not set +# CONFIG_SND_SOC_TAS5720 is not set +# CONFIG_SND_SOC_TAS6424 is not set +# CONFIG_SND_SOC_TDA7419 is not set +# CONFIG_SND_SOC_TFA9879 is not set +# CONFIG_SND_SOC_TLV320AIC23_I2C is not set +# CONFIG_SND_SOC_TLV320AIC23_SPI is not set +# CONFIG_SND_SOC_TLV320AIC31XX is not set +# CONFIG_SND_SOC_TLV320AIC32X4_I2C is not set +# CONFIG_SND_SOC_TLV320AIC32X4_SPI is not set +# CONFIG_SND_SOC_TLV320AIC3X is not set +CONFIG_SND_SOC_TS3A227E=m +# CONFIG_SND_SOC_TSCS42XX is not set +# CONFIG_SND_SOC_TSCS454 is not set +# CONFIG_SND_SOC_UDA1334 is not set +# CONFIG_SND_SOC_WM8510 is not set +# CONFIG_SND_SOC_WM8523 is not set +CONFIG_SND_SOC_WM8524=m +# CONFIG_SND_SOC_WM8580 is not set +# CONFIG_SND_SOC_WM8711 is not set +# CONFIG_SND_SOC_WM8728 is not set +# CONFIG_SND_SOC_WM8731 is not set +# CONFIG_SND_SOC_WM8737 is not set +# CONFIG_SND_SOC_WM8741 is not set +# CONFIG_SND_SOC_WM8750 is not set +# CONFIG_SND_SOC_WM8753 is not set +# CONFIG_SND_SOC_WM8770 is not set +# CONFIG_SND_SOC_WM8776 is not set +CONFIG_SND_SOC_WM8782=m +# CONFIG_SND_SOC_WM8804_I2C is not set +# CONFIG_SND_SOC_WM8804_SPI is not set +# CONFIG_SND_SOC_WM8903 is not set +# CONFIG_SND_SOC_WM8904 is not set +# CONFIG_SND_SOC_WM8960 is not set +# CONFIG_SND_SOC_WM8962 is not set +# CONFIG_SND_SOC_WM8974 is not set +# CONFIG_SND_SOC_WM8978 is not set +# CONFIG_SND_SOC_WM8985 is not set +CONFIG_SND_SOC_ZX_AUD96P22=m +# CONFIG_SND_SOC_MAX9759 is not set +# CONFIG_SND_SOC_MT6351 is not set +# CONFIG_SND_SOC_MT6358 is not set +CONFIG_SND_SOC_NAU8540=m +CONFIG_SND_SOC_NAU8810=m +# CONFIG_SND_SOC_NAU8822 is not set +CONFIG_SND_SOC_NAU8824=m +CONFIG_SND_SOC_NAU8825=m +# CONFIG_SND_SOC_TPA6130A2 is not set +# end of CODEC drivers + +# CONFIG_SND_SIMPLE_CARD is not set +CONFIG_SND_X86=y +CONFIG_HDMI_LPE_AUDIO=m +CONFIG_SND_SYNTH_EMUX=m +CONFIG_SND_XEN_FRONTEND=m +CONFIG_AC97_BUS=m + +# +# HID support +# +CONFIG_HID=m +CONFIG_HID_BATTERY_STRENGTH=y +CONFIG_HIDRAW=y +CONFIG_UHID=m +CONFIG_HID_GENERIC=m + +# +# Special HID drivers +# +CONFIG_HID_A4TECH=m +# CONFIG_HID_ACCUTOUCH is not set +CONFIG_HID_ACRUX=m +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_APPLE=m +CONFIG_HID_APPLEIR=m +CONFIG_HID_ASUS=m +CONFIG_HID_AUREAL=m +CONFIG_HID_BELKIN=m +CONFIG_HID_BETOP_FF=m +CONFIG_HID_BIGBEN_FF=m +CONFIG_HID_CHERRY=m +CONFIG_HID_CHICONY=m +CONFIG_HID_CORSAIR=m +CONFIG_HID_COUGAR=m +CONFIG_HID_MACALLY=m +CONFIG_HID_PRODIKEYS=m +CONFIG_HID_CMEDIA=m +CONFIG_HID_CP2112=m +CONFIG_HID_CREATIVE_SB0540=m +CONFIG_HID_CYPRESS=m +CONFIG_HID_DRAGONRISE=m +CONFIG_DRAGONRISE_FF=y +CONFIG_HID_EMS_FF=m +CONFIG_HID_ELAN=m +CONFIG_HID_ELECOM=m +CONFIG_HID_ELO=m +CONFIG_HID_EZKEY=m +CONFIG_HID_GEMBIRD=m +CONFIG_HID_GFRM=m +CONFIG_HID_HOLTEK=m +CONFIG_HOLTEK_FF=y +CONFIG_HID_GOOGLE_HAMMER=m +CONFIG_HID_GT683R=m +CONFIG_HID_KEYTOUCH=m +CONFIG_HID_KYE=m +CONFIG_HID_UCLOGIC=m +CONFIG_HID_WALTOP=m +# CONFIG_HID_VIEWSONIC is not set +CONFIG_HID_GYRATION=m +CONFIG_HID_ICADE=m +CONFIG_HID_ITE=m +CONFIG_HID_JABRA=m +CONFIG_HID_TWINHAN=m +CONFIG_HID_KENSINGTON=m +CONFIG_HID_LCPOWER=m +CONFIG_HID_LED=m +CONFIG_HID_LENOVO=m +CONFIG_HID_LOGITECH=m +CONFIG_HID_LOGITECH_DJ=m +CONFIG_HID_LOGITECH_HIDPP=m +CONFIG_LOGITECH_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGIG940_FF=y +CONFIG_LOGIWHEELS_FF=y +CONFIG_HID_MAGICMOUSE=m +# CONFIG_HID_MALTRON is not set +CONFIG_HID_MAYFLASH=m +CONFIG_HID_REDRAGON=m +CONFIG_HID_MICROSOFT=m +CONFIG_HID_MONTEREY=m +CONFIG_HID_MULTITOUCH=m +# CONFIG_HID_NTI is not set +CONFIG_HID_NTRIG=m +CONFIG_HID_ORTEK=m +CONFIG_HID_PANTHERLORD=m +CONFIG_PANTHERLORD_FF=y +CONFIG_HID_PENMOUNT=m +CONFIG_HID_PETALYNX=m +CONFIG_HID_PICOLCD=m +CONFIG_HID_PICOLCD_FB=y +CONFIG_HID_PICOLCD_BACKLIGHT=y +CONFIG_HID_PICOLCD_LCD=y +CONFIG_HID_PICOLCD_LEDS=y +CONFIG_HID_PICOLCD_CIR=y +CONFIG_HID_PLANTRONICS=m +CONFIG_HID_PRIMAX=m +CONFIG_HID_RETRODE=m +CONFIG_HID_ROCCAT=m +CONFIG_HID_SAITEK=m +CONFIG_HID_SAMSUNG=m +CONFIG_HID_SONY=m +CONFIG_SONY_FF=y +CONFIG_HID_SPEEDLINK=m +CONFIG_HID_STEAM=m +CONFIG_HID_STEELSERIES=m +CONFIG_HID_SUNPLUS=m +CONFIG_HID_RMI=m +CONFIG_HID_GREENASIA=m +CONFIG_GREENASIA_FF=y +CONFIG_HID_HYPERV_MOUSE=m +CONFIG_HID_SMARTJOYPLUS=m +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_HID_TIVO=m +CONFIG_HID_TOPSEED=m +CONFIG_HID_THINGM=m +CONFIG_HID_THRUSTMASTER=m +CONFIG_THRUSTMASTER_FF=y +# CONFIG_HID_UDRAW_PS3 is not set +# CONFIG_HID_U2FZERO is not set +CONFIG_HID_WACOM=m +CONFIG_HID_WIIMOTE=m +CONFIG_HID_XINMO=m +CONFIG_HID_ZEROPLUS=m +CONFIG_ZEROPLUS_FF=y +CONFIG_HID_ZYDACRON=m +CONFIG_HID_SENSOR_HUB=m +# CONFIG_HID_SENSOR_CUSTOM_SENSOR is not set +# CONFIG_HID_ALPS is not set +# end of Special HID drivers + +# +# USB HID support +# +CONFIG_USB_HID=m +CONFIG_HID_PID=y +CONFIG_USB_HIDDEV=y + +# +# USB HID Boot Protocol drivers +# +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# end of USB HID Boot Protocol drivers +# end of USB HID support + +# +# I2C HID support +# +CONFIG_I2C_HID=m +# end of I2C HID support + +# +# Intel ISH HID support +# +CONFIG_INTEL_ISH_HID=m +CONFIG_INTEL_ISH_FIRMWARE_DOWNLOADER=m +# end of Intel ISH HID support +# end of HID support + +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=m +# CONFIG_USB_LED_TRIG is not set +CONFIG_USB_ULPI_BUS=m +# CONFIG_USB_CONN_GPIO is not set +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=m +CONFIG_USB_PCI=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +CONFIG_USB_DYNAMIC_MINORS=y +CONFIG_USB_OTG=y +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +CONFIG_USB_OTG_FSM=m +# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set +CONFIG_USB_AUTOSUSPEND_DELAY=2 +CONFIG_USB_MON=m + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_XHCI_HCD=m +# CONFIG_USB_XHCI_DBGCAP is not set +CONFIG_USB_XHCI_PCI=m +CONFIG_USB_XHCI_PLATFORM=m +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EHCI_PCI=m +# CONFIG_USB_EHCI_FSL is not set +CONFIG_USB_EHCI_HCD_PLATFORM=m +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +CONFIG_USB_FOTG210_HCD=m +CONFIG_USB_MAX3421_HCD=m +CONFIG_USB_OHCI_HCD=m +CONFIG_USB_OHCI_HCD_PCI=m +# CONFIG_USB_OHCI_HCD_SSB is not set +CONFIG_USB_OHCI_HCD_PLATFORM=m +CONFIG_USB_UHCI_HCD=m +CONFIG_USB_U132_HCD=m +CONFIG_USB_SL811_HCD=m +# CONFIG_USB_SL811_HCD_ISO is not set +CONFIG_USB_SL811_CS=m +# CONFIG_USB_R8A66597_HCD is not set +CONFIG_USB_HCD_BCMA=m +CONFIG_USB_HCD_SSB=m +# CONFIG_USB_HCD_TEST_MODE is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +CONFIG_USB_WDM=m +CONFIG_USB_TMC=m + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_REALTEK=m +CONFIG_REALTEK_AUTOPM=y +CONFIG_USB_STORAGE_DATAFAB=m +CONFIG_USB_STORAGE_FREECOM=m +CONFIG_USB_STORAGE_ISD200=m +CONFIG_USB_STORAGE_USBAT=m +CONFIG_USB_STORAGE_SDDR09=m +CONFIG_USB_STORAGE_SDDR55=m +CONFIG_USB_STORAGE_JUMPSHOT=m +CONFIG_USB_STORAGE_ALAUDA=m +CONFIG_USB_STORAGE_ONETOUCH=m +CONFIG_USB_STORAGE_KARMA=m +CONFIG_USB_STORAGE_CYPRESS_ATACB=m +CONFIG_USB_STORAGE_ENE_UB6250=m +CONFIG_USB_UAS=m + +# +# USB Imaging devices +# +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m +CONFIG_USBIP_CORE=m +CONFIG_USBIP_VHCI_HCD=m +CONFIG_USBIP_VHCI_HC_PORTS=8 +CONFIG_USBIP_VHCI_NR_HCS=1 +CONFIG_USBIP_HOST=m +# CONFIG_USBIP_DEBUG is not set +CONFIG_USB_CDNS3=m +CONFIG_USB_CDNS3_HOST=y +CONFIG_USB_CDNS3_PCI_WRAP=m +CONFIG_USB_MUSB_HDRC=m +CONFIG_USB_MUSB_HOST=y + +# +# Platform Glue Layer +# + +# +# MUSB DMA mode +# +CONFIG_MUSB_PIO_ONLY=y +CONFIG_USB_DWC3=m +# CONFIG_USB_DWC3_ULPI is not set +CONFIG_USB_DWC3_HOST=y + +# +# Platform Glue Driver Support +# +CONFIG_USB_DWC3_PCI=m +CONFIG_USB_DWC3_HAPS=m +CONFIG_USB_DWC2=m +CONFIG_USB_DWC2_HOST=y + +# +# Gadget/Dual-role mode requires USB Gadget support to be enabled +# +CONFIG_USB_DWC2_PCI=m +# CONFIG_USB_DWC2_DEBUG is not set +# CONFIG_USB_DWC2_TRACK_MISSED_SOFS is not set +# CONFIG_USB_CHIPIDEA is not set +# CONFIG_USB_ISP1760 is not set + +# +# USB port drivers +# +CONFIG_USB_USS720=m +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_SIMPLE=m +CONFIG_USB_SERIAL_AIRCABLE=m +CONFIG_USB_SERIAL_ARK3116=m +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_CH341=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_CP210X=m +CONFIG_USB_SERIAL_CYPRESS_M8=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IR=m +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_F81232=m +CONFIG_USB_SERIAL_F8153X=m +CONFIG_USB_SERIAL_GARMIN=m +CONFIG_USB_SERIAL_IPW=m +CONFIG_USB_SERIAL_IUU=m +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_METRO=m +CONFIG_USB_SERIAL_MOS7720=m +CONFIG_USB_SERIAL_MOS7715_PARPORT=y +CONFIG_USB_SERIAL_MOS7840=m +CONFIG_USB_SERIAL_MXUPORT=m +CONFIG_USB_SERIAL_NAVMAN=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_OTI6858=m +CONFIG_USB_SERIAL_QCAUX=m +CONFIG_USB_SERIAL_QUALCOMM=m +CONFIG_USB_SERIAL_SPCP8X5=m +CONFIG_USB_SERIAL_SAFE=m +CONFIG_USB_SERIAL_SAFE_PADDED=y +CONFIG_USB_SERIAL_SIERRAWIRELESS=m +CONFIG_USB_SERIAL_SYMBOL=m +CONFIG_USB_SERIAL_TI=m +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SERIAL_WWAN=m +CONFIG_USB_SERIAL_OPTION=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_SERIAL_OPTICON=m +CONFIG_USB_SERIAL_XSENS_MT=m +CONFIG_USB_SERIAL_WISHBONE=m +CONFIG_USB_SERIAL_SSU100=m +CONFIG_USB_SERIAL_QT2=m +CONFIG_USB_SERIAL_UPD78F0730=m +CONFIG_USB_SERIAL_DEBUG=m + +# +# USB Miscellaneous drivers +# +CONFIG_USB_EMI62=m +CONFIG_USB_EMI26=m +CONFIG_USB_ADUTUX=m +CONFIG_USB_SEVSEG=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_LCD=m +CONFIG_USB_CYPRESS_CY7C63=m +CONFIG_USB_CYTHERM=m +CONFIG_USB_IDMOUSE=m +CONFIG_USB_FTDI_ELAN=m +CONFIG_USB_APPLEDISPLAY=m +CONFIG_USB_SISUSBVGA=m +CONFIG_USB_SISUSBVGA_CON=y +CONFIG_USB_LD=m +CONFIG_USB_TRANCEVIBRATOR=m +CONFIG_USB_IOWARRIOR=m +CONFIG_USB_TEST=m +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +CONFIG_USB_ISIGHTFW=m +CONFIG_USB_YUREX=m +CONFIG_USB_EZUSB_FX2=m +# CONFIG_USB_HUB_USB251XB is not set +CONFIG_USB_HSIC_USB3503=m +CONFIG_USB_HSIC_USB4604=m +# CONFIG_USB_LINK_LAYER_TEST is not set +# CONFIG_USB_CHAOSKEY is not set +CONFIG_USB_ATM=m +CONFIG_USB_SPEEDTOUCH=m +CONFIG_USB_CXACRU=m +CONFIG_USB_UEAGLEATM=m +CONFIG_USB_XUSBATM=m + +# +# USB Physical Layer drivers +# +CONFIG_USB_PHY=y +CONFIG_NOP_USB_XCEIV=m +# CONFIG_USB_GPIO_VBUS is not set +CONFIG_TAHVO_USB=m +# CONFIG_TAHVO_USB_HOST_BY_DEFAULT is not set +CONFIG_USB_ISP1301=m +# end of USB Physical Layer drivers + +# CONFIG_USB_GADGET is not set +CONFIG_TYPEC=m +CONFIG_TYPEC_TCPM=m +CONFIG_TYPEC_TCPCI=m +CONFIG_TYPEC_RT1711H=m +CONFIG_TYPEC_FUSB302=m +CONFIG_TYPEC_WCOVE=m +CONFIG_TYPEC_UCSI=m +CONFIG_UCSI_CCG=m +CONFIG_UCSI_ACPI=m +# CONFIG_TYPEC_TPS6598X is not set + +# +# USB Type-C Multiplexer/DeMultiplexer Switch support +# +# CONFIG_TYPEC_MUX_PI3USB30532 is not set +# end of USB Type-C Multiplexer/DeMultiplexer Switch support + +# +# USB Type-C Alternate Mode drivers +# +CONFIG_TYPEC_DP_ALTMODE=m +CONFIG_TYPEC_NVIDIA_ALTMODE=m +# end of USB Type-C Alternate Mode drivers + +CONFIG_USB_ROLE_SWITCH=m +CONFIG_USB_ROLES_INTEL_XHCI=m +CONFIG_MMC=m +CONFIG_MMC_BLOCK=m +CONFIG_MMC_BLOCK_MINORS=8 +CONFIG_SDIO_UART=m +CONFIG_MMC_TEST=m + +# +# MMC/SD/SDIO Host Controller Drivers +# +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_SDHCI=m +CONFIG_MMC_SDHCI_IO_ACCESSORS=y +CONFIG_MMC_SDHCI_PCI=m +CONFIG_MMC_RICOH_MMC=y +CONFIG_MMC_SDHCI_ACPI=m +CONFIG_MMC_SDHCI_PLTFM=m +CONFIG_MMC_SDHCI_F_SDH30=m +CONFIG_MMC_WBSD=m +CONFIG_MMC_ALCOR=m +CONFIG_MMC_TIFM_SD=m +CONFIG_MMC_SPI=m +CONFIG_MMC_SDRICOH_CS=m +CONFIG_MMC_CB710=m +CONFIG_MMC_VIA_SDMMC=m +CONFIG_MMC_VUB300=m +CONFIG_MMC_USHC=m +CONFIG_MMC_USDHI6ROL0=m +CONFIG_MMC_REALTEK_PCI=m +CONFIG_MMC_REALTEK_USB=m +CONFIG_MMC_CQHCI=m +CONFIG_MMC_TOSHIBA_PCI=m +CONFIG_MMC_MTK=m +CONFIG_MMC_SDHCI_XENON=m +CONFIG_MEMSTICK=m +# CONFIG_MEMSTICK_DEBUG is not set + +# +# MemoryStick drivers +# +# CONFIG_MEMSTICK_UNSAFE_RESUME is not set +CONFIG_MSPRO_BLOCK=m +CONFIG_MS_BLOCK=m + +# +# MemoryStick Host Controller Drivers +# +CONFIG_MEMSTICK_TIFM_MS=m +CONFIG_MEMSTICK_JMICRON_38X=m +CONFIG_MEMSTICK_R592=m +CONFIG_MEMSTICK_REALTEK_PCI=m +CONFIG_MEMSTICK_REALTEK_USB=m +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +# CONFIG_LEDS_CLASS_FLASH is not set +# CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set + +# +# LED drivers +# +CONFIG_LEDS_88PM860X=m +# CONFIG_LEDS_APU is not set +CONFIG_LEDS_LM3530=m +# CONFIG_LEDS_LM3532 is not set +CONFIG_LEDS_LM3642=m +# CONFIG_LEDS_PCA9532 is not set +CONFIG_LEDS_GPIO=m +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP3952 is not set +CONFIG_LEDS_LP55XX_COMMON=m +CONFIG_LEDS_LP5521=m +CONFIG_LEDS_LP5523=m +CONFIG_LEDS_LP5562=m +CONFIG_LEDS_LP8501=m +CONFIG_LEDS_LP8788=m +CONFIG_LEDS_CLEVO_MAIL=m +# CONFIG_LEDS_PCA955X is not set +CONFIG_LEDS_PCA963X=m +CONFIG_LEDS_WM831X_STATUS=m +CONFIG_LEDS_WM8350=m +CONFIG_LEDS_DA903X=m +CONFIG_LEDS_DA9052=m +CONFIG_LEDS_DAC124S085=m +CONFIG_LEDS_PWM=m +CONFIG_LEDS_REGULATOR=m +# CONFIG_LEDS_BD2802 is not set +CONFIG_LEDS_INTEL_SS4200=m +CONFIG_LEDS_ADP5520=m +CONFIG_LEDS_MC13783=m +CONFIG_LEDS_TCA6507=m +CONFIG_LEDS_TLC591XX=m +CONFIG_LEDS_MAX8997=m +CONFIG_LEDS_LM355x=m +CONFIG_LEDS_MENF21BMC=m + +# +# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM) +# +CONFIG_LEDS_BLINKM=m +CONFIG_LEDS_MLXCPLD=m +CONFIG_LEDS_MLXREG=m +CONFIG_LEDS_USER=m +# CONFIG_LEDS_NIC78BX is not set +# CONFIG_LEDS_TI_LMU_COMMON is not set + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=m +CONFIG_LEDS_TRIGGER_ONESHOT=m +CONFIG_LEDS_TRIGGER_DISK=y +# CONFIG_LEDS_TRIGGER_MTD is not set +CONFIG_LEDS_TRIGGER_HEARTBEAT=m +CONFIG_LEDS_TRIGGER_BACKLIGHT=m +CONFIG_LEDS_TRIGGER_CPU=y +# CONFIG_LEDS_TRIGGER_ACTIVITY is not set +CONFIG_LEDS_TRIGGER_GPIO=m +CONFIG_LEDS_TRIGGER_DEFAULT_ON=m + +# +# iptables trigger is under Netfilter config (LED target) +# +CONFIG_LEDS_TRIGGER_TRANSIENT=m +CONFIG_LEDS_TRIGGER_CAMERA=m +# CONFIG_LEDS_TRIGGER_PANIC is not set +CONFIG_LEDS_TRIGGER_NETDEV=m +CONFIG_LEDS_TRIGGER_PATTERN=m +CONFIG_LEDS_TRIGGER_AUDIO=m +CONFIG_ACCESSIBILITY=y +CONFIG_A11Y_BRAILLE_CONSOLE=y +CONFIG_INFINIBAND=m +CONFIG_INFINIBAND_USER_MAD=m +CONFIG_INFINIBAND_USER_ACCESS=m +# CONFIG_INFINIBAND_EXP_LEGACY_VERBS_NEW_UAPI is not set +CONFIG_INFINIBAND_USER_MEM=y +CONFIG_INFINIBAND_ON_DEMAND_PAGING=y +CONFIG_INFINIBAND_ADDR_TRANS=y +CONFIG_INFINIBAND_ADDR_TRANS_CONFIGFS=y +CONFIG_INFINIBAND_MTHCA=m +# CONFIG_INFINIBAND_MTHCA_DEBUG is not set +CONFIG_INFINIBAND_QIB=m +CONFIG_INFINIBAND_QIB_DCA=y +CONFIG_INFINIBAND_CXGB3=m +CONFIG_INFINIBAND_CXGB4=m +CONFIG_INFINIBAND_EFA=m +CONFIG_INFINIBAND_I40IW=m +CONFIG_MLX4_INFINIBAND=m +CONFIG_MLX5_INFINIBAND=m +CONFIG_INFINIBAND_OCRDMA=m +CONFIG_INFINIBAND_VMWARE_PVRDMA=m +CONFIG_INFINIBAND_USNIC=m +CONFIG_INFINIBAND_BNXT_RE=m +CONFIG_INFINIBAND_HFI1=m +# CONFIG_HFI1_DEBUG_SDMA_ORDER is not set +# CONFIG_SDMA_VERBOSITY is not set +CONFIG_INFINIBAND_QEDR=m +CONFIG_INFINIBAND_RDMAVT=m +CONFIG_RDMA_RXE=m +CONFIG_RDMA_SIW=m +CONFIG_INFINIBAND_IPOIB=m +# CONFIG_INFINIBAND_IPOIB_CM is not set +# CONFIG_INFINIBAND_IPOIB_DEBUG is not set +CONFIG_INFINIBAND_SRP=m +CONFIG_INFINIBAND_SRPT=m +CONFIG_INFINIBAND_ISER=m +CONFIG_INFINIBAND_ISERT=m +CONFIG_INFINIBAND_OPA_VNIC=m +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +CONFIG_EDAC=y +CONFIG_EDAC_LEGACY_SYSFS=y +# CONFIG_EDAC_DEBUG is not set +CONFIG_EDAC_DECODE_MCE=y +# CONFIG_EDAC_GHES is not set +CONFIG_EDAC_AMD64=m +# CONFIG_EDAC_AMD64_ERROR_INJECTION is not set +CONFIG_EDAC_E752X=m +CONFIG_EDAC_I82975X=m +CONFIG_EDAC_I3000=m +CONFIG_EDAC_I3200=m +CONFIG_EDAC_IE31200=m +CONFIG_EDAC_X38=m +CONFIG_EDAC_I5400=m +CONFIG_EDAC_I7CORE=m +CONFIG_EDAC_I5000=m +CONFIG_EDAC_I5100=m +CONFIG_EDAC_I7300=m +CONFIG_EDAC_SBRIDGE=m +CONFIG_EDAC_SKX=m +CONFIG_EDAC_I10NM=m +CONFIG_EDAC_PND2=m +CONFIG_RTC_LIB=y +CONFIG_RTC_MC146818_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_SYSTOHC_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set +CONFIG_RTC_NVMEM=y + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +# CONFIG_RTC_INTF_PROC is not set +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_DEV_UIE_EMUL=y +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +CONFIG_RTC_DRV_88PM860X=m +CONFIG_RTC_DRV_88PM80X=m +# CONFIG_RTC_DRV_ABB5ZES3 is not set +# CONFIG_RTC_DRV_ABEOZ9 is not set +# CONFIG_RTC_DRV_ABX80X is not set +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +CONFIG_RTC_DRV_LP8788=m +# CONFIG_RTC_DRV_MAX6900 is not set +CONFIG_RTC_DRV_MAX8907=m +CONFIG_RTC_DRV_MAX8925=m +CONFIG_RTC_DRV_MAX8998=m +CONFIG_RTC_DRV_MAX8997=m +# CONFIG_RTC_DRV_RS5C372 is not set +CONFIG_RTC_DRV_ISL1208=m +CONFIG_RTC_DRV_ISL12022=m +# CONFIG_RTC_DRV_X1205 is not set +CONFIG_RTC_DRV_PCF8523=m +CONFIG_RTC_DRV_PCF85063=m +# CONFIG_RTC_DRV_PCF85363 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +CONFIG_RTC_DRV_BQ32K=m +CONFIG_RTC_DRV_PALMAS=m +CONFIG_RTC_DRV_TPS6586X=m +CONFIG_RTC_DRV_TPS65910=m +CONFIG_RTC_DRV_TPS80031=m +CONFIG_RTC_DRV_RC5T583=m +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +CONFIG_RTC_DRV_RX8010=m +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3028 is not set +CONFIG_RTC_DRV_RV8803=m +CONFIG_RTC_DRV_S5M=m +# CONFIG_RTC_DRV_SD3078 is not set + +# +# SPI RTC drivers +# +CONFIG_RTC_DRV_M41T93=m +CONFIG_RTC_DRV_M41T94=m +CONFIG_RTC_DRV_DS1302=m +CONFIG_RTC_DRV_DS1305=m +CONFIG_RTC_DRV_DS1343=m +CONFIG_RTC_DRV_DS1347=m +CONFIG_RTC_DRV_DS1390=m +CONFIG_RTC_DRV_MAX6916=m +CONFIG_RTC_DRV_R9701=m +CONFIG_RTC_DRV_RX4581=m +CONFIG_RTC_DRV_RX6110=m +CONFIG_RTC_DRV_RS5C348=m +CONFIG_RTC_DRV_MAX6902=m +CONFIG_RTC_DRV_PCF2123=m +CONFIG_RTC_DRV_MCP795=m +CONFIG_RTC_I2C_AND_SPI=y + +# +# SPI and I2C RTC drivers +# +# CONFIG_RTC_DRV_DS3232 is not set +CONFIG_RTC_DRV_PCF2127=m +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# Platform RTC drivers +# +CONFIG_RTC_DRV_CMOS=y +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1685_FAMILY is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_DS2404 is not set +CONFIG_RTC_DRV_DA9052=m +CONFIG_RTC_DRV_DA9055=m +CONFIG_RTC_DRV_DA9063=m +# 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_WM831X=m +CONFIG_RTC_DRV_WM8350=m +CONFIG_RTC_DRV_CROS_EC=m + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_FTRTC010 is not set +CONFIG_RTC_DRV_PCAP=m +CONFIG_RTC_DRV_MC13XXX=m + +# +# HID Sensor RTC drivers +# +CONFIG_RTC_DRV_HID_SENSOR_TIME=m +CONFIG_RTC_DRV_WILCO_EC=m +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +CONFIG_DMA_ENGINE=y +CONFIG_DMA_VIRTUAL_CHANNELS=m +CONFIG_DMA_ACPI=y +CONFIG_ALTERA_MSGDMA=m +CONFIG_INTEL_IDMA64=m +CONFIG_INTEL_IOATDMA=m +CONFIG_INTEL_MIC_X100_DMA=m +CONFIG_QCOM_HIDMA_MGMT=m +CONFIG_QCOM_HIDMA=m +CONFIG_DW_DMAC_CORE=m +CONFIG_DW_DMAC=m +CONFIG_DW_DMAC_PCI=m +CONFIG_DW_EDMA=m +CONFIG_DW_EDMA_PCIE=m +CONFIG_HSU_DMA=m + +# +# DMA Clients +# +# CONFIG_ASYNC_TX_DMA is not set +CONFIG_DMATEST=m +CONFIG_DMA_ENGINE_RAID=y + +# +# DMABUF options +# +CONFIG_SYNC_FILE=y +# CONFIG_SW_SYNC is not set +CONFIG_UDMABUF=y +# CONFIG_DMABUF_SELFTESTS is not set +# end of DMABUF options + +CONFIG_DCA=m +CONFIG_AUXDISPLAY=y +# CONFIG_HD44780 is not set +CONFIG_KS0108=m +CONFIG_KS0108_PORT=0x378 +CONFIG_KS0108_DELAY=2 +CONFIG_CFAG12864B=m +CONFIG_CFAG12864B_RATE=20 +# CONFIG_IMG_ASCII_LCD is not set +CONFIG_PARPORT_PANEL=m +CONFIG_PANEL_PARPORT=0 +CONFIG_PANEL_PROFILE=5 +# CONFIG_PANEL_CHANGE_MESSAGE is not set +# CONFIG_CHARLCD_BL_OFF is not set +# CONFIG_CHARLCD_BL_ON is not set +CONFIG_CHARLCD_BL_FLASH=y +CONFIG_PANEL=m +CONFIG_CHARLCD=m +CONFIG_UIO=m +CONFIG_UIO_CIF=m +# CONFIG_UIO_PDRV_GENIRQ is not set +CONFIG_UIO_DMEM_GENIRQ=m +CONFIG_UIO_AEC=m +CONFIG_UIO_SERCOS3=m +CONFIG_UIO_PCI_GENERIC=m +CONFIG_UIO_NETX=m +CONFIG_UIO_PRUSS=m +CONFIG_UIO_MF624=m +CONFIG_UIO_HV_GENERIC=m +CONFIG_VFIO_IOMMU_TYPE1=m +CONFIG_VFIO_VIRQFD=m +CONFIG_VFIO=m +# CONFIG_VFIO_NOIOMMU is not set +CONFIG_VFIO_PCI=m +CONFIG_VFIO_PCI_VGA=y +CONFIG_VFIO_PCI_MMAP=y +CONFIG_VFIO_PCI_INTX=y +CONFIG_VFIO_PCI_IGD=y +CONFIG_VFIO_MDEV=m +CONFIG_VFIO_MDEV_DEVICE=m +CONFIG_IRQ_BYPASS_MANAGER=m +CONFIG_VIRT_DRIVERS=y +CONFIG_VBOXGUEST=m +CONFIG_VIRTIO=m +CONFIG_VIRTIO_MENU=y +CONFIG_VIRTIO_PCI=m +CONFIG_VIRTIO_PCI_LEGACY=y +CONFIG_VIRTIO_PMEM=m +CONFIG_VIRTIO_BALLOON=m +CONFIG_VIRTIO_INPUT=m +CONFIG_VIRTIO_MMIO=m +# CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES is not set + +# +# Microsoft Hyper-V guest support +# +CONFIG_HYPERV=m +CONFIG_HYPERV_TIMER=y +CONFIG_HYPERV_UTILS=m +CONFIG_HYPERV_BALLOON=m +# end of Microsoft Hyper-V guest support + +# +# Xen driver support +# +CONFIG_XEN_BALLOON=y +# CONFIG_XEN_BALLOON_MEMORY_HOTPLUG is not set +CONFIG_XEN_SCRUB_PAGES_DEFAULT=y +CONFIG_XEN_DEV_EVTCHN=m +CONFIG_XEN_BACKEND=y +CONFIG_XENFS=m +CONFIG_XEN_COMPAT_XENFS=y +CONFIG_XEN_SYS_HYPERVISOR=y +CONFIG_XEN_XENBUS_FRONTEND=y +CONFIG_XEN_GNTDEV=m +CONFIG_XEN_GRANT_DEV_ALLOC=m +# CONFIG_XEN_GRANT_DMA_ALLOC is not set +CONFIG_SWIOTLB_XEN=y +CONFIG_XEN_PCIDEV_BACKEND=m +# CONFIG_XEN_PVCALLS_FRONTEND is not set +# CONFIG_XEN_PVCALLS_BACKEND is not set +CONFIG_XEN_SCSI_BACKEND=m +CONFIG_XEN_PRIVCMD=m +CONFIG_XEN_ACPI_PROCESSOR=m +# CONFIG_XEN_MCE_LOG is not set +CONFIG_XEN_HAVE_PVMMU=y +CONFIG_XEN_EFI=y +CONFIG_XEN_AUTO_XLATE=y +CONFIG_XEN_ACPI=y +CONFIG_XEN_SYMS=y +CONFIG_XEN_HAVE_VPMU=y +CONFIG_XEN_FRONT_PGDIR_SHBUF=m +# end of Xen driver support + +# CONFIG_GREYBUS is not set +CONFIG_STAGING=y +CONFIG_PRISM2_USB=m +CONFIG_COMEDI=m +# CONFIG_COMEDI_DEBUG is not set +CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB=2048 +CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB=20480 +CONFIG_COMEDI_MISC_DRIVERS=y +CONFIG_COMEDI_BOND=m +CONFIG_COMEDI_TEST=m +CONFIG_COMEDI_PARPORT=m +CONFIG_COMEDI_ISA_DRIVERS=y +CONFIG_COMEDI_PCL711=m +CONFIG_COMEDI_PCL724=m +CONFIG_COMEDI_PCL726=m +CONFIG_COMEDI_PCL730=m +CONFIG_COMEDI_PCL812=m +CONFIG_COMEDI_PCL816=m +CONFIG_COMEDI_PCL818=m +CONFIG_COMEDI_PCM3724=m +CONFIG_COMEDI_AMPLC_DIO200_ISA=m +CONFIG_COMEDI_AMPLC_PC236_ISA=m +CONFIG_COMEDI_AMPLC_PC263_ISA=m +CONFIG_COMEDI_RTI800=m +CONFIG_COMEDI_RTI802=m +# CONFIG_COMEDI_DAC02 is not set +CONFIG_COMEDI_DAS16M1=m +CONFIG_COMEDI_DAS08_ISA=m +CONFIG_COMEDI_DAS16=m +CONFIG_COMEDI_DAS800=m +CONFIG_COMEDI_DAS1800=m +CONFIG_COMEDI_DAS6402=m +CONFIG_COMEDI_DT2801=m +CONFIG_COMEDI_DT2811=m +CONFIG_COMEDI_DT2814=m +CONFIG_COMEDI_DT2815=m +CONFIG_COMEDI_DT2817=m +CONFIG_COMEDI_DT282X=m +CONFIG_COMEDI_DMM32AT=m +CONFIG_COMEDI_FL512=m +CONFIG_COMEDI_AIO_AIO12_8=m +CONFIG_COMEDI_AIO_IIRO_16=m +CONFIG_COMEDI_II_PCI20KC=m +CONFIG_COMEDI_C6XDIGIO=m +CONFIG_COMEDI_MPC624=m +CONFIG_COMEDI_ADQ12B=m +CONFIG_COMEDI_NI_AT_A2150=m +CONFIG_COMEDI_NI_AT_AO=m +CONFIG_COMEDI_NI_ATMIO=m +CONFIG_COMEDI_NI_ATMIO16D=m +CONFIG_COMEDI_NI_LABPC_ISA=m +CONFIG_COMEDI_PCMAD=m +CONFIG_COMEDI_PCMDA12=m +CONFIG_COMEDI_PCMMIO=m +CONFIG_COMEDI_PCMUIO=m +CONFIG_COMEDI_MULTIQ3=m +CONFIG_COMEDI_S526=m +CONFIG_COMEDI_PCI_DRIVERS=m +CONFIG_COMEDI_8255_PCI=m +CONFIG_COMEDI_ADDI_WATCHDOG=m +CONFIG_COMEDI_ADDI_APCI_1032=m +CONFIG_COMEDI_ADDI_APCI_1500=m +CONFIG_COMEDI_ADDI_APCI_1516=m +CONFIG_COMEDI_ADDI_APCI_1564=m +CONFIG_COMEDI_ADDI_APCI_16XX=m +CONFIG_COMEDI_ADDI_APCI_2032=m +CONFIG_COMEDI_ADDI_APCI_2200=m +CONFIG_COMEDI_ADDI_APCI_3120=m +CONFIG_COMEDI_ADDI_APCI_3501=m +CONFIG_COMEDI_ADDI_APCI_3XXX=m +CONFIG_COMEDI_ADL_PCI6208=m +CONFIG_COMEDI_ADL_PCI7X3X=m +CONFIG_COMEDI_ADL_PCI8164=m +CONFIG_COMEDI_ADL_PCI9111=m +CONFIG_COMEDI_ADL_PCI9118=m +CONFIG_COMEDI_ADV_PCI1710=m +CONFIG_COMEDI_ADV_PCI1720=m +CONFIG_COMEDI_ADV_PCI1723=m +CONFIG_COMEDI_ADV_PCI1724=m +CONFIG_COMEDI_ADV_PCI1760=m +CONFIG_COMEDI_ADV_PCI_DIO=m +CONFIG_COMEDI_AMPLC_DIO200_PCI=m +CONFIG_COMEDI_AMPLC_PC236_PCI=m +CONFIG_COMEDI_AMPLC_PC263_PCI=m +CONFIG_COMEDI_AMPLC_PCI224=m +CONFIG_COMEDI_AMPLC_PCI230=m +CONFIG_COMEDI_CONTEC_PCI_DIO=m +CONFIG_COMEDI_DAS08_PCI=m +CONFIG_COMEDI_DT3000=m +CONFIG_COMEDI_DYNA_PCI10XX=m +CONFIG_COMEDI_GSC_HPDI=m +CONFIG_COMEDI_MF6X4=m +CONFIG_COMEDI_ICP_MULTI=m +CONFIG_COMEDI_DAQBOARD2000=m +CONFIG_COMEDI_JR3_PCI=m +CONFIG_COMEDI_KE_COUNTER=m +CONFIG_COMEDI_CB_PCIDAS64=m +CONFIG_COMEDI_CB_PCIDAS=m +CONFIG_COMEDI_CB_PCIDDA=m +CONFIG_COMEDI_CB_PCIMDAS=m +CONFIG_COMEDI_CB_PCIMDDA=m +CONFIG_COMEDI_ME4000=m +CONFIG_COMEDI_ME_DAQ=m +CONFIG_COMEDI_NI_6527=m +CONFIG_COMEDI_NI_65XX=m +CONFIG_COMEDI_NI_660X=m +CONFIG_COMEDI_NI_670X=m +CONFIG_COMEDI_NI_LABPC_PCI=m +CONFIG_COMEDI_NI_PCIDIO=m +CONFIG_COMEDI_NI_PCIMIO=m +CONFIG_COMEDI_RTD520=m +CONFIG_COMEDI_S626=m +CONFIG_COMEDI_MITE=m +CONFIG_COMEDI_NI_TIOCMD=m +CONFIG_COMEDI_PCMCIA_DRIVERS=m +CONFIG_COMEDI_CB_DAS16_CS=m +CONFIG_COMEDI_DAS08_CS=m +CONFIG_COMEDI_NI_DAQ_700_CS=m +CONFIG_COMEDI_NI_DAQ_DIO24_CS=m +CONFIG_COMEDI_NI_LABPC_CS=m +CONFIG_COMEDI_NI_MIO_CS=m +CONFIG_COMEDI_QUATECH_DAQP_CS=m +CONFIG_COMEDI_USB_DRIVERS=m +CONFIG_COMEDI_DT9812=m +CONFIG_COMEDI_NI_USB6501=m +CONFIG_COMEDI_USBDUX=m +CONFIG_COMEDI_USBDUXFAST=m +CONFIG_COMEDI_USBDUXSIGMA=m +CONFIG_COMEDI_VMK80XX=m +CONFIG_COMEDI_8254=m +CONFIG_COMEDI_8255=m +CONFIG_COMEDI_8255_SA=m +CONFIG_COMEDI_KCOMEDILIB=m +CONFIG_COMEDI_AMPLC_DIO200=m +CONFIG_COMEDI_AMPLC_PC236=m +CONFIG_COMEDI_DAS08=m +CONFIG_COMEDI_ISADMA=m +CONFIG_COMEDI_NI_LABPC=m +CONFIG_COMEDI_NI_LABPC_ISADMA=m +CONFIG_COMEDI_NI_TIO=m +CONFIG_COMEDI_NI_ROUTING=m +CONFIG_RTL8192U=m +CONFIG_RTLLIB=m +CONFIG_RTLLIB_CRYPTO_CCMP=m +CONFIG_RTLLIB_CRYPTO_TKIP=m +CONFIG_RTLLIB_CRYPTO_WEP=m +CONFIG_RTL8192E=m +CONFIG_RTL8723BS=m +CONFIG_R8712U=m +CONFIG_R8188EU=m +CONFIG_88EU_AP_MODE=y +CONFIG_RTS5208=m +CONFIG_VT6655=m +CONFIG_VT6656=m + +# +# IIO staging drivers +# + +# +# Accelerometers +# +CONFIG_ADIS16203=m +CONFIG_ADIS16240=m +# end of Accelerometers + +# +# Analog to digital converters +# +CONFIG_AD7816=m +CONFIG_AD7192=m +CONFIG_AD7280=m +# end of Analog to digital converters + +# +# Analog digital bi-direction converters +# +CONFIG_ADT7316=m +CONFIG_ADT7316_SPI=m +CONFIG_ADT7316_I2C=m +# end of Analog digital bi-direction converters + +# +# Capacitance to digital converters +# +CONFIG_AD7150=m +CONFIG_AD7746=m +# end of Capacitance to digital converters + +# +# Direct Digital Synthesis +# +CONFIG_AD9832=m +CONFIG_AD9834=m +# end of Direct Digital Synthesis + +# +# Network Analyzer, Impedance Converters +# +CONFIG_AD5933=m +# end of Network Analyzer, Impedance Converters + +# +# Active energy metering IC +# +CONFIG_ADE7854=m +CONFIG_ADE7854_I2C=m +CONFIG_ADE7854_SPI=m +# end of Active energy metering IC + +# +# Resolver to digital converters +# +CONFIG_AD2S1210=m +# end of Resolver to digital converters +# end of IIO staging drivers + +# CONFIG_FB_SM750 is not set + +# +# Speakup console speech +# +CONFIG_SPEAKUP=m +CONFIG_SPEAKUP_SYNTH_ACNTSA=m +CONFIG_SPEAKUP_SYNTH_APOLLO=m +CONFIG_SPEAKUP_SYNTH_AUDPTR=m +CONFIG_SPEAKUP_SYNTH_BNS=m +CONFIG_SPEAKUP_SYNTH_DECTLK=m +CONFIG_SPEAKUP_SYNTH_DECEXT=m +CONFIG_SPEAKUP_SYNTH_LTLK=m +CONFIG_SPEAKUP_SYNTH_SOFT=m +CONFIG_SPEAKUP_SYNTH_SPKOUT=m +CONFIG_SPEAKUP_SYNTH_TXPRT=m +CONFIG_SPEAKUP_SYNTH_DUMMY=m +# end of Speakup console speech + +CONFIG_STAGING_MEDIA=y + +# +# soc_camera sensor drivers +# + +# +# Android +# +# end of Android + +CONFIG_LTE_GDM724X=m +CONFIG_FIREWIRE_SERIAL=m +CONFIG_FWTTY_MAX_TOTAL_PORTS=64 +CONFIG_FWTTY_MAX_CARD_PORTS=32 +# CONFIG_GS_FPGABOOT is not set +CONFIG_UNISYSSPAR=y +CONFIG_UNISYS_VISORNIC=m +CONFIG_UNISYS_VISORINPUT=m +CONFIG_UNISYS_VISORHBA=m +CONFIG_WILC1000=m +CONFIG_WILC1000_SDIO=m +# CONFIG_WILC1000_SPI is not set +# CONFIG_WILC1000_HW_OOB_INTR is not set +CONFIG_MOST=m +CONFIG_MOST_CDEV=m +CONFIG_MOST_NET=m +CONFIG_MOST_SOUND=m +CONFIG_MOST_VIDEO=m +CONFIG_MOST_I2C=m +CONFIG_MOST_USB=m +CONFIG_KS7010=m +# CONFIG_PI433 is not set + +# +# Gasket devices +# +# CONFIG_STAGING_GASKET_FRAMEWORK is not set +# end of Gasket devices + +CONFIG_FIELDBUS_DEV=m +# CONFIG_KPC2000 is not set + +# +# ISDN CAPI drivers +# +CONFIG_CAPI_AVM=y +CONFIG_ISDN_DRV_AVMB1_B1PCI=m +# CONFIG_ISDN_DRV_AVMB1_B1PCIV4 is not set +CONFIG_ISDN_DRV_AVMB1_B1PCMCIA=m +CONFIG_ISDN_DRV_AVMB1_AVM_CS=m +CONFIG_ISDN_DRV_AVMB1_T1PCI=m +CONFIG_ISDN_DRV_AVMB1_C4=m +CONFIG_ISDN_DRV_GIGASET=m +CONFIG_GIGASET_CAPI=y +CONFIG_GIGASET_BASE=m +CONFIG_GIGASET_M105=m +CONFIG_GIGASET_M101=m +# CONFIG_GIGASET_DEBUG is not set +CONFIG_HYSDN=m +CONFIG_HYSDN_CAPI=y +# end of ISDN CAPI drivers + +CONFIG_USB_WUSB=m +CONFIG_USB_WUSB_CBAF=m +# CONFIG_USB_WUSB_CBAF_DEBUG is not set +CONFIG_USB_WHCI_HCD=m +CONFIG_USB_HWA_HCD=m +CONFIG_UWB=m +CONFIG_UWB_HWA=m +CONFIG_UWB_WHCI=m +CONFIG_UWB_I1480U=m +CONFIG_EXFAT_FS=m +CONFIG_EXFAT_DONT_MOUNT_VFAT=y +CONFIG_EXFAT_DISCARD=y +# CONFIG_EXFAT_DELAYED_SYNC is not set +# CONFIG_EXFAT_KERNEL_DEBUG is not set +# CONFIG_EXFAT_DEBUG_MSG is not set +CONFIG_EXFAT_DEFAULT_CODEPAGE=437 +CONFIG_EXFAT_DEFAULT_IOCHARSET="utf8" +CONFIG_QLGE=m +CONFIG_VBOXSF_FS=m +CONFIG_X86_PLATFORM_DEVICES=y +CONFIG_ACER_WMI=m +CONFIG_ACER_WIRELESS=m +CONFIG_ACERHDF=m +CONFIG_ALIENWARE_WMI=m +CONFIG_ASUS_LAPTOP=m +CONFIG_DCDBAS=m +CONFIG_DELL_SMBIOS=m +CONFIG_DELL_SMBIOS_WMI=y +CONFIG_DELL_SMBIOS_SMM=y +CONFIG_DELL_LAPTOP=m +CONFIG_DELL_WMI=m +CONFIG_DELL_WMI_DESCRIPTOR=m +CONFIG_DELL_WMI_AIO=m +CONFIG_DELL_WMI_LED=m +CONFIG_DELL_SMO8800=m +CONFIG_DELL_RBTN=m +# CONFIG_DELL_RBU is not set +CONFIG_FUJITSU_LAPTOP=m +CONFIG_FUJITSU_TABLET=m +CONFIG_AMILO_RFKILL=m +CONFIG_GPD_POCKET_FAN=m +CONFIG_HP_ACCEL=m +CONFIG_HP_WIRELESS=m +CONFIG_HP_WMI=m +CONFIG_LG_LAPTOP=m +CONFIG_MSI_LAPTOP=m +CONFIG_PANASONIC_LAPTOP=m +CONFIG_COMPAL_LAPTOP=m +CONFIG_SONY_LAPTOP=m +CONFIG_SONYPI_COMPAT=y +CONFIG_IDEAPAD_LAPTOP=m +CONFIG_SURFACE3_WMI=m +CONFIG_THINKPAD_ACPI=m +CONFIG_THINKPAD_ACPI_ALSA_SUPPORT=y +# CONFIG_THINKPAD_ACPI_DEBUGFACILITIES is not set +# CONFIG_THINKPAD_ACPI_DEBUG is not set +# CONFIG_THINKPAD_ACPI_UNSAFE_LEDS is not set +CONFIG_THINKPAD_ACPI_VIDEO=y +CONFIG_THINKPAD_ACPI_HOTKEY_POLL=y +CONFIG_SENSORS_HDAPS=m +CONFIG_INTEL_MENLOW=m +CONFIG_EEEPC_LAPTOP=m +CONFIG_ASUS_WMI=m +CONFIG_ASUS_NB_WMI=m +CONFIG_EEEPC_WMI=m +CONFIG_ASUS_WIRELESS=m +CONFIG_ACPI_WMI=m +CONFIG_WMI_BMOF=m +CONFIG_INTEL_WMI_THUNDERBOLT=m +CONFIG_XIAOMI_WMI=m +CONFIG_MSI_WMI=m +CONFIG_PEAQ_WMI=m +CONFIG_TOPSTAR_LAPTOP=m +CONFIG_ACPI_TOSHIBA=m +CONFIG_TOSHIBA_BT_RFKILL=m +CONFIG_TOSHIBA_HAPS=m +CONFIG_TOSHIBA_WMI=m +CONFIG_ACPI_CMPC=m +CONFIG_INTEL_INT0002_VGPIO=m +CONFIG_INTEL_HID_EVENT=m +CONFIG_INTEL_VBTN=m +CONFIG_INTEL_IPS=m +CONFIG_INTEL_PMC_CORE=y +CONFIG_IBM_RTL=m +CONFIG_SAMSUNG_LAPTOP=m +CONFIG_MXM_WMI=m +CONFIG_INTEL_OAKTRAIL=m +CONFIG_SAMSUNG_Q10=m +CONFIG_APPLE_GMUX=m +CONFIG_INTEL_RST=m +CONFIG_INTEL_SMARTCONNECT=m +CONFIG_INTEL_PMC_IPC=m +CONFIG_INTEL_BXTWC_PMIC_TMU=m +CONFIG_SURFACE_PRO3_BUTTON=m +CONFIG_SURFACE_3_BUTTON=m +CONFIG_INTEL_PUNIT_IPC=m +CONFIG_INTEL_TELEMETRY=m +CONFIG_MLX_PLATFORM=m +CONFIG_INTEL_TURBO_MAX_3=y +CONFIG_TOUCHSCREEN_DMI=y +CONFIG_INTEL_CHTDC_TI_PWRBTN=m +CONFIG_I2C_MULTI_INSTANTIATE=m +CONFIG_INTEL_ATOMISP2_PM=m +CONFIG_HUAWEI_WMI=m +# CONFIG_PCENGINES_APU2 is not set + +# +# Intel Speed Select Technology interface support +# +CONFIG_INTEL_SPEED_SELECT_INTERFACE=m +# end of Intel Speed Select Technology interface support + +CONFIG_PMC_ATOM=y +CONFIG_MFD_CROS_EC=m +CONFIG_CHROME_PLATFORMS=y +CONFIG_CHROMEOS_LAPTOP=m +CONFIG_CHROMEOS_PSTORE=m +CONFIG_CHROMEOS_TBMC=m +CONFIG_CROS_EC=m +CONFIG_CROS_EC_I2C=m +CONFIG_CROS_EC_ISHTP=m +CONFIG_CROS_EC_SPI=m +CONFIG_CROS_EC_LPC=m +CONFIG_CROS_EC_PROTO=y +CONFIG_CROS_KBD_LED_BACKLIGHT=m +CONFIG_CROS_EC_CHARDEV=m +CONFIG_CROS_EC_LIGHTBAR=m +CONFIG_CROS_EC_DEBUGFS=m +CONFIG_CROS_EC_SYSFS=m +CONFIG_CROS_USBPD_LOGGER=m +CONFIG_WILCO_EC=m +CONFIG_WILCO_EC_DEBUGFS=m +CONFIG_WILCO_EC_EVENTS=m +CONFIG_WILCO_EC_TELEMETRY=m +CONFIG_MELLANOX_PLATFORM=y +CONFIG_MLXREG_HOTPLUG=m +CONFIG_MLXREG_IO=m +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_COMMON_CLK=y + +# +# Common Clock Framework +# +CONFIG_COMMON_CLK_WM831X=m +# CONFIG_COMMON_CLK_MAX9485 is not set +# CONFIG_COMMON_CLK_SI5341 is not set +CONFIG_COMMON_CLK_SI5351=m +# CONFIG_COMMON_CLK_SI544 is not set +# CONFIG_COMMON_CLK_CDCE706 is not set +CONFIG_COMMON_CLK_CS2000_CP=m +CONFIG_COMMON_CLK_S2MPS11=m +CONFIG_CLK_TWL6040=m +CONFIG_COMMON_CLK_PALMAS=m +CONFIG_COMMON_CLK_PWM=m +# end of Common Clock Framework + +# CONFIG_HWSPINLOCK is not set + +# +# Clock Source drivers +# +CONFIG_CLKEVT_I8253=y +CONFIG_I8253_LOCK=y +CONFIG_CLKBLD_I8253=y +# end of Clock Source drivers + +CONFIG_MAILBOX=y +CONFIG_PCC=y +CONFIG_ALTERA_MBOX=m +CONFIG_IOMMU_IOVA=y +CONFIG_IOMMU_API=y +CONFIG_IOMMU_SUPPORT=y + +# +# Generic IOMMU Pagetable Support +# +# end of Generic IOMMU Pagetable Support + +# CONFIG_IOMMU_DEBUGFS is not set +# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set +CONFIG_AMD_IOMMU=y +CONFIG_AMD_IOMMU_V2=m +CONFIG_DMAR_TABLE=y +CONFIG_INTEL_IOMMU=y +# CONFIG_INTEL_IOMMU_SVM is not set +# CONFIG_INTEL_IOMMU_DEFAULT_ON is not set +CONFIG_INTEL_IOMMU_FLOPPY_WA=y +CONFIG_IRQ_REMAP=y +CONFIG_HYPERV_IOMMU=y + +# +# Remoteproc drivers +# +# CONFIG_REMOTEPROC is not set +# end of Remoteproc drivers + +# +# Rpmsg drivers +# +CONFIG_RPMSG=m +# CONFIG_RPMSG_CHAR is not set +CONFIG_RPMSG_QCOM_GLINK_NATIVE=m +CONFIG_RPMSG_QCOM_GLINK_RPM=m +CONFIG_RPMSG_VIRTIO=m +# end of Rpmsg drivers + +CONFIG_SOUNDWIRE=y + +# +# SoundWire Devices +# +CONFIG_SOUNDWIRE_CADENCE=m +CONFIG_SOUNDWIRE_INTEL=m + +# +# SOC (System On Chip) specific Drivers +# + +# +# Amlogic SoC drivers +# +# end of Amlogic SoC drivers + +# +# Aspeed SoC drivers +# +# end of Aspeed SoC drivers + +# +# Broadcom SoC drivers +# +# end of Broadcom SoC drivers + +# +# NXP/Freescale QorIQ SoC drivers +# +# end of NXP/Freescale QorIQ SoC drivers + +# +# i.MX SoC drivers +# +# end of i.MX SoC drivers + +# +# Qualcomm SoC drivers +# +# end of Qualcomm SoC drivers + +# CONFIG_SOC_TI is not set + +# +# Xilinx SoC drivers +# +CONFIG_XILINX_VCU=m +# end of Xilinx SoC drivers +# end of SOC (System On Chip) specific Drivers + +CONFIG_PM_DEVFREQ=y + +# +# DEVFREQ Governors +# +CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=m +# CONFIG_DEVFREQ_GOV_PERFORMANCE is not set +# CONFIG_DEVFREQ_GOV_POWERSAVE is not set +# CONFIG_DEVFREQ_GOV_USERSPACE is not set +# CONFIG_DEVFREQ_GOV_PASSIVE is not set + +# +# DEVFREQ Drivers +# +# CONFIG_PM_DEVFREQ_EVENT is not set +CONFIG_EXTCON=y + +# +# Extcon Device Drivers +# +CONFIG_EXTCON_ADC_JACK=m +# CONFIG_EXTCON_ARIZONA is not set +CONFIG_EXTCON_AXP288=m +# CONFIG_EXTCON_FSA9480 is not set +CONFIG_EXTCON_GPIO=m +CONFIG_EXTCON_INTEL_INT3496=m +CONFIG_EXTCON_INTEL_CHT_WC=m +CONFIG_EXTCON_MAX14577=m +CONFIG_EXTCON_MAX3355=m +CONFIG_EXTCON_MAX77693=m +CONFIG_EXTCON_MAX8997=m +CONFIG_EXTCON_PALMAS=m +# CONFIG_EXTCON_PTN5150 is not set +CONFIG_EXTCON_RT8973A=m +CONFIG_EXTCON_SM5502=m +CONFIG_EXTCON_USB_GPIO=m +CONFIG_EXTCON_USBC_CROS_EC=m +CONFIG_MEMORY=y +CONFIG_IIO=m +CONFIG_IIO_BUFFER=y +CONFIG_IIO_BUFFER_CB=m +CONFIG_IIO_BUFFER_HW_CONSUMER=m +CONFIG_IIO_KFIFO_BUF=m +CONFIG_IIO_TRIGGERED_BUFFER=m +CONFIG_IIO_CONFIGFS=m +CONFIG_IIO_TRIGGER=y +CONFIG_IIO_CONSUMERS_PER_TRIGGER=2 +CONFIG_IIO_SW_DEVICE=m +CONFIG_IIO_SW_TRIGGER=m +CONFIG_IIO_TRIGGERED_EVENT=m + +# +# Accelerometers +# +CONFIG_ADIS16201=m +CONFIG_ADIS16209=m +CONFIG_ADXL345=m +CONFIG_ADXL345_I2C=m +CONFIG_ADXL345_SPI=m +# CONFIG_ADXL372_SPI is not set +# CONFIG_ADXL372_I2C is not set +CONFIG_BMA180=m +CONFIG_BMA220=m +CONFIG_BMC150_ACCEL=m +CONFIG_BMC150_ACCEL_I2C=m +CONFIG_BMC150_ACCEL_SPI=m +# CONFIG_DA280 is not set +# CONFIG_DA311 is not set +# CONFIG_DMARD09 is not set +# CONFIG_DMARD10 is not set +CONFIG_HID_SENSOR_ACCEL_3D=m +# CONFIG_IIO_CROS_EC_ACCEL_LEGACY is not set +CONFIG_IIO_ST_ACCEL_3AXIS=m +CONFIG_IIO_ST_ACCEL_I2C_3AXIS=m +CONFIG_IIO_ST_ACCEL_SPI_3AXIS=m +CONFIG_KXSD9=m +CONFIG_KXSD9_SPI=m +CONFIG_KXSD9_I2C=m +CONFIG_KXCJK1013=m +# CONFIG_MC3230 is not set +CONFIG_MMA7455=m +CONFIG_MMA7455_I2C=m +CONFIG_MMA7455_SPI=m +CONFIG_MMA7660=m +CONFIG_MMA8452=m +# CONFIG_MMA9551 is not set +# CONFIG_MMA9553 is not set +CONFIG_MXC4005=m +CONFIG_MXC6255=m +CONFIG_SCA3000=m +CONFIG_STK8312=m +CONFIG_STK8BA50=m +# end of Accelerometers + +# +# Analog to digital converters +# +CONFIG_AD_SIGMA_DELTA=m +CONFIG_AD7124=m +CONFIG_AD7266=m +CONFIG_AD7291=m +CONFIG_AD7298=m +CONFIG_AD7476=m +CONFIG_AD7606=m +CONFIG_AD7606_IFACE_PARALLEL=m +CONFIG_AD7606_IFACE_SPI=m +CONFIG_AD7766=m +# CONFIG_AD7768_1 is not set +CONFIG_AD7780=m +CONFIG_AD7791=m +CONFIG_AD7793=m +CONFIG_AD7887=m +CONFIG_AD7923=m +CONFIG_AD7949=m +CONFIG_AD799X=m +# CONFIG_AXP20X_ADC is not set +CONFIG_AXP288_ADC=m +# CONFIG_CC10001_ADC is not set +CONFIG_DLN2_ADC=m +CONFIG_HI8435=m +# CONFIG_HX711 is not set +CONFIG_INA2XX_ADC=m +CONFIG_LP8788_ADC=m +CONFIG_LTC2471=m +# CONFIG_LTC2485 is not set +# CONFIG_LTC2497 is not set +CONFIG_MAX1027=m +# CONFIG_MAX11100 is not set +# CONFIG_MAX1118 is not set +CONFIG_MAX1363=m +# CONFIG_MAX9611 is not set +CONFIG_MCP320X=m +CONFIG_MCP3422=m +# CONFIG_MCP3911 is not set +CONFIG_NAU7802=m +CONFIG_PALMAS_GPADC=m +CONFIG_QCOM_SPMI_IADC=m +# CONFIG_QCOM_SPMI_VADC is not set +# CONFIG_QCOM_SPMI_ADC5 is not set +CONFIG_TI_ADC081C=m +CONFIG_TI_ADC0832=m +CONFIG_TI_ADC084S021=m +# CONFIG_TI_ADC12138 is not set +CONFIG_TI_ADC108S102=m +CONFIG_TI_ADC128S052=m +# CONFIG_TI_ADC161S626 is not set +CONFIG_TI_ADS1015=m +# CONFIG_TI_ADS7950 is not set +CONFIG_TI_AM335X_ADC=m +# CONFIG_TI_TLC4541 is not set +CONFIG_TWL4030_MADC=m +CONFIG_TWL6030_GPADC=m +CONFIG_VIPERBOARD_ADC=m +CONFIG_XILINX_XADC=m +# end of Analog to digital converters + +# +# Analog Front Ends +# +# end of Analog Front Ends + +# +# Amplifiers +# +CONFIG_AD8366=m +# end of Amplifiers + +# +# Chemical Sensors +# +CONFIG_ATLAS_PH_SENSOR=m +# CONFIG_BME680 is not set +CONFIG_CCS811=m +CONFIG_IAQCORE=m +# CONFIG_PMS7003 is not set +# CONFIG_SENSIRION_SGP30 is not set +# CONFIG_SPS30 is not set +CONFIG_VZ89X=m +# end of Chemical Sensors + +CONFIG_IIO_CROS_EC_SENSORS_CORE=m +CONFIG_IIO_CROS_EC_SENSORS=m +CONFIG_IIO_CROS_EC_SENSORS_LID_ANGLE=m + +# +# Hid Sensor IIO Common +# +CONFIG_HID_SENSOR_IIO_COMMON=m +CONFIG_HID_SENSOR_IIO_TRIGGER=m +# end of Hid Sensor IIO Common + +CONFIG_IIO_MS_SENSORS_I2C=m + +# +# SSP Sensor Common +# +# CONFIG_IIO_SSP_SENSORHUB is not set +# end of SSP Sensor Common + +CONFIG_IIO_ST_SENSORS_I2C=m +CONFIG_IIO_ST_SENSORS_SPI=m +CONFIG_IIO_ST_SENSORS_CORE=m + +# +# Digital to analog converters +# +CONFIG_AD5064=m +CONFIG_AD5360=m +CONFIG_AD5380=m +CONFIG_AD5421=m +CONFIG_AD5446=m +CONFIG_AD5449=m +CONFIG_AD5592R_BASE=m +CONFIG_AD5592R=m +CONFIG_AD5593R=m +CONFIG_AD5504=m +CONFIG_AD5624R_SPI=m +# CONFIG_LTC1660 is not set +# CONFIG_LTC2632 is not set +CONFIG_AD5686=m +CONFIG_AD5686_SPI=m +CONFIG_AD5696_I2C=m +CONFIG_AD5755=m +CONFIG_AD5758=m +CONFIG_AD5761=m +CONFIG_AD5764=m +CONFIG_AD5791=m +CONFIG_AD7303=m +# CONFIG_CIO_DAC is not set +CONFIG_AD8801=m +# CONFIG_DS4424 is not set +CONFIG_M62332=m +CONFIG_MAX517=m +CONFIG_MCP4725=m +CONFIG_MCP4922=m +# CONFIG_TI_DAC082S085 is not set +# CONFIG_TI_DAC5571 is not set +# CONFIG_TI_DAC7311 is not set +# CONFIG_TI_DAC7612 is not set +# end of Digital to analog converters + +# +# IIO dummy driver +# +# CONFIG_IIO_SIMPLE_DUMMY is not set +# end of IIO dummy driver + +# +# Frequency Synthesizers DDS/PLL +# + +# +# Clock Generator/Distribution +# +CONFIG_AD9523=m +# end of Clock Generator/Distribution + +# +# Phase-Locked Loop (PLL) frequency synthesizers +# +CONFIG_ADF4350=m +CONFIG_ADF4371=m +# end of Phase-Locked Loop (PLL) frequency synthesizers +# end of Frequency Synthesizers DDS/PLL + +# +# Digital gyroscope sensors +# +CONFIG_ADIS16080=m +CONFIG_ADIS16130=m +CONFIG_ADIS16136=m +CONFIG_ADIS16260=m +CONFIG_ADXRS450=m +CONFIG_BMG160=m +CONFIG_BMG160_I2C=m +CONFIG_BMG160_SPI=m +# CONFIG_FXAS21002C is not set +CONFIG_HID_SENSOR_GYRO_3D=m +# CONFIG_MPU3050_I2C is not set +CONFIG_IIO_ST_GYRO_3AXIS=m +CONFIG_IIO_ST_GYRO_I2C_3AXIS=m +CONFIG_IIO_ST_GYRO_SPI_3AXIS=m +CONFIG_ITG3200=m +# end of Digital gyroscope sensors + +# +# Health Sensors +# + +# +# Heart Rate Monitors +# +CONFIG_AFE4403=m +CONFIG_AFE4404=m +CONFIG_MAX30100=m +# CONFIG_MAX30102 is not set +# end of Heart Rate Monitors +# end of Health Sensors + +# +# Humidity sensors +# +CONFIG_AM2315=m +CONFIG_DHT11=m +CONFIG_HDC100X=m +CONFIG_HID_SENSOR_HUMIDITY=m +CONFIG_HTS221=m +CONFIG_HTS221_I2C=m +CONFIG_HTS221_SPI=m +CONFIG_HTU21=m +CONFIG_SI7005=m +CONFIG_SI7020=m +# end of Humidity sensors + +# +# Inertial measurement units +# +CONFIG_ADIS16400=m +CONFIG_ADIS16460=m +CONFIG_ADIS16480=m +CONFIG_BMI160=m +CONFIG_BMI160_I2C=m +CONFIG_BMI160_SPI=m +# CONFIG_KMX61 is not set +CONFIG_INV_MPU6050_IIO=m +CONFIG_INV_MPU6050_I2C=m +CONFIG_INV_MPU6050_SPI=m +# CONFIG_IIO_ST_LSM6DSX is not set +# end of Inertial measurement units + +CONFIG_IIO_ADIS_LIB=m +CONFIG_IIO_ADIS_LIB_BUFFER=y + +# +# Light sensors +# +CONFIG_ACPI_ALS=m +CONFIG_ADJD_S311=m +CONFIG_AL3320A=m +CONFIG_APDS9300=m +CONFIG_APDS9960=m +CONFIG_BH1750=m +CONFIG_BH1780=m +CONFIG_CM32181=m +# CONFIG_CM3232 is not set +# CONFIG_CM3323 is not set +CONFIG_CM36651=m +CONFIG_IIO_CROS_EC_LIGHT_PROX=m +CONFIG_GP2AP020A00F=m +CONFIG_SENSORS_ISL29018=m +CONFIG_SENSORS_ISL29028=m +CONFIG_ISL29125=m +CONFIG_HID_SENSOR_ALS=m +CONFIG_HID_SENSOR_PROX=m +# CONFIG_JSA1212 is not set +CONFIG_RPR0521=m +CONFIG_LTR501=m +# CONFIG_LV0104CS is not set +CONFIG_MAX44000=m +# CONFIG_MAX44009 is not set +# CONFIG_NOA1305 is not set +CONFIG_OPT3001=m +CONFIG_PA12203001=m +# CONFIG_SI1133 is not set +# CONFIG_SI1145 is not set +CONFIG_STK3310=m +CONFIG_ST_UVIS25=m +CONFIG_ST_UVIS25_I2C=m +CONFIG_ST_UVIS25_SPI=m +CONFIG_TCS3414=m +CONFIG_TCS3472=m +CONFIG_SENSORS_TSL2563=m +CONFIG_TSL2583=m +# CONFIG_TSL2772 is not set +CONFIG_TSL4531=m +CONFIG_US5182D=m +CONFIG_VCNL4000=m +# CONFIG_VCNL4035 is not set +CONFIG_VEML6070=m +# CONFIG_VL6180 is not set +# CONFIG_ZOPT2201 is not set +# end of Light sensors + +# +# Magnetometer sensors +# +CONFIG_AK8975=m +CONFIG_AK09911=m +CONFIG_BMC150_MAGN=m +CONFIG_BMC150_MAGN_I2C=m +CONFIG_BMC150_MAGN_SPI=m +CONFIG_MAG3110=m +CONFIG_HID_SENSOR_MAGNETOMETER_3D=m +CONFIG_MMC35240=m +CONFIG_IIO_ST_MAGN_3AXIS=m +CONFIG_IIO_ST_MAGN_I2C_3AXIS=m +CONFIG_IIO_ST_MAGN_SPI_3AXIS=m +CONFIG_SENSORS_HMC5843=m +CONFIG_SENSORS_HMC5843_I2C=m +CONFIG_SENSORS_HMC5843_SPI=m +# CONFIG_SENSORS_RM3100_I2C is not set +# CONFIG_SENSORS_RM3100_SPI is not set +# end of Magnetometer sensors + +# +# Multiplexers +# +# end of Multiplexers + +# +# Inclinometer sensors +# +CONFIG_HID_SENSOR_INCLINOMETER_3D=m +CONFIG_HID_SENSOR_DEVICE_ROTATION=m +# end of Inclinometer sensors + +# +# Triggers - standalone +# +CONFIG_IIO_HRTIMER_TRIGGER=m +CONFIG_IIO_INTERRUPT_TRIGGER=m +# CONFIG_IIO_TIGHTLOOP_TRIGGER is not set +CONFIG_IIO_SYSFS_TRIGGER=m +# end of Triggers - standalone + +# +# Digital potentiometers +# +# CONFIG_AD5272 is not set +CONFIG_DS1803=m +# CONFIG_MAX5432 is not set +# CONFIG_MAX5481 is not set +# CONFIG_MAX5487 is not set +# CONFIG_MCP4018 is not set +CONFIG_MCP4131=m +CONFIG_MCP4531=m +# CONFIG_MCP41010 is not set +CONFIG_TPL0102=m +# end of Digital potentiometers + +# +# Digital potentiostats +# +# CONFIG_LMP91000 is not set +# end of Digital potentiostats + +# +# Pressure sensors +# +# CONFIG_ABP060MG is not set +# CONFIG_BMP280 is not set +CONFIG_IIO_CROS_EC_BARO=m +# CONFIG_DPS310 is not set +CONFIG_HID_SENSOR_PRESS=m +CONFIG_HP03=m +CONFIG_MPL115=m +CONFIG_MPL115_I2C=m +CONFIG_MPL115_SPI=m +# CONFIG_MPL3115 is not set +# CONFIG_MS5611 is not set +CONFIG_MS5637=m +CONFIG_IIO_ST_PRESS=m +CONFIG_IIO_ST_PRESS_I2C=m +CONFIG_IIO_ST_PRESS_SPI=m +CONFIG_T5403=m +CONFIG_HP206C=m +# CONFIG_ZPA2326 is not set +# end of Pressure sensors + +# +# Lightning sensors +# +CONFIG_AS3935=m +# end of Lightning sensors + +# +# Proximity and distance sensors +# +# CONFIG_ISL29501 is not set +CONFIG_LIDAR_LITE_V2=m +# CONFIG_MB1232 is not set +# CONFIG_RFD77402 is not set +# CONFIG_SRF04 is not set +# CONFIG_SX9500 is not set +# CONFIG_SRF08 is not set +# CONFIG_VL53L0X_I2C is not set +# end of Proximity and distance sensors + +# +# Resolver to digital converters +# +CONFIG_AD2S90=m +CONFIG_AD2S1200=m +# end of Resolver to digital converters + +# +# Temperature sensors +# +# CONFIG_MAXIM_THERMOCOUPLE is not set +CONFIG_HID_SENSOR_TEMP=m +CONFIG_MLX90614=m +CONFIG_MLX90632=m +CONFIG_TMP006=m +# CONFIG_TMP007 is not set +CONFIG_TSYS01=m +CONFIG_TSYS02D=m +# CONFIG_MAX31856 is not set +# end of Temperature sensors + +CONFIG_NTB=m +# CONFIG_NTB_MSI is not set +CONFIG_NTB_AMD=m +CONFIG_NTB_IDT=m +CONFIG_NTB_INTEL=m +# CONFIG_NTB_SWITCHTEC is not set +CONFIG_NTB_PINGPONG=m +CONFIG_NTB_TOOL=m +CONFIG_NTB_PERF=m +CONFIG_NTB_TRANSPORT=m +CONFIG_VME_BUS=y + +# +# VME Bridge Drivers +# +CONFIG_VME_CA91CX42=m +CONFIG_VME_TSI148=m +# CONFIG_VME_FAKE is not set + +# +# VME Board Drivers +# +CONFIG_VMIVME_7805=m + +# +# VME Device Drivers +# +CONFIG_VME_USER=m +CONFIG_PWM=y +CONFIG_PWM_SYSFS=y +CONFIG_PWM_CRC=y +CONFIG_PWM_CROS_EC=m +CONFIG_PWM_LP3943=m +CONFIG_PWM_LPSS=m +CONFIG_PWM_LPSS_PCI=m +CONFIG_PWM_LPSS_PLATFORM=m +CONFIG_PWM_PCA9685=m +CONFIG_PWM_TWL=m +CONFIG_PWM_TWL_LED=m + +# +# IRQ chip support +# +CONFIG_MADERA_IRQ=m +# end of IRQ chip support + +# CONFIG_IPACK_BUS is not set +CONFIG_RESET_CONTROLLER=y +CONFIG_RESET_TI_SYSCON=m + +# +# PHY Subsystem +# +CONFIG_GENERIC_PHY=y +CONFIG_BCM_KONA_USB2_PHY=m +CONFIG_PHY_PXA_28NM_HSIC=m +CONFIG_PHY_PXA_28NM_USB2=m +CONFIG_PHY_CPCAP_USB=m +CONFIG_PHY_QCOM_USB_HS=m +CONFIG_PHY_QCOM_USB_HSIC=m +CONFIG_PHY_SAMSUNG_USB2=m +CONFIG_PHY_TUSB1210=m +# end of PHY Subsystem + +CONFIG_POWERCAP=y +CONFIG_INTEL_RAPL_CORE=m +CONFIG_INTEL_RAPL=m +CONFIG_IDLE_INJECT=y +# CONFIG_MCB is not set + +# +# Performance monitor support +# +# end of Performance monitor support + +CONFIG_RAS=y +# CONFIG_RAS_CEC is not set +CONFIG_THUNDERBOLT=m + +# +# Android +# +# CONFIG_ANDROID is not set +# end of Android + +CONFIG_LIBNVDIMM=m +CONFIG_BLK_DEV_PMEM=m +CONFIG_ND_BLK=m +CONFIG_ND_CLAIM=y +CONFIG_ND_BTT=m +CONFIG_BTT=y +CONFIG_NVDIMM_KEYS=y +CONFIG_DAX_DRIVER=y +CONFIG_DAX=y +CONFIG_DEV_DAX=m +CONFIG_DEV_DAX_KMEM=m +CONFIG_NVMEM=y +CONFIG_NVMEM_SYSFS=y + +# +# HW tracing support +# +CONFIG_STM=m +CONFIG_STM_PROTO_BASIC=m +CONFIG_STM_PROTO_SYS_T=m +CONFIG_STM_DUMMY=m +CONFIG_STM_SOURCE_CONSOLE=m +CONFIG_STM_SOURCE_HEARTBEAT=m +# CONFIG_STM_SOURCE_FTRACE is not set +CONFIG_INTEL_TH=m +CONFIG_INTEL_TH_PCI=m +CONFIG_INTEL_TH_ACPI=m +CONFIG_INTEL_TH_GTH=m +CONFIG_INTEL_TH_STH=m +CONFIG_INTEL_TH_MSU=m +CONFIG_INTEL_TH_PTI=m +# CONFIG_INTEL_TH_DEBUG is not set +# end of HW tracing support + +CONFIG_FPGA=m +# CONFIG_ALTERA_PR_IP_CORE is not set +# CONFIG_FPGA_MGR_ALTERA_PS_SPI is not set +# CONFIG_FPGA_MGR_ALTERA_CVP is not set +# CONFIG_FPGA_MGR_XILINX_SPI is not set +# CONFIG_FPGA_MGR_MACHXO2_SPI is not set +# CONFIG_FPGA_BRIDGE is not set +# CONFIG_FPGA_DFL is not set +CONFIG_PM_OPP=y +CONFIG_UNISYS_VISORBUS=m +# CONFIG_SIOX is not set +# CONFIG_SLIMBUS is not set +# CONFIG_INTERCONNECT is not set +# CONFIG_COUNTER is not set +# end of Device Drivers + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +# CONFIG_VALIDATE_FS_PARSER is not set +CONFIG_FS_IOMAP=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +CONFIG_REISERFS_PROC_INFO=y +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +CONFIG_JFS_FS=m +CONFIG_JFS_POSIX_ACL=y +CONFIG_JFS_SECURITY=y +# CONFIG_JFS_DEBUG is not set +CONFIG_JFS_STATISTICS=y +CONFIG_XFS_FS=m +CONFIG_XFS_QUOTA=y +CONFIG_XFS_POSIX_ACL=y +CONFIG_XFS_RT=y +# CONFIG_XFS_ONLINE_SCRUB is not set +# CONFIG_XFS_WARN is not set +# CONFIG_XFS_DEBUG is not set +CONFIG_GFS2_FS=m +CONFIG_GFS2_FS_LOCKING_DLM=y +CONFIG_OCFS2_FS=m +CONFIG_OCFS2_FS_O2CB=m +CONFIG_OCFS2_FS_USERSPACE_CLUSTER=m +CONFIG_OCFS2_FS_STATS=y +CONFIG_OCFS2_DEBUG_MASKLOG=y +# CONFIG_OCFS2_DEBUG_FS is not set +CONFIG_BTRFS_FS=y +CONFIG_BTRFS_FS_POSIX_ACL=y +# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set +# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set +# CONFIG_BTRFS_DEBUG is not set +# CONFIG_BTRFS_ASSERT is not set +# CONFIG_BTRFS_FS_REF_VERIFY is not set +CONFIG_NILFS2_FS=m +CONFIG_F2FS_FS=m +CONFIG_F2FS_STAT_FS=y +CONFIG_F2FS_FS_XATTR=y +CONFIG_F2FS_FS_POSIX_ACL=y +# CONFIG_F2FS_FS_SECURITY is not set +# CONFIG_F2FS_CHECK_FS is not set +# CONFIG_F2FS_IO_TRACE is not set +# CONFIG_F2FS_FAULT_INJECTION is not set +CONFIG_FS_DAX=y +CONFIG_FS_POSIX_ACL=y +CONFIG_EXPORTFS=y +CONFIG_EXPORTFS_BLOCK_OPS=y +CONFIG_FILE_LOCKING=y +CONFIG_MANDATORY_FILE_LOCKING=y +CONFIG_FS_ENCRYPTION=y +# CONFIG_FS_VERITY is not set +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +CONFIG_FANOTIFY=y +CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_PRINT_QUOTA_WARNING=y +# CONFIG_QUOTA_DEBUG is not set +CONFIG_QUOTA_TREE=y +CONFIG_QFMT_V1=m +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +CONFIG_QUOTACTL_COMPAT=y +CONFIG_AUTOFS4_FS=m +CONFIG_AUTOFS_FS=m +CONFIG_FUSE_FS=m +CONFIG_CUSE=m +CONFIG_VIRTIO_FS=m +CONFIG_OVERLAY_FS=m +# CONFIG_OVERLAY_FS_REDIRECT_DIR is not set +CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y +# CONFIG_OVERLAY_FS_INDEX is not set +# CONFIG_OVERLAY_FS_XINO_AUTO is not set +# CONFIG_OVERLAY_FS_METACOPY is not set +CONFIG_AUFS_FS=m +# CONFIG_AUFS_BRANCH_MAX_127 is not set +CONFIG_AUFS_BRANCH_MAX_511=y +# CONFIG_AUFS_BRANCH_MAX_1023 is not set +# CONFIG_AUFS_BRANCH_MAX_32767 is not set +CONFIG_AUFS_SBILIST=y +# CONFIG_AUFS_HNOTIFY is not set +# CONFIG_AUFS_EXPORT is not set +# CONFIG_AUFS_XATTR is not set +# CONFIG_AUFS_FHSM is not set +# CONFIG_AUFS_RDU is not set +# CONFIG_AUFS_DIRREN is not set +CONFIG_AUFS_SHWH=y +# CONFIG_AUFS_BR_RAMFS is not set +# CONFIG_AUFS_BR_FUSE is not set +CONFIG_AUFS_BR_HFSPLUS=y +CONFIG_AUFS_BDEV_LOOP=y +# CONFIG_AUFS_DEBUG is not set + +# +# Caches +# +CONFIG_FSCACHE=m +CONFIG_FSCACHE_STATS=y +# CONFIG_FSCACHE_HISTOGRAM is not set +CONFIG_FSCACHE_DEBUG=y +# CONFIG_FSCACHE_OBJECT_LIST is not set +CONFIG_CACHEFILES=m +CONFIG_CACHEFILES_DEBUG=y +# CONFIG_CACHEFILES_HISTOGRAM is not set +# end of Caches + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +# end of CD-ROM/DVD Filesystems + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_FAT_DEFAULT_UTF8=y +CONFIG_NTFS_FS=m +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set +# end of DOS/FAT/NT Filesystems + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_VMCORE=y +# CONFIG_PROC_VMCORE_DEVICE_DUMP is not set +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_PROC_CHILDREN=y +CONFIG_PROC_PID_ARCH_STATUS=y +CONFIG_KERNFS=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS_XATTR=y +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_MEMFD_CREATE=y +CONFIG_ARCH_HAS_GIGANTIC_PAGE=y +CONFIG_CONFIGFS_FS=m +CONFIG_EFIVAR_FS=m +# end of Pseudo filesystems + +CONFIG_MISC_FILESYSTEMS=y +CONFIG_ORANGEFS_FS=m +CONFIG_ADFS_FS=m +# CONFIG_ADFS_FS_RW is not set +CONFIG_AFFS_FS=m +CONFIG_ECRYPT_FS=m +# CONFIG_ECRYPT_FS_MESSAGING is not set +CONFIG_HFS_FS=m +CONFIG_HFSPLUS_FS=m +CONFIG_BEFS_FS=m +# CONFIG_BEFS_DEBUG is not set +CONFIG_BFS_FS=m +CONFIG_EFS_FS=m +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +CONFIG_JFFS2_SUMMARY=y +CONFIG_JFFS2_FS_XATTR=y +CONFIG_JFFS2_FS_POSIX_ACL=y +CONFIG_JFFS2_FS_SECURITY=y +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +CONFIG_UBIFS_FS=m +# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set +CONFIG_UBIFS_FS_LZO=y +CONFIG_UBIFS_FS_ZLIB=y +CONFIG_UBIFS_FS_ZSTD=y +# CONFIG_UBIFS_ATIME_SUPPORT is not set +CONFIG_UBIFS_FS_XATTR=y +CONFIG_UBIFS_FS_SECURITY=y +CONFIG_UBIFS_FS_AUTHENTICATION=y +CONFIG_CRAMFS=y +CONFIG_CRAMFS_BLOCKDEV=y +CONFIG_SQUASHFS=m +# CONFIG_SQUASHFS_FILE_CACHE is not set +CONFIG_SQUASHFS_FILE_DIRECT=y +# CONFIG_SQUASHFS_DECOMP_SINGLE is not set +CONFIG_SQUASHFS_DECOMP_MULTI=y +# CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU is not set +CONFIG_SQUASHFS_XATTR=y +CONFIG_SQUASHFS_ZLIB=y +CONFIG_SQUASHFS_LZ4=y +CONFIG_SQUASHFS_LZO=y +CONFIG_SQUASHFS_XZ=y +CONFIG_SQUASHFS_ZSTD=y +# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set +# CONFIG_SQUASHFS_EMBEDDED is not set +CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 +CONFIG_VXFS_FS=m +CONFIG_MINIX_FS=m +CONFIG_OMFS_FS=m +CONFIG_HPFS_FS=m +CONFIG_QNX4FS_FS=m +CONFIG_QNX6FS_FS=m +# CONFIG_QNX6FS_DEBUG is not set +CONFIG_ROMFS_FS=m +# CONFIG_ROMFS_BACKED_BY_BLOCK is not set +# CONFIG_ROMFS_BACKED_BY_MTD is not set +CONFIG_ROMFS_BACKED_BY_BOTH=y +CONFIG_ROMFS_ON_BLOCK=y +CONFIG_ROMFS_ON_MTD=y +CONFIG_PSTORE=y +CONFIG_PSTORE_DEFLATE_COMPRESS=m +CONFIG_PSTORE_LZO_COMPRESS=m +CONFIG_PSTORE_LZ4_COMPRESS=m +CONFIG_PSTORE_LZ4HC_COMPRESS=m +CONFIG_PSTORE_842_COMPRESS=y +CONFIG_PSTORE_ZSTD_COMPRESS=y +CONFIG_PSTORE_COMPRESS=y +CONFIG_PSTORE_DEFLATE_COMPRESS_DEFAULT=y +# CONFIG_PSTORE_LZO_COMPRESS_DEFAULT is not set +# CONFIG_PSTORE_LZ4_COMPRESS_DEFAULT is not set +# CONFIG_PSTORE_LZ4HC_COMPRESS_DEFAULT is not set +# CONFIG_PSTORE_842_COMPRESS_DEFAULT is not set +# CONFIG_PSTORE_ZSTD_COMPRESS_DEFAULT is not set +CONFIG_PSTORE_COMPRESS_DEFAULT="deflate" +# CONFIG_PSTORE_CONSOLE is not set +# CONFIG_PSTORE_PMSG is not set +# CONFIG_PSTORE_FTRACE is not set +CONFIG_PSTORE_RAM=m +CONFIG_SYSV_FS=m +CONFIG_UFS_FS=m +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_UFS_DEBUG is not set +CONFIG_EROFS_FS=m +# CONFIG_EROFS_FS_DEBUG is not set +CONFIG_EROFS_FS_XATTR=y +CONFIG_EROFS_FS_POSIX_ACL=y +# CONFIG_EROFS_FS_SECURITY is not set +# CONFIG_EROFS_FS_ZIP is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=m +CONFIG_NFS_V2=m +CONFIG_NFS_V3=m +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=m +CONFIG_NFS_SWAP=y +CONFIG_NFS_V4_1=y +CONFIG_NFS_V4_2=y +CONFIG_PNFS_FILE_LAYOUT=m +CONFIG_PNFS_BLOCK=m +CONFIG_PNFS_FLEXFILE_LAYOUT=m +CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN="kernel.org" +# CONFIG_NFS_V4_1_MIGRATION is not set +CONFIG_NFS_V4_SECURITY_LABEL=y +CONFIG_NFS_FSCACHE=y +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +CONFIG_NFS_DEBUG=y +CONFIG_NFSD=m +CONFIG_NFSD_V2_ACL=y +CONFIG_NFSD_V3=y +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y +CONFIG_NFSD_PNFS=y +CONFIG_NFSD_BLOCKLAYOUT=y +CONFIG_NFSD_SCSILAYOUT=y +CONFIG_NFSD_FLEXFILELAYOUT=y +# CONFIG_NFSD_V4_SECURITY_LABEL is not set +CONFIG_GRACE_PERIOD=m +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_NFS_ACL_SUPPORT=m +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_SUNRPC_BACKCHANNEL=y +CONFIG_SUNRPC_SWAP=y +CONFIG_RPCSEC_GSS_KRB5=m +# CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES is not set +CONFIG_SUNRPC_DEBUG=y +CONFIG_SUNRPC_XPRT_RDMA=m +CONFIG_CEPH_FS=m +CONFIG_CEPH_FSCACHE=y +CONFIG_CEPH_FS_POSIX_ACL=y +CONFIG_CEPH_FS_SECURITY_LABEL=y +CONFIG_CIFS=m +CONFIG_CIFS_STATS2=y +CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y +CONFIG_CIFS_WEAK_PW_HASH=y +CONFIG_CIFS_UPCALL=y +CONFIG_CIFS_XATTR=y +CONFIG_CIFS_POSIX=y +CONFIG_CIFS_DEBUG=y +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_DEBUG_DUMP_KEYS is not set +CONFIG_CIFS_DFS_UPCALL=y +# CONFIG_CIFS_SMB_DIRECT is not set +# CONFIG_CIFS_FSCACHE is not set +CONFIG_CODA_FS=m +CONFIG_AFS_FS=m +# CONFIG_AFS_DEBUG is not set +CONFIG_AFS_FSCACHE=y +# CONFIG_AFS_DEBUG_CURSOR is not set +CONFIG_9P_FS=m +CONFIG_9P_FSCACHE=y +CONFIG_9P_FS_POSIX_ACL=y +# CONFIG_9P_FS_SECURITY is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_MAC_ROMAN=m +CONFIG_NLS_MAC_CELTIC=m +CONFIG_NLS_MAC_CENTEURO=m +CONFIG_NLS_MAC_CROATIAN=m +CONFIG_NLS_MAC_CYRILLIC=m +CONFIG_NLS_MAC_GAELIC=m +CONFIG_NLS_MAC_GREEK=m +CONFIG_NLS_MAC_ICELAND=m +CONFIG_NLS_MAC_INUIT=m +CONFIG_NLS_MAC_ROMANIAN=m +CONFIG_NLS_MAC_TURKISH=m +CONFIG_NLS_UTF8=m +CONFIG_DLM=m +# CONFIG_DLM_DEBUG is not set +# CONFIG_UNICODE is not set +# end of File systems + +# +# Security options +# +CONFIG_KEYS=y +CONFIG_KEYS_COMPAT=y +# CONFIG_KEYS_REQUEST_CACHE is not set +# CONFIG_PERSISTENT_KEYRINGS is not set +# CONFIG_BIG_KEYS is not set +CONFIG_TRUSTED_KEYS=m +CONFIG_ENCRYPTED_KEYS=y +# CONFIG_KEY_DH_OPERATIONS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY=y +CONFIG_SECURITYFS=y +CONFIG_SECURITY_NETWORK=y +CONFIG_PAGE_TABLE_ISOLATION=y +# CONFIG_SECURITY_INFINIBAND is not set +CONFIG_SECURITY_NETWORK_XFRM=y +CONFIG_SECURITY_PATH=y +CONFIG_INTEL_TXT=y +CONFIG_LSM_MMAP_MIN_ADDR=65536 +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_HARDENED_USERCOPY_FALLBACK=y +# CONFIG_HARDENED_USERCOPY_PAGESPAN is not set +CONFIG_FORTIFY_SOURCE=y +# CONFIG_STATIC_USERMODEHELPER is not set +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +# CONFIG_SECURITY_SELINUX_DISABLE is not set +CONFIG_SECURITY_SELINUX_DEVELOP=y +# CONFIG_SECURITY_SELINUX_AVC_STATS is not set +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=0 +# CONFIG_SECURITY_SMACK is not set +CONFIG_SECURITY_TOMOYO=y +CONFIG_SECURITY_TOMOYO_MAX_ACCEPT_ENTRY=2048 +CONFIG_SECURITY_TOMOYO_MAX_AUDIT_LOG=1024 +# CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER is not set +CONFIG_SECURITY_TOMOYO_POLICY_LOADER="/sbin/tomoyo-init" +CONFIG_SECURITY_TOMOYO_ACTIVATION_TRIGGER="/sbin/init" +# CONFIG_SECURITY_TOMOYO_INSECURE_BUILTIN_SETTING is not set +# CONFIG_SECURITY_APPARMOR is not set +# CONFIG_SECURITY_LOADPIN is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_SECURITY_SAFESETID is not set +# CONFIG_SECURITY_LOCKDOWN_LSM is not set +CONFIG_INTEGRITY=y +# CONFIG_INTEGRITY_SIGNATURE is not set +CONFIG_INTEGRITY_AUDIT=y +# CONFIG_IMA is not set +# CONFIG_EVM is not set +CONFIG_DEFAULT_SECURITY_SELINUX=y +# CONFIG_DEFAULT_SECURITY_TOMOYO is not set +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_LSM="" + +# +# Kernel hardening options +# + +# +# Memory initialization +# +CONFIG_INIT_STACK_NONE=y +# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set +# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set +# end of Memory initialization +# end of Kernel hardening options +# end of Security options + +CONFIG_XOR_BLOCKS=y +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_ASYNC_PQ=m +CONFIG_ASYNC_RAID6_RECOV=m +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=y +CONFIG_CRYPTO_AKCIPHER2=y +CONFIG_CRYPTO_AKCIPHER=y +CONFIG_CRYPTO_KPP2=y +CONFIG_CRYPTO_KPP=m +CONFIG_CRYPTO_ACOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_USER=m +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_NULL2=y +CONFIG_CRYPTO_PCRYPT=m +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_AUTHENC=m +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_SIMD=m +CONFIG_CRYPTO_GLUE_HELPER_X86=m +CONFIG_CRYPTO_ENGINE=m + +# +# Public-key cryptography +# +CONFIG_CRYPTO_RSA=y +CONFIG_CRYPTO_DH=m +CONFIG_CRYPTO_ECC=m +CONFIG_CRYPTO_ECDH=m +CONFIG_CRYPTO_ECRDSA=m + +# +# Authenticated Encryption with Associated Data +# +CONFIG_CRYPTO_CCM=m +CONFIG_CRYPTO_GCM=m +CONFIG_CRYPTO_CHACHA20POLY1305=m +CONFIG_CRYPTO_AEGIS128=m +CONFIG_CRYPTO_AEGIS128_AESNI_SSE2=m +CONFIG_CRYPTO_SEQIV=y +CONFIG_CRYPTO_ECHAINIV=m + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_CFB=m +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_CTS=y +CONFIG_CRYPTO_ECB=y +CONFIG_CRYPTO_LRW=m +CONFIG_CRYPTO_OFB=m +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_XTS=y +CONFIG_CRYPTO_KEYWRAP=m +CONFIG_CRYPTO_NHPOLY1305=m +CONFIG_CRYPTO_NHPOLY1305_SSE2=m +CONFIG_CRYPTO_NHPOLY1305_AVX2=m +CONFIG_CRYPTO_ADIANTUM=m +CONFIG_CRYPTO_ESSIV=m + +# +# Hash modes +# +CONFIG_CRYPTO_CMAC=m +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_XCBC=m +CONFIG_CRYPTO_VMAC=m + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_CRC32C_INTEL=m +CONFIG_CRYPTO_CRC32=m +CONFIG_CRYPTO_CRC32_PCLMUL=m +CONFIG_CRYPTO_XXHASH=m +CONFIG_CRYPTO_CRCT10DIF=y +CONFIG_CRYPTO_CRCT10DIF_PCLMUL=y +CONFIG_CRYPTO_GHASH=m +CONFIG_CRYPTO_POLY1305=m +CONFIG_CRYPTO_POLY1305_X86_64=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_RMD128=m +CONFIG_CRYPTO_RMD160=m +CONFIG_CRYPTO_RMD256=m +CONFIG_CRYPTO_RMD320=m +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA1_SSSE3=m +CONFIG_CRYPTO_SHA256_SSSE3=m +CONFIG_CRYPTO_SHA512_SSSE3=m +CONFIG_CRYPTO_LIB_SHA256=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_SHA512=y +CONFIG_CRYPTO_SHA3=m +CONFIG_CRYPTO_SM3=m +CONFIG_CRYPTO_STREEBOG=m +CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL=m + +# +# Ciphers +# +CONFIG_CRYPTO_LIB_AES=y +CONFIG_CRYPTO_AES=y +CONFIG_CRYPTO_AES_TI=m +CONFIG_CRYPTO_AES_NI_INTEL=m +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_LIB_ARC4=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_BLOWFISH_COMMON=m +CONFIG_CRYPTO_BLOWFISH_X86_64=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_CAMELLIA_X86_64=m +CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64=m +CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64=m +CONFIG_CRYPTO_CAST_COMMON=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST5_AVX_X86_64=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_CAST6_AVX_X86_64=m +CONFIG_CRYPTO_LIB_DES=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_DES3_EDE_X86_64=m +CONFIG_CRYPTO_FCRYPT=m +CONFIG_CRYPTO_KHAZAD=m +CONFIG_CRYPTO_SALSA20=m +CONFIG_CRYPTO_CHACHA20=m +CONFIG_CRYPTO_CHACHA20_X86_64=m +CONFIG_CRYPTO_SEED=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_SERPENT_SSE2_X86_64=m +CONFIG_CRYPTO_SERPENT_AVX_X86_64=m +CONFIG_CRYPTO_SERPENT_AVX2_X86_64=m +CONFIG_CRYPTO_SM4=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_TWOFISH_COMMON=m +CONFIG_CRYPTO_TWOFISH_X86_64=m +CONFIG_CRYPTO_TWOFISH_X86_64_3WAY=m +CONFIG_CRYPTO_TWOFISH_AVX_X86_64=m + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_LZO=y +CONFIG_CRYPTO_842=y +CONFIG_CRYPTO_LZ4=m +CONFIG_CRYPTO_LZ4HC=m +CONFIG_CRYPTO_ZSTD=y + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +CONFIG_CRYPTO_DRBG_MENU=y +CONFIG_CRYPTO_DRBG_HMAC=y +# CONFIG_CRYPTO_DRBG_HASH is not set +# CONFIG_CRYPTO_DRBG_CTR is not set +CONFIG_CRYPTO_DRBG=y +CONFIG_CRYPTO_JITTERENTROPY=y +CONFIG_CRYPTO_USER_API=m +CONFIG_CRYPTO_USER_API_HASH=m +CONFIG_CRYPTO_USER_API_SKCIPHER=m +CONFIG_CRYPTO_USER_API_RNG=m +CONFIG_CRYPTO_USER_API_AEAD=m +# CONFIG_CRYPTO_STATS is not set +CONFIG_CRYPTO_HASH_INFO=y +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_DEV_PADLOCK=m +CONFIG_CRYPTO_DEV_PADLOCK_AES=m +CONFIG_CRYPTO_DEV_PADLOCK_SHA=m +CONFIG_CRYPTO_DEV_ATMEL_I2C=m +CONFIG_CRYPTO_DEV_ATMEL_ECC=m +CONFIG_CRYPTO_DEV_ATMEL_SHA204A=m +CONFIG_CRYPTO_DEV_CCP=y +CONFIG_CRYPTO_DEV_CCP_DD=m +CONFIG_CRYPTO_DEV_SP_CCP=y +CONFIG_CRYPTO_DEV_CCP_CRYPTO=m +CONFIG_CRYPTO_DEV_SP_PSP=y +# CONFIG_CRYPTO_DEV_CCP_DEBUGFS is not set +CONFIG_CRYPTO_DEV_QAT=m +CONFIG_CRYPTO_DEV_QAT_DH895xCC=m +CONFIG_CRYPTO_DEV_QAT_C3XXX=m +CONFIG_CRYPTO_DEV_QAT_C62X=m +CONFIG_CRYPTO_DEV_QAT_DH895xCCVF=m +CONFIG_CRYPTO_DEV_QAT_C3XXXVF=m +CONFIG_CRYPTO_DEV_QAT_C62XVF=m +CONFIG_CRYPTO_DEV_NITROX=m +CONFIG_CRYPTO_DEV_NITROX_CNN55XX=m +CONFIG_CRYPTO_DEV_CHELSIO=m +CONFIG_CHELSIO_IPSEC_INLINE=y +CONFIG_CRYPTO_DEV_CHELSIO_TLS=m +CONFIG_CRYPTO_DEV_VIRTIO=m +CONFIG_CRYPTO_DEV_SAFEXCEL=m +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_ASYMMETRIC_TPM_KEY_SUBTYPE=m +CONFIG_X509_CERTIFICATE_PARSER=y +CONFIG_PKCS8_PRIVATE_KEY_PARSER=m +CONFIG_TPM_KEY_PARSER=m +CONFIG_PKCS7_MESSAGE_PARSER=y +# CONFIG_PKCS7_TEST_KEY is not set +CONFIG_SIGNED_PE_FILE_VERIFICATION=y + +# +# Certificates for signature checking +# +CONFIG_SYSTEM_TRUSTED_KEYRING=y +CONFIG_SYSTEM_TRUSTED_KEYS="" +# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set +# CONFIG_SECONDARY_TRUSTED_KEYRING is not set +# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set +# end of Certificates for signature checking + +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_RAID6_PQ=y +CONFIG_RAID6_PQ_BENCHMARK=y +# CONFIG_PACKING is not set +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_NET_UTILS=y +CONFIG_GENERIC_FIND_FIRST_BIT=y +CONFIG_CORDIC=m +CONFIG_RATIONAL=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IOMAP=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_HAS_FAST_MULTIPLIER=y +CONFIG_CRC_CCITT=m +CONFIG_CRC16=y +CONFIG_CRC_T10DIF=y +CONFIG_CRC_ITU_T=m +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_CRC64=y +CONFIG_CRC4=m +CONFIG_CRC7=m +CONFIG_LIBCRC32C=y +CONFIG_CRC8=m +CONFIG_XXHASH=y +# CONFIG_RANDOM32_SELFTEST is not set +CONFIG_842_COMPRESS=y +CONFIG_842_DECOMPRESS=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_LZ4_COMPRESS=m +CONFIG_LZ4HC_COMPRESS=m +CONFIG_LZ4_DECOMPRESS=y +CONFIG_ZSTD_COMPRESS=y +CONFIG_ZSTD_DECOMPRESS=y +CONFIG_XZ_DEC=y +CONFIG_XZ_DEC_X86=y +# CONFIG_XZ_DEC_POWERPC is not set +# CONFIG_XZ_DEC_IA64 is not set +# CONFIG_XZ_DEC_ARM is not set +# CONFIG_XZ_DEC_ARMTHUMB is not set +# CONFIG_XZ_DEC_SPARC is not set +CONFIG_XZ_DEC_BCJ=y +# CONFIG_XZ_DEC_TEST is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_BZIP2=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_DECOMPRESS_XZ=y +CONFIG_DECOMPRESS_LZO=y +CONFIG_DECOMPRESS_LZ4=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_REED_SOLOMON=m +CONFIG_REED_SOLOMON_ENC8=y +CONFIG_REED_SOLOMON_DEC8=y +CONFIG_REED_SOLOMON_DEC16=y +CONFIG_BCH=m +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=m +CONFIG_TEXTSEARCH_BM=m +CONFIG_TEXTSEARCH_FSM=m +CONFIG_BTREE=y +CONFIG_INTERVAL_TREE=y +CONFIG_XARRAY_MULTI=y +CONFIG_ASSOCIATIVE_ARRAY=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAS_DMA=y +CONFIG_NEED_SG_DMA_LENGTH=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_DMA_VIRT_OPS=y +CONFIG_SWIOTLB=y +# CONFIG_DMA_CMA is not set +# CONFIG_DMA_API_DEBUG is not set +CONFIG_SGL_ALLOC=y +CONFIG_IOMMU_HELPER=y +CONFIG_CHECK_SIGNATURE=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_GLOB=y +# CONFIG_GLOB_SELFTEST is not set +CONFIG_NLATTR=y +CONFIG_CLZ_TAB=y +CONFIG_IRQ_POLL=y +CONFIG_MPILIB=y +CONFIG_DIMLIB=y +CONFIG_OID_REGISTRY=y +CONFIG_UCS2_STRING=y +CONFIG_HAVE_GENERIC_VDSO=y +CONFIG_GENERIC_GETTIMEOFDAY=y +CONFIG_FONT_SUPPORT=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +CONFIG_SG_POOL=y +CONFIG_ARCH_HAS_PMEM_API=y +CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE=y +CONFIG_ARCH_HAS_UACCESS_MCSAFE=y +CONFIG_ARCH_STACKWALK=y +CONFIG_SBITMAP=y +CONFIG_PARMAN=m +CONFIG_OBJAGG=m +# CONFIG_STRING_SELFTEST is not set +# end of Library routines + +# +# Kernel hacking +# + +# +# printk and dmesg options +# +CONFIG_PRINTK_TIME=y +# CONFIG_PRINTK_CALLER is not set +CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7 +CONFIG_CONSOLE_LOGLEVEL_QUIET=4 +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 +CONFIG_BOOT_PRINTK_DELAY=y +CONFIG_DYNAMIC_DEBUG=y +# end of printk and dmesg options + +# +# Compile-time checks and compiler options +# +# CONFIG_DEBUG_INFO is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=2048 +CONFIG_STRIP_ASM_SYMS=y +# CONFIG_READABLE_ASM is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_INSTALL is not set +CONFIG_OPTIMIZE_INLINING=y +# CONFIG_DEBUG_SECTION_MISMATCH is not set +CONFIG_SECTION_MISMATCH_WARN_ONLY=y +CONFIG_STACK_VALIDATION=y +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# end of Compile-time checks and compiler options + +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +CONFIG_MAGIC_SYSRQ_SERIAL=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_MISC=y + +# +# Memory Debugging +# +# CONFIG_PAGE_EXTENSION is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_PAGE_OWNER is not set +# CONFIG_PAGE_POISONING is not set +# CONFIG_DEBUG_PAGE_REF is not set +# CONFIG_DEBUG_RODATA_TEST is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_VM is not set +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +# CONFIG_DEBUG_VIRTUAL is not set +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_MEMORY_NOTIFIER_ERROR_INJECT=m +# CONFIG_DEBUG_PER_CPU_MAPS is not set +CONFIG_HAVE_ARCH_KASAN=y +CONFIG_CC_HAS_KASAN_GENERIC=y +# CONFIG_KASAN is not set +CONFIG_KASAN_STACK=1 +# end of Memory Debugging + +CONFIG_ARCH_HAS_KCOV=y +CONFIG_CC_HAS_SANCOV_TRACE_PC=y +# CONFIG_KCOV is not set +# CONFIG_DEBUG_SHIRQ is not set + +# +# Debug Lockups and Hangs +# +# CONFIG_SOFTLOCKUP_DETECTOR is not set +CONFIG_HARDLOCKUP_CHECK_TIMESTAMP=y +# CONFIG_HARDLOCKUP_DETECTOR is not set +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +# CONFIG_WQ_WATCHDOG is not set +# end of Debug Lockups and Hangs + +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +CONFIG_PANIC_TIMEOUT=0 +CONFIG_SCHED_DEBUG=y +CONFIG_SCHED_INFO=y +CONFIG_SCHEDSTATS=y +# CONFIG_SCHED_STACK_END_CHECK is not set +# CONFIG_DEBUG_TIMEKEEPING is not set + +# +# Lock Debugging (spinlocks, mutexes, etc...) +# +CONFIG_LOCK_DEBUGGING_SUPPORT=y +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_LOCK_TORTURE_TEST is not set +# CONFIG_WW_MUTEX_SELFTEST is not set +# end of Lock Debugging (spinlocks, mutexes, etc...) + +CONFIG_STACKTRACE=y +# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_DEBUG_BUGVERBOSE=y +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_PLIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set + +# +# RCU Debugging +# +CONFIG_TORTURE_TEST=m +CONFIG_RCU_PERF_TEST=m +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_TRACE is not set +# CONFIG_RCU_EQS_DEBUG is not set +# end of RCU Debugging + +# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +CONFIG_NOTIFIER_ERROR_INJECTION=m +CONFIG_PM_NOTIFIER_ERROR_INJECT=m +# CONFIG_NETDEV_NOTIFIER_ERROR_INJECT is not set +CONFIG_FUNCTION_ERROR_INJECTION=y +# CONFIG_FAULT_INJECTION is not set +CONFIG_LATENCYTOP=y +CONFIG_USER_STACKTRACE_SUPPORT=y +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_FENTRY=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACER_MAX_TRACE=y +CONFIG_TRACE_CLOCK=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_RING_BUFFER_ALLOW_SWAP=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +CONFIG_FUNCTION_TRACER=y +# CONFIG_FUNCTION_GRAPH_TRACER is not set +# CONFIG_PREEMPTIRQ_EVENTS is not set +# CONFIG_IRQSOFF_TRACER is not set +CONFIG_SCHED_TRACER=y +# CONFIG_HWLAT_TRACER is not set +CONFIG_FTRACE_SYSCALLS=y +CONFIG_TRACER_SNAPSHOT=y +# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +CONFIG_STACK_TRACER=y +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_KPROBE_EVENTS=y +# CONFIG_KPROBE_EVENTS_ON_NOTRACE is not set +CONFIG_UPROBE_EVENTS=y +CONFIG_BPF_EVENTS=y +CONFIG_DYNAMIC_EVENTS=y +CONFIG_PROBE_EVENTS=y +CONFIG_DYNAMIC_FTRACE=y +CONFIG_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_FUNCTION_PROFILER=y +# CONFIG_BPF_KPROBE_OVERRIDE is not set +CONFIG_FTRACE_MCOUNT_RECORD=y +# CONFIG_FTRACE_STARTUP_TEST is not set +CONFIG_MMIOTRACE=y +# CONFIG_HIST_TRIGGERS is not set +# CONFIG_MMIOTRACE_TEST is not set +# CONFIG_TRACEPOINT_BENCHMARK is not set +CONFIG_RING_BUFFER_BENCHMARK=m +# CONFIG_RING_BUFFER_STARTUP_TEST is not set +# CONFIG_PREEMPTIRQ_DELAY_TEST is not set +# CONFIG_TRACE_EVAL_MAP_FILE is not set +# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set +CONFIG_RUNTIME_TESTING_MENU=y +# CONFIG_LKDTM is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_TEST_SORT is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +CONFIG_RBTREE_TEST=m +# CONFIG_REED_SOLOMON_TEST is not set +CONFIG_INTERVAL_TREE_TEST=m +# CONFIG_PERCPU_TEST is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_ASYNC_RAID6_TEST is not set +# CONFIG_TEST_HEXDUMP is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_STRSCPY is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_TEST_PRINTF is not set +# CONFIG_TEST_BITMAP is not set +# CONFIG_TEST_BITFIELD is not set +# CONFIG_TEST_UUID is not set +CONFIG_TEST_XARRAY=m +# CONFIG_TEST_OVERFLOW is not set +# CONFIG_TEST_RHASHTABLE is not set +# CONFIG_TEST_HASH is not set +# CONFIG_TEST_IDA is not set +# CONFIG_TEST_PARMAN is not set +# CONFIG_TEST_LKM is not set +# CONFIG_TEST_VMALLOC is not set +# CONFIG_TEST_USER_COPY is not set +# CONFIG_TEST_BPF is not set +# CONFIG_TEST_BLACKHOLE_DEV is not set +# CONFIG_FIND_BIT_BENCHMARK is not set +# CONFIG_TEST_FIRMWARE is not set +# CONFIG_TEST_SYSCTL is not set +# CONFIG_TEST_UDELAY is not set +# CONFIG_TEST_STATIC_KEYS is not set +# CONFIG_TEST_KMOD is not set +# CONFIG_TEST_MEMCAT_P is not set +# CONFIG_TEST_LIVEPATCH is not set +# CONFIG_TEST_OBJAGG is not set +# CONFIG_TEST_STACKINIT is not set +# CONFIG_TEST_MEMINIT is not set +CONFIG_MEMTEST=y +# CONFIG_BUG_ON_DATA_CORRUPTION is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y +# CONFIG_UBSAN is not set +CONFIG_UBSAN_ALIGNMENT=y +CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y +CONFIG_STRICT_DEVMEM=y +CONFIG_IO_STRICT_DEVMEM=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_X86_VERBOSE_BOOTUP=y +CONFIG_EARLY_PRINTK=y +# CONFIG_EARLY_PRINTK_DBGP is not set +# CONFIG_EARLY_PRINTK_USB_XDBC is not set +CONFIG_X86_PTDUMP_CORE=y +# CONFIG_X86_PTDUMP is not set +# CONFIG_EFI_PGT_DUMP is not set +CONFIG_DEBUG_WX=y +CONFIG_DOUBLEFAULT=y +# CONFIG_DEBUG_TLBFLUSH is not set +# CONFIG_IOMMU_DEBUG is not set +CONFIG_HAVE_MMIOTRACE_SUPPORT=y +# CONFIG_X86_DECODER_SELFTEST is not set +CONFIG_IO_DELAY_0X80=y +# CONFIG_IO_DELAY_0XED is not set +# CONFIG_IO_DELAY_UDELAY is not set +# CONFIG_IO_DELAY_NONE is not set +# CONFIG_DEBUG_BOOT_PARAMS is not set +# CONFIG_CPA_DEBUG is not set +# CONFIG_DEBUG_ENTRY is not set +# CONFIG_DEBUG_NMI_SELFTEST is not set +CONFIG_X86_DEBUG_FPU=y +CONFIG_PUNIT_ATOM_DEBUG=m +CONFIG_UNWINDER_ORC=y +# CONFIG_UNWINDER_FRAME_POINTER is not set +# CONFIG_UNWINDER_GUESS is not set +# end of Kernel hacking diff --git a/kernel/kernel/files/patches/linux/patch-5.4.6.xz b/kernel/kernel/files/patches/linux/patch-5.4.6.xz new file mode 100644 index 00000000..96152450 Binary files /dev/null and b/kernel/kernel/files/patches/linux/patch-5.4.6.xz differ diff --git a/kernel/kernel/files/patches/mageia/CVE-2019-12379.patch b/kernel/kernel/files/patches/mageia/CVE-2019-12379.patch new file mode 100644 index 00000000..04d16049 --- /dev/null +++ b/kernel/kernel/files/patches/mageia/CVE-2019-12379.patch @@ -0,0 +1,37 @@ +From 84ecc2f6eb1cb12e6d44818f94fa49b50f06e6ac Mon Sep 17 00:00:00 2001 +From: Gen Zhang +Date: Thu, 23 May 2019 08:34:52 +0800 +Subject: consolemap: Fix a memory leaking bug in drivers/tty/vt/consolemap.c + +In function con_insert_unipair(), when allocation for p2 and p1[n] +fails, ENOMEM is returned, but previously allocated p1 is not freed, +remains as leaking memory. Thus we should free p1 as well when this +allocation fails. + +Signed-off-by: Gen Zhang +Reviewed-by: Kees Cook +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/vt/consolemap.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c +index b28aa0d289f8..79fcc96cc7c0 100644 +--- a/drivers/tty/vt/consolemap.c ++++ b/drivers/tty/vt/consolemap.c +@@ -489,7 +489,11 @@ con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos) + p2 = p1[n = (unicode >> 6) & 0x1f]; + if (!p2) { + p2 = p1[n] = kmalloc_array(64, sizeof(u16), GFP_KERNEL); +- if (!p2) return -ENOMEM; ++ if (!p2) { ++ kfree(p1); ++ p->uni_pgdir[n] = NULL; ++ return -ENOMEM; ++ } + memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */ + } + +-- +cgit 1.2-0.3.lf.el7 + diff --git a/kernel/kernel/files/patches/mageia/disable-mrproper-in-devel-rpms.patch b/kernel/kernel/files/patches/mageia/disable-mrproper-in-devel-rpms.patch new file mode 100644 index 00000000..150d8e1e --- /dev/null +++ b/kernel/kernel/files/patches/mageia/disable-mrproper-in-devel-rpms.patch @@ -0,0 +1,74 @@ + + Makefile | 18 +++++------------- + scripts/kconfig/Makefile | 4 ---- + 2 files changed, 5 insertions(+), 17 deletions(-) + +diff -Nurp linux-5.4.orig/Makefile linux-5.4/Makefile +--- linux-5.4.orig/Makefile 2019-11-30 23:06:49.394199628 +0200 ++++ linux-5.4/Makefile 2019-11-30 23:08:00.927203318 +0200 +@@ -1093,8 +1093,7 @@ include/config/kernel.release: FORCE + # Carefully list dependencies so we do not try to build scripts twice + # in parallel + PHONY += scripts +-scripts: scripts_basic scripts_dtc +- $(Q)$(MAKE) $(build)=$(@) ++scripts: + + # Things we need to do before we recursively start building the kernel + # or the modules are listed in "prepare". +@@ -1112,7 +1111,7 @@ prepare0: archprepare + $(Q)$(MAKE) $(build)=. + + # All the preparing.. +-prepare: prepare0 prepare-objtool ++prepare: + + # Support for using generic headers in asm-generic + asm-generic := -f $(srctree)/scripts/Makefile.asm-generic obj +@@ -1363,15 +1362,8 @@ CLEAN_DIRS += include/ksym + CLEAN_FILES += modules.builtin.modinfo + + # Directories & files removed with 'make mrproper' +-MRPROPER_DIRS += include/config include/generated \ +- arch/$(SRCARCH)/include/generated .tmp_objdiff \ +- debian/ snap/ tar-install/ +-MRPROPER_FILES += .config .config.old .version \ +- Module.symvers \ +- signing_key.pem signing_key.priv signing_key.x509 \ +- x509.genkey extra_certificates signing_key.x509.keyid \ +- signing_key.x509.signer vmlinux-gdb.py \ +- *.spec ++MRPROPER_DIRS += "" ++MRPROPER_FILES += "" + + # Directories & files removed with 'make distclean' + DISTCLEAN_DIRS += +@@ -1394,7 +1386,7 @@ clean: archclean vmlinuxclean + # + mrproper: rm-dirs := $(wildcard $(MRPROPER_DIRS)) + mrproper: rm-files := $(wildcard $(MRPROPER_FILES)) +-mrproper-dirs := $(addprefix _mrproper_,scripts) ++mrproper-dirs := $(addprefix _mrproper_,scripts) + + PHONY += $(mrproper-dirs) mrproper + $(mrproper-dirs): +diff -Nurp linux-5.4.orig/scripts/kconfig/Makefile linux-5.4/scripts/kconfig/Makefile +--- linux-5.4.orig/scripts/kconfig/Makefile 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4/scripts/kconfig/Makefile 2019-11-30 23:07:24.957201462 +0200 +@@ -24,16 +24,12 @@ endif + unexport CONFIG_ + + xconfig: $(obj)/qconf +- $< $(silent) $(Kconfig) + + gconfig: $(obj)/gconf +- $< $(silent) $(Kconfig) + + menuconfig: $(obj)/mconf +- $< $(silent) $(Kconfig) + + config: $(obj)/conf +- $< $(silent) --oldaskconfig $(Kconfig) + + nconfig: $(obj)/nconf + $< $(silent) $(Kconfig) diff --git a/kernel/kernel/files/patches/mageia/fs-aufs-5.4-modular.patch b/kernel/kernel/files/patches/mageia/fs-aufs-5.4-modular.patch new file mode 100644 index 00000000..ec4a9135 --- /dev/null +++ b/kernel/kernel/files/patches/mageia/fs-aufs-5.4-modular.patch @@ -0,0 +1,321 @@ + + fs/aufs/Kconfig | 2 +- + fs/dcache.c | 2 ++ + fs/exec.c | 1 + + fs/fcntl.c | 1 + + fs/file_table.c | 2 ++ + fs/inode.c | 1 + + fs/namespace.c | 3 +++ + fs/notify/group.c | 1 + + fs/open.c | 1 + + fs/read_write.c | 4 ++++ + fs/splice.c | 2 ++ + fs/sync.c | 1 + + fs/xattr.c | 1 + + kernel/locking/lockdep.c | 1 + + kernel/task_work.c | 1 + + security/device_cgroup.c | 1 + + security/security.c | 8 ++++++++ + 17 files changed, 32 insertions(+), 1 deletion(-) + +diff -Nurp linux-5.4-aufs/fs/aufs/Kconfig linux-5.4-aufs-mod/fs/aufs/Kconfig +--- linux-5.4-aufs/fs/aufs/Kconfig 2019-11-28 01:25:59.062925618 +0200 ++++ linux-5.4-aufs-mod/fs/aufs/Kconfig 2019-11-28 01:38:40.564895255 +0200 +@@ -1,6 +1,6 @@ + # SPDX-License-Identifier: GPL-2.0 + config AUFS_FS +- bool "Aufs (Advanced multi layered unification filesystem) support" ++ tristate "Aufs (Advanced multi layered unification filesystem) support" + help + Aufs is a stackable unification filesystem such as Unionfs, + which unifies several directories and provides a merged single +diff -Nurp linux-5.4-aufs/fs/dcache.c linux-5.4-aufs-mod/fs/dcache.c +--- linux-5.4-aufs/fs/dcache.c 2019-11-28 01:25:59.069925618 +0200 ++++ linux-5.4-aufs-mod/fs/dcache.c 2019-11-28 01:38:40.585895254 +0200 +@@ -1369,6 +1369,7 @@ rename_retry: + seq = 1; + goto again; + } ++EXPORT_SYMBOL_GPL(d_walk); + + struct check_mount { + struct vfsmount *mnt; +@@ -2914,6 +2915,7 @@ void d_exchange(struct dentry *dentry1, + + write_sequnlock(&rename_lock); + } ++EXPORT_SYMBOL_GPL(d_exchange); + + /** + * d_ancestor - search for an ancestor +diff -Nurp linux-5.4-aufs/fs/exec.c linux-5.4-aufs-mod/fs/exec.c +--- linux-5.4-aufs/fs/exec.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs-mod/fs/exec.c 2019-11-28 01:38:40.589895254 +0200 +@@ -110,6 +110,7 @@ bool path_noexec(const struct path *path + return (path->mnt->mnt_flags & MNT_NOEXEC) || + (path->mnt->mnt_sb->s_iflags & SB_I_NOEXEC); + } ++EXPORT_SYMBOL_GPL(path_noexec); + + #ifdef CONFIG_USELIB + /* +diff -Nurp linux-5.4-aufs/fs/fcntl.c linux-5.4-aufs-mod/fs/fcntl.c +--- linux-5.4-aufs/fs/fcntl.c 2019-11-28 01:25:59.069925618 +0200 ++++ linux-5.4-aufs-mod/fs/fcntl.c 2019-11-28 01:38:40.589895254 +0200 +@@ -85,6 +85,7 @@ int setfl(int fd, struct file * filp, un + out: + return error; + } ++EXPORT_SYMBOL_GPL(setfl); + + static void f_modown(struct file *filp, struct pid *pid, enum pid_type type, + int force) +diff -Nurp linux-5.4-aufs/fs/file_table.c linux-5.4-aufs-mod/fs/file_table.c +--- linux-5.4-aufs/fs/file_table.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs-mod/fs/file_table.c 2019-11-28 01:38:40.589895254 +0200 +@@ -162,6 +162,7 @@ over: + } + return ERR_PTR(-ENFILE); + } ++EXPORT_SYMBOL_GPL(alloc_empty_file); + + /* + * Variant of alloc_empty_file() that doesn't check and modify nr_files. +@@ -375,6 +377,7 @@ void __fput_sync(struct file *file) + } + + EXPORT_SYMBOL(fput); ++EXPORT_SYMBOL_GPL(__fput_sync); + + void __init files_init(void) + { +diff -Nurp linux-5.4-aufs/fs/inode.c linux-5.4-aufs-mod/fs/inode.c +--- linux-5.4-aufs/fs/inode.c 2019-11-28 01:25:59.070925617 +0200 ++++ linux-5.4-aufs-mod/fs/inode.c 2019-11-28 01:38:40.589895254 +0200 +@@ -1682,6 +1682,7 @@ int update_time(struct inode *inode, str + + return update_time(inode, time, flags); + } ++EXPORT_SYMBOL_GPL(update_time); + + /** + * touch_atime - update the access time +diff -Nurp linux-5.4-aufs/fs/namespace.c linux-5.4-aufs-mod/fs/namespace.c +--- linux-5.4-aufs/fs/namespace.c 2019-11-28 01:25:59.070925617 +0200 ++++ linux-5.4-aufs-mod/fs/namespace.c 2019-11-28 01:38:40.589895254 +0200 +@@ -431,6 +431,7 @@ void __mnt_drop_write(struct vfsmount *m + mnt_dec_writers(real_mount(mnt)); + preempt_enable(); + } ++EXPORT_SYMBOL_GPL(__mnt_drop_write); + + /** + * mnt_drop_write - give up write access to a mount +@@ -781,6 +782,7 @@ int is_current_mnt_ns(struct vfsmount *m + { + return check_mnt(real_mount(mnt)); + } ++EXPORT_SYMBOL_GPL(is_current_mnt_ns); + + /* + * vfsmount lock must be held for write +@@ -1903,6 +1905,7 @@ int iterate_mounts(int (*f)(struct vfsmo + } + return 0; + } ++EXPORT_SYMBOL_GPL(iterate_mounts); + + static void lock_mnt_tree(struct mount *mnt) + { +diff -Nurp linux-5.4-aufs/fs/notify/group.c linux-5.4-aufs-mod/fs/notify/group.c +--- linux-5.4-aufs/fs/notify/group.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs-mod/fs/notify/group.c 2019-11-28 01:38:40.590895253 +0200 +@@ -99,6 +99,7 @@ void fsnotify_get_group(struct fsnotify_ + { + refcount_inc(&group->refcnt); + } ++EXPORT_SYMBOL_GPL(fsnotify_get_group); + + /* + * Drop a reference to a group. Free it if it's through. +diff -Nurp linux-5.4-aufs/fs/open.c linux-5.4-aufs-mod/fs/open.c +--- linux-5.4-aufs/fs/open.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs-mod/fs/open.c 2019-11-28 01:38:48.762894928 +0200 +@@ -65,6 +65,7 @@ int do_truncate(struct dentry *dentry, l + inode_unlock(dentry->d_inode); + return ret; + } ++EXPORT_SYMBOL_GPL(do_truncate); + + long vfs_truncate(const struct path *path, loff_t length) + { +diff -Nurp linux-5.4-aufs/fs/read_write.c linux-5.4-aufs-mod/fs/read_write.c +--- linux-5.4-aufs/fs/read_write.c 2019-11-28 01:25:59.070925617 +0200 ++++ linux-5.4-aufs-mod/fs/read_write.c 2019-11-28 01:38:48.780894927 +0200 +@@ -468,6 +468,7 @@ ssize_t vfs_read(struct file *file, char + + return ret; + } ++EXPORT_SYMBOL_GPL(vfs_read); + + static ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos) + { +@@ -508,6 +509,7 @@ vfs_readf_t vfs_readf(struct file *file) + return new_sync_read; + return ERR_PTR(-ENOSYS); + } ++EXPORT_SYMBOL_GPL(vfs_readf); + + vfs_writef_t vfs_writef(struct file *file) + { +@@ -519,6 +521,7 @@ vfs_writef_t vfs_writef(struct file *fil + return new_sync_write; + return ERR_PTR(-ENOSYS); + } ++EXPORT_SYMBOL_GPL(vfs_writef); + + ssize_t __kernel_write(struct file *file, const void *buf, size_t count, loff_t *pos) + { +@@ -588,6 +591,7 @@ ssize_t vfs_write(struct file *file, con + + return ret; + } ++EXPORT_SYMBOL_GPL(vfs_write); + + /* file_ppos returns &file->f_pos or NULL if file is stream */ + static inline loff_t *file_ppos(struct file *file) +diff -Nurp linux-5.4-aufs/fs/splice.c linux-5.4-aufs-mod/fs/splice.c +--- linux-5.4-aufs/fs/splice.c 2019-11-28 01:25:59.071925617 +0200 ++++ linux-5.4-aufs-mod/fs/splice.c 2019-11-28 01:38:48.780894927 +0200 +@@ -847,6 +847,7 @@ long do_splice_from(struct pipe_inode_in + + return splice_write(pipe, out, ppos, len, flags); + } ++EXPORT_SYMBOL_GPL(do_splice_from); + + /* + * Attempt to initiate a splice from a file to a pipe. +@@ -876,6 +877,7 @@ long do_splice_to(struct file *in, loff_ + + return splice_read(in, ppos, pipe, len, flags); + } ++EXPORT_SYMBOL_GPL(do_splice_to); + + /** + * splice_direct_to_actor - splices data directly between two non-pipes +diff -Nurp linux-5.4-aufs/fs/sync.c linux-5.4-aufs-mod/fs/sync.c +--- linux-5.4-aufs/fs/sync.c 2019-11-28 01:25:59.071925617 +0200 ++++ linux-5.4-aufs-mod/fs/sync.c 2019-11-28 01:38:48.780894927 +0200 +@@ -39,6 +39,7 @@ int __sync_filesystem(struct super_block + sb->s_op->sync_fs(sb, wait); + return __sync_blockdev(sb->s_bdev, wait); + } ++EXPORT_SYMBOL_GPL(__sync_filesystem); + + /* + * Write out and wait upon all dirty data associated with this +diff -Nurp linux-5.4-aufs/fs/xattr.c linux-5.4-aufs-mod/fs/xattr.c +--- linux-5.4-aufs/fs/xattr.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs-mod/fs/xattr.c 2019-11-28 01:38:48.780894927 +0200 +@@ -296,6 +296,7 @@ vfs_getxattr_alloc(struct dentry *dentry + *xattr_value = value; + return error; + } ++EXPORT_SYMBOL_GPL(vfs_getxattr_alloc); + + ssize_t + __vfs_getxattr(struct dentry *dentry, struct inode *inode, const char *name, +diff -Nurp linux-5.4-aufs/kernel/locking/lockdep.c linux-5.4-aufs-mod/kernel/locking/lockdep.c +--- linux-5.4-aufs/kernel/locking/lockdep.c 2019-11-28 01:25:59.072925617 +0200 ++++ linux-5.4-aufs-mod/kernel/locking/lockdep.c 2019-11-28 01:38:48.780894927 +0200 +@@ -174,6 +174,7 @@ inline struct lock_class *lockdep_hlock_ + */ + return lock_classes + class_idx; + } ++EXPORT_SYMBOL_GPL(lockdep_hlock_class); + #define hlock_class(hlock) lockdep_hlock_class(hlock) + + #ifdef CONFIG_LOCK_STAT +diff -Nurp linux-5.4-aufs/kernel/task_work.c linux-5.4-aufs-mod/kernel/task_work.c +--- linux-5.4-aufs/kernel/task_work.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs-mod/kernel/task_work.c 2019-11-28 01:38:48.786894927 +0200 +@@ -116,3 +116,4 @@ void task_work_run(void) + } while (work); + } + } ++EXPORT_SYMBOL_GPL(task_work_run); +diff -Nurp linux-5.4-aufs/security/device_cgroup.c linux-5.4-aufs-mod/security/device_cgroup.c +--- linux-5.4-aufs/security/device_cgroup.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs-mod/security/device_cgroup.c 2019-11-28 01:38:48.790894927 +0200 +@@ -824,3 +824,4 @@ int __devcgroup_check_permission(short t + + return 0; + } ++EXPORT_SYMBOL_GPL(__devcgroup_check_permission); +diff -Nurp linux-5.4-aufs/security/security.c linux-5.4-aufs-mod/security/security.c +--- linux-5.4-aufs/security/security.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs-mod/security/security.c 2019-11-28 01:38:48.794894926 +0200 +@@ -1036,6 +1036,7 @@ int security_path_rmdir(const struct pat + return 0; + return call_int_hook(path_rmdir, 0, dir, dentry); + } ++EXPORT_SYMBOL_GPL(security_path_rmdir); + + int security_path_unlink(const struct path *dir, struct dentry *dentry) + { +@@ -1052,6 +1053,7 @@ int security_path_symlink(const struct p + return 0; + return call_int_hook(path_symlink, 0, dir, dentry, old_name); + } ++EXPORT_SYMBOL_GPL(security_path_symlink); + + int security_path_link(struct dentry *old_dentry, const struct path *new_dir, + struct dentry *new_dentry) +@@ -1060,6 +1062,7 @@ int security_path_link(struct dentry *ol + return 0; + return call_int_hook(path_link, 0, old_dentry, new_dir, new_dentry); + } ++EXPORT_SYMBOL_GPL(security_path_link); + + int security_path_rename(const struct path *old_dir, struct dentry *old_dentry, + const struct path *new_dir, struct dentry *new_dentry, +@@ -1087,6 +1090,7 @@ int security_path_truncate(const struct + return 0; + return call_int_hook(path_truncate, 0, path); + } ++EXPORT_SYMBOL_GPL(security_path_truncate); + + int security_path_chmod(const struct path *path, umode_t mode) + { +@@ -1094,6 +1098,7 @@ int security_path_chmod(const struct pat + return 0; + return call_int_hook(path_chmod, 0, path, mode); + } ++EXPORT_SYMBOL_GPL(security_path_chmod); + + int security_path_chown(const struct path *path, kuid_t uid, kgid_t gid) + { +@@ -1101,6 +1106,7 @@ int security_path_chown(const struct pat + return 0; + return call_int_hook(path_chown, 0, path, uid, gid); + } ++EXPORT_SYMBOL_GPL(security_path_chown); + + int security_path_chroot(const struct path *path) + { +@@ -1201,6 +1207,7 @@ int security_inode_permission(struct ino + return 0; + return call_int_hook(inode_permission, 0, inode, mask); + } ++EXPORT_SYMBOL_GPL(security_inode_permission); + + int security_inode_setattr(struct dentry *dentry, struct iattr *attr) + { +@@ -1378,6 +1385,7 @@ int security_file_permission(struct file + + return fsnotify_perm(file, mask); + } ++EXPORT_SYMBOL_GPL(security_file_permission); + + int security_file_alloc(struct file *file) + { diff --git a/kernel/kernel/files/patches/mageia/fs-aufs-5.4-version.patch b/kernel/kernel/files/patches/mageia/fs-aufs-5.4-version.patch new file mode 100755 index 00000000..85c71bf3 --- /dev/null +++ b/kernel/kernel/files/patches/mageia/fs-aufs-5.4-version.patch @@ -0,0 +1,12 @@ +diff -Nurp linux-5.3-aufs/include/uapi/linux/aufs_type.h linux-5.3-aufs-ver/include/uapi/linux/aufs_type.h +--- linux-5.3-aufs/include/uapi/linux/aufs_type.h 2019-09-24 16:13:44.012259519 +0300 ++++ linux-5.3-aufs-ver/include/uapi/linux/aufs_type.h 2019-09-24 20:04:21.924707762 +0300 +@@ -27,7 +27,7 @@ + + #include + +-#define AUFS_VERSION "5.x-rcN" ++#define AUFS_VERSION "5.4" + + /* todo? move this to linux-2.6.19/include/magic.h */ + #define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's') diff --git a/kernel/kernel/files/patches/mageia/fs-aufs-5.4.patch b/kernel/kernel/files/patches/mageia/fs-aufs-5.4.patch new file mode 100644 index 00000000..0f717dbf --- /dev/null +++ b/kernel/kernel/files/patches/mageia/fs-aufs-5.4.patch @@ -0,0 +1,37876 @@ + + Documentation/ABI/testing/debugfs-aufs | 55 + Documentation/ABI/testing/sysfs-aufs | 31 + Documentation/filesystems/aufs/README | 399 +++ + Documentation/filesystems/aufs/design/01intro.txt | 158 + + Documentation/filesystems/aufs/design/02struct.txt | 245 ++ + Documentation/filesystems/aufs/design/03atomic_open.txt | 72 + Documentation/filesystems/aufs/design/03lookup.txt | 100 + Documentation/filesystems/aufs/design/04branch.txt | 61 + Documentation/filesystems/aufs/design/05wbr_policy.txt | 51 + Documentation/filesystems/aufs/design/06dirren.dot | 31 + Documentation/filesystems/aufs/design/06dirren.txt | 89 + Documentation/filesystems/aufs/design/06fhsm.txt | 105 + Documentation/filesystems/aufs/design/06mmap.txt | 59 + Documentation/filesystems/aufs/design/06xattr.txt | 81 + Documentation/filesystems/aufs/design/07export.txt | 45 + Documentation/filesystems/aufs/design/08shwh.txt | 39 + Documentation/filesystems/aufs/design/10dynop.txt | 34 + MAINTAINERS | 13 + drivers/block/loop.c | 18 + fs/Kconfig | 1 + fs/Makefile | 1 + fs/aufs/Kconfig | 199 + + fs/aufs/Makefile | 39 + fs/aufs/aufs.h | 49 + fs/aufs/branch.c | 1415 +++++++++++ + fs/aufs/branch.h | 353 ++ + fs/aufs/cpup.c | 1445 +++++++++++ + fs/aufs/cpup.h | 87 + fs/aufs/dbgaufs.c | 513 ++++ + fs/aufs/dbgaufs.h | 40 + fs/aufs/dcsub.c | 212 + + fs/aufs/dcsub.h | 124 + + fs/aufs/debug.c | 428 +++ + fs/aufs/debug.h | 213 + + fs/aufs/dentry.c | 1141 +++++++++ + fs/aufs/dentry.h | 255 ++ + fs/aufs/dinfo.c | 541 ++++ + fs/aufs/dir.c | 750 ++++++ + fs/aufs/dir.h | 121 + fs/aufs/dirren.c | 1303 ++++++++++ + fs/aufs/dirren.h | 127 + + fs/aufs/dynop.c | 354 ++ + fs/aufs/dynop.h | 64 + fs/aufs/export.c | 825 ++++++ + fs/aufs/f_op.c | 806 ++++++ + fs/aufs/fhsm.c | 413 +++ + fs/aufs/file.c | 850 ++++++ + fs/aufs/file.h | 329 ++ + fs/aufs/finfo.c | 136 + + fs/aufs/fstype.h | 388 +++ + fs/aufs/hbl.h | 52 + fs/aufs/hfsnotify.c | 275 ++ + fs/aufs/hfsplus.c | 47 + fs/aufs/hnotify.c | 708 +++++ + fs/aufs/i_op.c | 1492 ++++++++++++ + fs/aufs/i_op_add.c | 923 +++++++ + fs/aufs/i_op_del.c | 500 ++++ + fs/aufs/i_op_ren.c | 1237 ++++++++++ + fs/aufs/iinfo.c | 273 ++ + fs/aufs/inode.c | 516 ++++ + fs/aufs/inode.h | 685 +++++ + fs/aufs/ioctl.c | 207 + + fs/aufs/lcnt.h | 173 + + fs/aufs/loop.c | 135 + + fs/aufs/loop.h | 42 + fs/aufs/magic.mk | 31 + fs/aufs/module.c | 259 ++ + fs/aufs/module.h | 153 + + fs/aufs/mvdown.c | 693 +++++ + fs/aufs/opts.c | 1867 +++++++++++++++ + fs/aufs/opts.h | 212 + + fs/aufs/plink.c | 503 ++++ + fs/aufs/poll.c | 38 + fs/aufs/posix_acl.c | 92 + fs/aufs/procfs.c | 158 + + fs/aufs/rdu.c | 371 +++ + fs/aufs/rwsem.h | 60 + fs/aufs/sbinfo.c | 301 ++ + fs/aufs/super.c | 1034 ++++++++ + fs/aufs/super.h | 576 ++++ + fs/aufs/sysaufs.c | 80 + fs/aufs/sysaufs.h | 89 + fs/aufs/sysfs.c | 338 ++ + fs/aufs/sysrq.c | 147 + + fs/aufs/vdir.c | 883 +++++++ + fs/aufs/vfsub.c | 889 +++++++ + fs/aufs/vfsub.h | 341 ++ + fs/aufs/wbr_policy.c | 817 ++++++ + fs/aufs/whout.c | 1049 ++++++++ + fs/aufs/whout.h | 73 + fs/aufs/wkq.c | 379 +++ + fs/aufs/wkq.h | 76 + fs/aufs/xattr.c | 343 ++ + fs/aufs/xino.c | 1952 ++++++++++++++++ + fs/dcache.c | 2 + fs/fcntl.c | 4 + fs/inode.c | 2 + fs/namespace.c | 6 + fs/proc/base.c | 2 + fs/proc/nommu.c | 5 + fs/proc/task_mmu.c | 7 + fs/proc/task_nommu.c | 5 + fs/read_write.c | 22 + fs/splice.c | 10 + fs/sync.c | 2 + include/linux/fs.h | 10 + include/linux/lockdep.h | 3 + include/linux/mm.h | 22 + include/linux/mm_types.h | 2 + include/linux/mnt_namespace.h | 3 + include/linux/splice.h | 6 + include/uapi/linux/aufs_type.h | 439 +++ + kernel/fork.c | 2 + kernel/locking/lockdep.c | 3 + mm/Makefile | 2 + mm/filemap.c | 2 + mm/mmap.c | 33 + mm/nommu.c | 10 + mm/prfile.c | 86 + 119 files changed, 36936 insertions(+), 31 deletions(-) + +diff -Nurp linux-5.4/Documentation/ABI/testing/debugfs-aufs linux-5.4-aufs/Documentation/ABI/testing/debugfs-aufs +--- linux-5.4/Documentation/ABI/testing/debugfs-aufs 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/ABI/testing/debugfs-aufs 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,55 @@ ++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_/plink ++Date: Apr 2013 ++Contact: J. R. Okajima ++Description: ++ It has three lines and shows the information about the ++ pseudo-link. The first line is a single number ++ representing a number of buckets. The second line is a ++ number of pseudo-links per buckets (separated by a ++ blank). The last line is a single number representing a ++ total number of psedo-links. ++ When the aufs mount option 'noplink' is specified, it ++ will show "1\n0\n0\n". ++ ++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_/xi0, xi1 ... xiN and xiN-N ++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. ++ Due to the file size limit, there may exist multiple ++ xino files per branch. In this case, "-N" is added to ++ the filename and it corresponds to the index of the ++ internal xino array. "-0" is omitted. ++ When the aufs mount option 'noxino' is specified, Those ++ entries won't exist. 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 -Nurp linux-5.4/Documentation/ABI/testing/sysfs-aufs linux-5.4-aufs/Documentation/ABI/testing/sysfs-aufs +--- linux-5.4/Documentation/ABI/testing/sysfs-aufs 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/ABI/testing/sysfs-aufs 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,31 @@ ++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_/brid0, brid1 ... bridN ++Date: July 2013 ++Contact: J. R. Okajima ++Description: ++ It shows the id of a member directory (which is called ++ branch) in aufs. ++ ++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 -Nurp linux-5.4/Documentation/filesystems/aufs/design/01intro.txt linux-5.4-aufs/Documentation/filesystems/aufs/design/01intro.txt +--- linux-5.4/Documentation/filesystems/aufs/design/01intro.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/filesystems/aufs/design/01intro.txt 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,158 @@ ++ ++# Copyright (C) 2005-2019 Junjiro R. Okajima ++ ++Introduction ++---------------------------------------- ++ ++aufs [ei ju: ef es] | /ey-yoo-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. ++4. abbrev. for "African Urban Fashion Show". ++ ++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', etc. 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). ++ ++In linux-3.18, "overlay" filesystem (formerly known as "overlayfs") was ++merged into mainline. This is another implementation of UnionMount as a ++separated filesystem. All the limitations and known problems which ++UnionMount are equally inherited to "overlay" filesystem. ++ ++Unionfs has a longer history. When I started implementing a stackable ++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). ++ ++You may want to read my old paper "Filesystems in LiveCD" ++(http://aufs.sourceforge.net/aufs2/report/sq/sq.pdf). ++ ++ ++Several characters/aspects/persona of aufs ++---------------------------------------------------------------------- ++ ++Aufs has several characters, aspects or persona. ++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 ++keep and maintain the inode numbers. 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 -Nurp linux-5.4/Documentation/filesystems/aufs/design/02struct.txt linux-5.4-aufs/Documentation/filesystems/aufs/design/02struct.txt +--- linux-5.4/Documentation/filesystems/aufs/design/02struct.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/filesystems/aufs/design/02struct.txt 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,245 @@ ++ ++# Copyright (C) 2005-2019 Junjiro R. Okajima ++ ++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 (because /rw/fileA doesn't exist) ++- [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 ++branches 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 ++wbr_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. ++ ++Aufs has a mount option to free the disk blocks for such holes in XINO ++files on tmpfs or ramdisk. But it is not so effective actually. If you ++meet a problem of disk shortage due to XINO files, then you should try ++"tmpfs-ino.patch" (and "vfs-ino.patch" too) in aufs4-standalone.git. ++The patch localizes the assignment inumbers per tmpfs-mount and avoid ++the holes in XINO files. ++ ++Also a writable branch has three kinds of "whiteout bases". All these ++are existed when the branch is joined to aufs, and their names are ++whiteout-ed doubly, so that users will never see their names in aufs ++hierarchy. ++1. a regular file which will be hardlinked 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 essentially necessary. ++ ++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 an internal 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. ++ ++As well as XINO files, aufs has a feature to truncate/refresh 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 ++obsoleted. 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, then the process may receive the unexpected SIGXFSZ or other ++signals. ++ ++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 ++further 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. ++ ++ ++Move-down (aufs3.9 and later) ++---------------------------------------------------------------------- ++"Copy-up" is one of the essential feature in aufs. It copies a file from ++the lower readonly branch to the upper writable branch when a user ++changes something about the file. ++"Move-down" is an opposite action of copy-up. Basically this action is ++ran manually instead of automatically and internally. ++For desgin and implementation, aufs has to consider these issues. ++- whiteout for the file may exist on the lower branch. ++- ancestor directories may not exist on the lower branch. ++- diropq for the ancestor directories may exist on the upper branch. ++- free space on the lower branch will reduce. ++- another access to the file may happen during moving-down, including ++ UDBA (see "Revalidate Dentry and UDBA"). ++- the file should not be hard-linked nor pseudo-linked. they should be ++ handled by auplink utility later. ++ ++Sometimes users want to move-down a file from the upper writable branch ++to the lower readonly or writable branch. For instance, ++- the free space of the upper writable branch is going to run out. ++- create a new intermediate branch between the upper and lower branch. ++- etc. ++ ++For this purpose, use "aumvdown" command in aufs-util.git. +diff -Nurp linux-5.4/Documentation/filesystems/aufs/design/03atomic_open.txt linux-5.4-aufs/Documentation/filesystems/aufs/design/03atomic_open.txt +--- linux-5.4/Documentation/filesystems/aufs/design/03atomic_open.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/filesystems/aufs/design/03atomic_open.txt 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,72 @@ ++ ++# Copyright (C) 2015-2019 Junjiro R. Okajima ++ ++Support for a branch who has its ->atomic_open() ++---------------------------------------------------------------------- ++The filesystems who implement its ->atomic_open() are not majority. For ++example NFSv4 does, and aufs should call NFSv4 ->atomic_open, ++particularly for open(O_CREAT|O_EXCL, 0400) case. Other than ++->atomic_open(), NFSv4 returns an error for this open(2). While I am not ++sure whether all filesystems who have ->atomic_open() behave like this, ++but NFSv4 surely returns the error. ++ ++In order to support ->atomic_open() for aufs, there are a few ++approaches. ++ ++A. Introduce aufs_atomic_open() ++ - calls one of VFS:do_last(), lookup_open() or atomic_open() for ++ branch fs. ++B. Introduce aufs_atomic_open() calling create, open and chmod. this is ++ an aufs user Pip Cet's approach ++ - calls aufs_create(), VFS finish_open() and notify_change(). ++ - pass fake-mode to finish_open(), and then correct the mode by ++ notify_change(). ++C. Extend aufs_open() to call branch fs's ->atomic_open() ++ - no aufs_atomic_open(). ++ - aufs_lookup() registers the TID to an aufs internal object. ++ - aufs_create() does nothing when the matching TID is registered, but ++ registers the mode. ++ - aufs_open() calls branch fs's ->atomic_open() when the matching ++ TID is registered. ++D. Extend aufs_open() to re-try branch fs's ->open() with superuser's ++ credential ++ - no aufs_atomic_open(). ++ - aufs_create() registers the TID to an internal object. this info ++ represents "this process created this file just now." ++ - when aufs gets EACCES from branch fs's ->open(), then confirm the ++ registered TID and re-try open() with superuser's credential. ++ ++Pros and cons for each approach. ++ ++A. ++ - straightforward but highly depends upon VFS internal. ++ - the atomic behavaiour is kept. ++ - some of parameters such as nameidata are hard to reproduce for ++ branch fs. ++ - large overhead. ++B. ++ - easy to implement. ++ - the atomic behavaiour is lost. ++C. ++ - the atomic behavaiour is kept. ++ - dirty and tricky. ++ - VFS checks whether the file is created correctly after calling ++ ->create(), which means this approach doesn't work. ++D. ++ - easy to implement. ++ - the atomic behavaiour is lost. ++ - to open a file with superuser's credential and give it to a user ++ process is a bad idea, since the file object keeps the credential ++ in it. It may affect LSM or something. This approach doesn't work ++ either. ++ ++The approach A is ideal, but it hard to implement. So here is a ++variation of A, which is to be implemented. ++ ++A-1. Introduce aufs_atomic_open() ++ - calls branch fs ->atomic_open() if exists. otherwise calls ++ vfs_create() and finish_open(). ++ - the demerit is that the several checks after branch fs ++ ->atomic_open() are lost. in the ordinary case, the checks are ++ done by VFS:do_last(), lookup_open() and atomic_open(). some can ++ be implemented in aufs, but not all I am afraid. +diff -Nurp linux-5.4/Documentation/filesystems/aufs/design/03lookup.txt linux-5.4-aufs/Documentation/filesystems/aufs/design/03lookup.txt +--- linux-5.4/Documentation/filesystems/aufs/design/03lookup.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/filesystems/aufs/design/03lookup.txt 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,100 @@ ++ ++# Copyright (C) 2005-2019 Junjiro R. Okajima ++ ++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. 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, and ++aufs calls it. ++ ++When a branch is a remote filesystem, aufs basically relies upon 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. ++ ++ ++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" ++- the internal copy-up is activated and "/rw/dirA" is created and its ++ permission bits are set to world readable. ++- then "/au/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 good solution for this case. So aufs ++implements 'dirperm1' and 'nodirperm1' mount options, 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 when the number of ++branch is many. ++ ++ ++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 the revalidation 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 -Nurp linux-5.4/Documentation/filesystems/aufs/design/04branch.txt linux-5.4-aufs/Documentation/filesystems/aufs/design/04branch.txt +--- linux-5.4/Documentation/filesystems/aufs/design/04branch.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/filesystems/aufs/design/04branch.txt 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,61 @@ ++ ++# Copyright (C) 2005-2019 Junjiro R. Okajima ++ ++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 its 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 aufs can do nothing 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 -Nurp linux-5.4/Documentation/filesystems/aufs/design/05wbr_policy.txt linux-5.4-aufs/Documentation/filesystems/aufs/design/05wbr_policy.txt +--- linux-5.4/Documentation/filesystems/aufs/design/05wbr_policy.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/filesystems/aufs/design/05wbr_policy.txt 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,51 @@ ++ ++# Copyright (C) 2005-2019 Junjiro R. Okajima ++ ++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 several policies, round-robin, ++most-free-space, and other policies. For copy-up, top-down-parent, ++bottom-up-parent, bottom-up and others. ++ ++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 -Nurp linux-5.4/Documentation/filesystems/aufs/design/06dirren.dot linux-5.4-aufs/Documentation/filesystems/aufs/design/06dirren.dot +--- linux-5.4/Documentation/filesystems/aufs/design/06dirren.dot 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/filesystems/aufs/design/06dirren.dot 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,31 @@ ++ ++// to view this graph, run dot(1) command in GRAPHVIZ. ++ ++digraph G { ++node [shape=box]; ++whinfo [label="detailed info file\n(lower_brid_root-hinum, h_inum, namelen, old name)"]; ++ ++node [shape=oval]; ++ ++aufs_rename -> whinfo [label="store/remove"]; ++ ++node [shape=oval]; ++inode_list [label="h_inum list in branch\ncache"]; ++ ++node [shape=box]; ++whinode [label="h_inum list file"]; ++ ++node [shape=oval]; ++brmgmt [label="br_add/del/mod/umount"]; ++ ++brmgmt -> inode_list [label="create/remove"]; ++brmgmt -> whinode [label="load/store"]; ++ ++inode_list -> whinode [style=dashed,dir=both]; ++ ++aufs_rename -> inode_list [label="add/del"]; ++ ++aufs_lookup -> inode_list [label="search"]; ++ ++aufs_lookup -> whinfo [label="load/remove"]; ++} +diff -Nurp linux-5.4/Documentation/filesystems/aufs/design/06dirren.txt linux-5.4-aufs/Documentation/filesystems/aufs/design/06dirren.txt +--- linux-5.4/Documentation/filesystems/aufs/design/06dirren.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/filesystems/aufs/design/06dirren.txt 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,89 @@ ++ ++# Copyright (C) 2017-2019 Junjiro R. Okajima ++ ++Special handling for renaming a directory (DIRREN) ++---------------------------------------------------------------------- ++First, let's assume we have a simple usecase. ++ ++- /u = /rw + /ro ++- /rw/dirA exists ++- /ro/dirA and /ro/dirA/file exist too ++- there is no dirB on both branches ++- a user issues rename("dirA", "dirB") ++ ++Now, what should aufs behave against this rename(2)? ++There are a few possible cases. ++ ++A. returns EROFS. ++ since dirA exists on a readonly branch which cannot be renamed. ++B. returns EXDEV. ++ it is possible to copy-up dirA (only the dir itself), but the child ++ entries ("file" in this case) should not be. it must be a bad ++ approach to copy-up recursively. ++C. returns a success. ++ even the branch /ro is readonly, aufs tries renaming it. Obviously it ++ is a violation of aufs' policy. ++D. construct an extra information which indicates that /ro/dirA should ++ be handled as the name of dirB. ++ overlayfs has a similar feature called REDIRECT. ++ ++Until now, aufs implements the case B only which returns EXDEV, and ++expects the userspace application behaves like mv(1) which tries ++issueing rename(2) recursively. ++ ++A new aufs feature called DIRREN is introduced which implements the case ++D. There are several "extra information" added. ++ ++1. detailed info per renamed directory ++ path: /rw/dirB/$AUFS_WH_DR_INFO_PFX. ++2. the inode-number list of directories on a branch ++ path: /rw/dirB/$AUFS_WH_DR_BRHINO ++ ++The filename of "detailed info per directory" represents the lower ++branch, and its format is ++- a type of the branch id ++ one of these. ++ + uuid (not implemented yet) ++ + fsid ++ + dev ++- the inode-number of the branch root dir ++ ++And it contains these info in a single regular file. ++- magic number ++- branch's inode-number of the logically renamed dir ++- the name of the before-renamed dir ++ ++The "detailed info per directory" file is created in aufs rename(2), and ++loaded in any lookup. ++The info is considered in lookup for the matching case only. Here ++"matching" means that the root of branch (in the info filename) is same ++to the current looking-up branch. After looking-up the before-renamed ++name, the inode-number is compared. And the matched dentry is used. ++ ++The "inode-number list of directories" is a regular file which contains ++simply the inode-numbers on the branch. The file is created or updated ++in removing the branch, and loaded in adding the branch. Its lifetime is ++equal to the branch. ++The list is refered in lookup, and when the current target inode is ++found in the list, the aufs tries loading the "detailed info per ++directory" and get the changed and valid name of the dir. ++ ++Theoretically these "extra informaiton" may be able to be put into XATTR ++in the dir inode. But aufs doesn't choose this way because ++1. XATTR may not be supported by the branch (or its configuration) ++2. XATTR may have its size limit. ++3. XATTR may be less easy to convert than a regular file, when the ++ format of the info is changed in the future. ++At the same time, I agree that the regular file approach is much slower ++than XATTR approach. So, in the future, aufs may take the XATTR or other ++better approach. ++ ++This DIRREN feature is enabled by aufs configuration, and is activated ++by a new mount option. ++ ++For the more complicated case, there is a work with UDBA option, which ++is to dected the direct access to the branches (by-passing aufs) and to ++maintain the cashes in aufs. Since a single cached aufs dentry may ++contains two names, before- and after-rename, the name comparision in ++UDBA handler may not work correctly. In this case, the behaviour will be ++equivalen to udba=reval case. +diff -Nurp linux-5.4/Documentation/filesystems/aufs/design/06fhsm.txt linux-5.4-aufs/Documentation/filesystems/aufs/design/06fhsm.txt +--- linux-5.4/Documentation/filesystems/aufs/design/06fhsm.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/filesystems/aufs/design/06fhsm.txt 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,105 @@ ++ ++# Copyright (C) 2011-2019 Junjiro R. Okajima ++ ++File-based Hierarchical Storage Management (FHSM) ++---------------------------------------------------------------------- ++Hierarchical Storage Management (or HSM) is a well-known feature in the ++storage world. Aufs provides this feature as file-based with multiple ++writable branches, based upon the principle of "Colder, the Lower". ++Here the word "colder" means that the less used files, and "lower" means ++that the position in the order of the stacked branches vertically. ++These multiple writable branches are prioritized, ie. the topmost one ++should be the fastest drive and be used heavily. ++ ++o Characters in aufs FHSM story ++- aufs itself and a new branch attribute. ++- a new ioctl interface to move-down and to establish a connection with ++ the daemon ("move-down" is a converse of "copy-up"). ++- userspace tool and daemon. ++ ++The userspace daemon establishes a connection with aufs and waits for ++the notification. The notified information is very similar to struct ++statfs containing the number of consumed blocks and inodes. ++When the consumed blocks/inodes of a branch exceeds the user-specified ++upper watermark, the daemon activates its move-down process until the ++consumed blocks/inodes reaches the user-specified lower watermark. ++ ++The actual move-down is done by aufs based upon the request from ++user-space since we need to maintain the inode number and the internal ++pointer arrays in aufs. ++ ++Currently aufs FHSM handles the regular files only. Additionally they ++must not be hard-linked nor pseudo-linked. ++ ++ ++o Cowork of aufs and the user-space daemon ++ During the userspace daemon established the connection, aufs sends a ++ small notification to it whenever aufs writes something into the ++ writable branch. But it may cost high since aufs issues statfs(2) ++ internally. So user can specify a new option to cache the ++ info. Actually the notification is controlled by these factors. ++ + the specified cache time. ++ + classified as "force" by aufs internally. ++ Until the specified time expires, aufs doesn't send the info ++ except the forced cases. When aufs decide forcing, the info is always ++ notified to userspace. ++ For example, the number of free inodes is generally large enough and ++ the shortage of it happens rarely. So aufs doesn't force the ++ notification when creating a new file, directory and others. This is ++ the typical case which aufs doesn't force. ++ When aufs writes the actual filedata and the files consumes any of new ++ blocks, the aufs forces notifying. ++ ++ ++o Interfaces in aufs ++- New branch attribute. ++ + fhsm ++ Specifies that the branch is managed by FHSM feature. In other word, ++ participant in the FHSM. ++ When nofhsm is set to the branch, it will not be the source/target ++ branch of the move-down operation. This attribute is set ++ independently from coo and moo attributes, and if you want full ++ FHSM, you should specify them as well. ++- New mount option. ++ + fhsm_sec ++ Specifies a second to suppress many less important info to be ++ notified. ++- New ioctl. ++ + AUFS_CTL_FHSM_FD ++ create a new file descriptor which userspace can read the notification ++ (a subset of struct statfs) from aufs. ++- Module parameter 'brs' ++ It has to be set to 1. Otherwise the new mount option 'fhsm' will not ++ be set. ++- mount helpers /sbin/mount.aufs and /sbin/umount.aufs ++ When there are two or more branches with fhsm attributes, ++ /sbin/mount.aufs invokes the user-space daemon and /sbin/umount.aufs ++ terminates it. As a result of remounting and branch-manipulation, the ++ number of branches with fhsm attribute can be one. In this case, ++ /sbin/mount.aufs will terminate the user-space daemon. ++ ++ ++Finally the operation is done as these steps in kernel-space. ++- make sure that, ++ + no one else is using the file. ++ + the file is not hard-linked. ++ + the file is not pseudo-linked. ++ + the file is a regular file. ++ + the parent dir is not opaqued. ++- find the target writable branch. ++- make sure the file is not whiteout-ed by the upper (than the target) ++ branch. ++- make the parent dir on the target branch. ++- mutex lock the inode on the branch. ++- unlink the whiteout on the target branch (if exists). ++- lookup and create the whiteout-ed temporary name on the target branch. ++- copy the file as the whiteout-ed temporary name on the target branch. ++- rename the whiteout-ed temporary name to the original name. ++- unlink the file on the source branch. ++- maintain the internal pointer array and the external inode number ++ table (XINO). ++- maintain the timestamps and other attributes of the parent dir and the ++ file. ++ ++And of course, in every step, an error may happen. So the operation ++should restore the original file state after an error happens. +diff -Nurp linux-5.4/Documentation/filesystems/aufs/design/06mmap.txt linux-5.4-aufs/Documentation/filesystems/aufs/design/06mmap.txt +--- linux-5.4/Documentation/filesystems/aufs/design/06mmap.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/filesystems/aufs/design/06mmap.txt 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,59 @@ ++ ++# Copyright (C) 2005-2019 Junjiro R. Okajima ++ ++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 mmapped 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 fakes 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. ++ ++There may be one more another approach which is ++- bind-mount the branch-root onto the aufs-root internally ++- grab the new vfsmount (ie. struct mount) ++- lazy-umount the branch-root internally ++- in open(2) the aufs-file, open the branch-file with the hidden ++ vfsmount (instead of the original branch's vfsmount) ++- ideally this "bind-mount and lazy-umount" should be done atomically, ++ but it may be possible from userspace by the mount helper. ++ ++Adding the internal hidden vfsmount and using it in opening a file, the ++file path under /proc will be printed correctly. This approach looks ++smarter, but is not possible I am afraid. ++- aufs-root may be bind-mount later. when it happens, another hidden ++ vfsmount will be required. ++- it is hard to get the chance to bind-mount and lazy-umount ++ + in kernel-space, FS can have vfsmount in open(2) via ++ file->f_path, and aufs can know its vfsmount. But several locks are ++ already acquired, and if aufs tries to bind-mount and lazy-umount ++ here, then it may cause a deadlock. ++ + in user-space, bind-mount doesn't invoke the mount helper. ++- since /proc shows dev and ino, aufs has to give vma these info. it ++ means a new member vm_prinode will be necessary. this is essentially ++ equivalent to vm_prfile described above. ++ ++I have to give up this "looks-smater" approach. +diff -Nurp linux-5.4/Documentation/filesystems/aufs/design/06xattr.txt linux-5.4-aufs/Documentation/filesystems/aufs/design/06xattr.txt +--- linux-5.4/Documentation/filesystems/aufs/design/06xattr.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/filesystems/aufs/design/06xattr.txt 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,81 @@ ++ ++# Copyright (C) 2014-2019 Junjiro R. Okajima ++ ++Listing XATTR/EA and getting the value ++---------------------------------------------------------------------- ++For the inode standard attributes (owner, group, timestamps, etc.), aufs ++shows the values from the topmost existing file. This behaviour is good ++for the non-dir entries since the bahaviour exactly matches the shown ++information. But for the directories, aufs considers all the same named ++entries on the lower branches. Which means, if one of the lower entry ++rejects readdir call, then aufs returns an error even if the topmost ++entry allows it. This behaviour is necessary to respect the branch fs's ++security, but can make users confused since the user-visible standard ++attributes don't match the behaviour. ++To address this issue, aufs has a mount option called dirperm1 which ++checks the permission for the topmost entry only, and ignores the lower ++entry's permission. ++ ++A similar issue can happen around XATTR. ++getxattr(2) and listxattr(2) families behave as if dirperm1 option is ++always set. Otherwise these very unpleasant situation would happen. ++- listxattr(2) may return the duplicated entries. ++- users may not be able to remove or reset the XATTR forever, ++ ++ ++XATTR/EA support in the internal (copy,move)-(up,down) ++---------------------------------------------------------------------- ++Generally the extended attributes of inode are categorized as these. ++- "security" for LSM and capability. ++- "system" for posix ACL, 'acl' mount option is required for the branch ++ fs generally. ++- "trusted" for userspace, CAP_SYS_ADMIN is required. ++- "user" for userspace, 'user_xattr' mount option is required for the ++ branch fs generally. ++ ++Moreover there are some other categories. Aufs handles these rather ++unpopular categories as the ordinary ones, ie. there is no special ++condition nor exception. ++ ++In copy-up, the support for XATTR on the dst branch may differ from the ++src branch. In this case, the copy-up operation will get an error and ++the original user operation which triggered the copy-up will fail. It ++can happen that even all copy-up will fail. ++When both of src and dst branches support XATTR and if an error occurs ++during copying XATTR, then the copy-up should fail obviously. That is a ++good reason and aufs should return an error to userspace. But when only ++the src branch support that XATTR, aufs should not return an error. ++For example, the src branch supports ACL but the dst branch doesn't ++because the dst branch may natively un-support it or temporary ++un-support it due to "noacl" mount option. Of course, the dst branch fs ++may NOT return an error even if the XATTR is not supported. It is ++totally up to the branch fs. ++ ++Anyway when the aufs internal copy-up gets an error from the dst branch ++fs, then aufs tries removing the just copied entry and returns the error ++to the userspace. The worst case of this situation will be all copy-up ++will fail. ++ ++For the copy-up operation, there two basic approaches. ++- copy the specified XATTR only (by category above), and return the ++ error unconditionally if it happens. ++- copy all XATTR, and ignore the error on the specified category only. ++ ++In order to support XATTR and to implement the correct behaviour, aufs ++chooses the latter approach and introduces some new branch attributes, ++"icexsec", "icexsys", "icextr", "icexusr", and "icexoth". ++They correspond to the XATTR namespaces (see above). Additionally, to be ++convenient, "icex" is also provided which means all "icex*" attributes ++are set (here the word "icex" stands for "ignore copy-error on XATTR"). ++ ++The meaning of these attributes is to ignore the error from setting ++XATTR on that branch. ++Note that aufs tries copying all XATTR unconditionally, and ignores the ++error from the dst branch according to the specified attributes. ++ ++Some XATTR may have its default value. The default value may come from ++the parent dir or the environment. If the default value is set at the ++file creating-time, it will be overwritten by copy-up. ++Some contradiction may happen I am afraid. ++Do we need another attribute to stop copying XATTR? I am unsure. For ++now, aufs implements the branch attributes to ignore the error. +diff -Nurp linux-5.4/Documentation/filesystems/aufs/design/07export.txt linux-5.4-aufs/Documentation/filesystems/aufs/design/07export.txt +--- linux-5.4/Documentation/filesystems/aufs/design/07export.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/filesystems/aufs/design/07export.txt 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,45 @@ ++ ++# Copyright (C) 2005-2019 Junjiro R. Okajima ++ ++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 in cache, get the parent inode number from ++ the handle and search it in cache. and then open the found 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 -Nurp linux-5.4/Documentation/filesystems/aufs/design/08shwh.txt linux-5.4-aufs/Documentation/filesystems/aufs/design/08shwh.txt +--- linux-5.4/Documentation/filesystems/aufs/design/08shwh.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/filesystems/aufs/design/08shwh.txt 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,39 @@ ++ ++# Copyright (C) 2005-2019 Junjiro R. Okajima ++ ++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 -Nurp linux-5.4/Documentation/filesystems/aufs/design/10dynop.txt linux-5.4-aufs/Documentation/filesystems/aufs/design/10dynop.txt +--- linux-5.4/Documentation/filesystems/aufs/design/10dynop.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/filesystems/aufs/design/10dynop.txt 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,34 @@ ++ ++# Copyright (C) 2010-2019 Junjiro R. Okajima ++ ++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 importantly ++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 behaviour of VFS, ++aufs defines these operations dynamically. For instance, aufs defines ++dummy direct_IO function for struct address_space_operations, but it may ++not be set to the address_space_operations actually. When the branch FS ++doesn't have it, aufs doesn't set it to its address_space_operations ++while the function definition itself is still alive. So the behaviour ++itself will not change, and it will return an error when direct_IO is ++not set. ++ ++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), Direct I/O and ++XIP (DAX) mainly. ++Currently this approach is applied to address_space_operations for ++regular files only. +diff -Nurp linux-5.4/Documentation/filesystems/aufs/README linux-5.4-aufs/Documentation/filesystems/aufs/README +--- linux-5.4/Documentation/filesystems/aufs/README 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/filesystems/aufs/README 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,399 @@ ++ ++Aufs5 -- advanced multi layered unification filesystem version 5.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. Adding many original ideas, approaches, ++improvements and implementations, it became totally different from ++Unionfs while keeping the basic features. ++Later, Unionfs Version 2.x series began taking some of the same ++approaches to aufs1's. ++Unionfs was being developed by Professor Erez Zadok at Stony Brook ++University and his team. ++ ++Aufs5 supports linux-v5.0 and later, If you want older kernel version ++support, ++- for linux-v4.x series, try aufs4-linux.git or aufs4-standalone.git ++- for linux-v3.x series, try aufs3-linux.git or aufs3-standalone.git ++- for linux-v2.6.16 and later, try aufs2-2.6.git, aufs2-standalone.git ++ or 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. ++ ++ ++PS. Al Viro seems have a plan to merge aufs as well as overlayfs and ++ UnionMount, and he pointed out an issue around a directory mutex ++ lock and aufs addressed it. But it is still unsure whether aufs will ++ be merged (or any other union solution). ++ ++ ++ ++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 aufs, such as: ++- test only the highest one for the directory permission (dirperm1) ++- copyup on open (coo=) ++- 'move' policy for copy-up between two writable branches, after ++ checking free space. ++- xattr, acl ++- 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 aufs5. ++See design/08plan.txt in detail. ++- nested mount, i.e. aufs as readonly no-whiteout branch of another aufs ++ (robr) ++- statistics of aufs thread (/sys/fs/aufs/stat) ++ ++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 ++- light version, without branch manipulation. (unnecessary?) ++- copyup in userspace ++- inotify in userspace ++- readv/writev ++ ++ ++2. Download ++---------------------------------------- ++There are three GIT trees for aufs5, aufs5-linux.git, ++aufs5-standalone.git, and aufs-util.git. Note that there is no "5" in ++"aufs-util.git." ++While the aufs-util is always necessary, you need either of aufs5-linux ++or aufs5-standalone. ++ ++The aufs5-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 aufs5 as an external kernel module. ++Several extra patches are not included in this tree. Only ++aufs5-standalone tree contains them. They are described in the later ++section "Configuration and Compilation." ++ ++On the other hand, the aufs5-standalone tree has only aufs source files ++and necessary patches, and you can select CONFIG_AUFS_FS=m. ++But you need to apply all aufs patches manually. ++ ++You will find GIT branches whose name is in form of "aufs5.x" where "x" ++represents the linux kernel version, "linux-5.x". For instance, ++"aufs5.0" is for linux-5.0. For latest "linux-5.x-rcN", use ++"aufs5.x-rcN" branch. ++ ++o aufs5-linux tree ++$ git clone --reference /your/linux/git/tree \ ++ git://github.com/sfjro/aufs5-linux.git aufs5-linux.git ++- if you don't have linux GIT tree, then remove "--reference ..." ++$ cd aufs5-linux.git ++$ git checkout origin/aufs5.0 ++ ++Or You may want to directly git-pull aufs into your linux GIT tree, and ++leave the patch-work to GIT. ++$ cd /your/linux/git/tree ++$ git remote add aufs5 git://github.com/sfjro/aufs5-linux.git ++$ git fetch aufs5 ++$ git checkout -b my5.0 v5.0 ++$ (add your local change...) ++$ git pull aufs5 aufs5.0 ++- now you have v5.0 + your_changes + aufs5.0 in you my5.0 branch. ++- you may need to solve some conflicts between your_changes and ++ aufs5.0. in this case, git-rerere is recommended so that you can ++ solve the similar conflicts automatically when you upgrade to 5.1 or ++ later in the future. ++ ++o aufs5-standalone tree ++$ git clone git://github.com/sfjro/aufs5-standalone.git aufs5-standalone.git ++$ cd aufs5-standalone.git ++$ git checkout origin/aufs5.0 ++ ++o aufs-util tree ++$ git clone git://git.code.sf.net/p/aufs/aufs-util aufs-util.git ++- note that the public aufs-util.git is on SourceForge instead of ++ GitHUB. ++$ cd aufs-util.git ++$ git checkout origin/aufs5.0 ++ ++Note: The 5.x-rcN branch is to be used with `rc' kernel versions ONLY. ++The minor version number, 'x' in '5.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-5.10" and the "aufs5.10" branch ++does not exist in aufs-util repository, then "aufs5.9", "aufs5.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 aufs5-linux tree, ++- enable CONFIG_AUFS_FS. ++- set other aufs configurations if necessary. ++ ++For aufs5-standalone tree, ++There are several ways to build. ++ ++1. ++- apply ./aufs5-kbuild.patch to your kernel source files. ++- apply ./aufs5-base.patch too. ++- apply ./aufs5-mmap.patch too. ++- apply ./aufs5-standalone.patch too, if you have a plan to set ++ CONFIG_AUFS_FS=m. otherwise you don't need ./aufs5-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_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 ./aufs5-base.patch to your kernel source files. ++- apply ./aufs5-mmap.patch too. ++- apply ./aufs5-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 aufs5-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. ++ ++There several other patches in aufs5-standalone.git. They are all ++optional. When you meet some problems, they will help you. ++- aufs5-loopback.patch ++ Supports a nested loopback mount in a branch-fs. This patch is ++ unnecessary until aufs produces a message like "you may want to try ++ another patch for loopback file". ++- proc_mounts.patch ++ When there are many mountpoints and many mount(2)/umount(2) are ++ running, then /proc/mounts may not show the all mountpoints. This ++ patch makes /proc/mounts always show the full mountpoints list. ++ If you don't want to apply this patch and meet such problem, then you ++ need to increase the value of 'ProcMounts_Times' make-variable in ++ aufs-util.git as a second best solution. ++- vfs-ino.patch ++ Modifies a system global kernel internal function get_next_ino() in ++ order to stop assigning 0 for an inode-number. Not directly related to ++ aufs, but recommended generally. ++- tmpfs-idr.patch ++ Keeps the tmpfs inode number as the lowest value. Effective to reduce ++ the size of aufs XINO files for tmpfs branch. Also it prevents the ++ duplication of inode number, which is important for backup tools and ++ other utilities. When you find aufs XINO files for tmpfs branch ++ growing too much, try this patch. ++- lockdep-debug.patch ++ Because aufs is not only an ordinary filesystem (callee of VFS), but ++ also a caller of VFS functions for branch filesystems, subclassing of ++ the internal locks for LOCKDEP is necessary. LOCKDEP is a debugging ++ feature of linux kernel. If you enable CONFIG_LOCKDEP, then you will ++ need to apply this debug patch to expand several constant values. ++ If don't know what LOCKDEP is, then you don't have apply this patch. ++ ++ ++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). ++Era Scarecrow made a donation (2013/4). ++Bor Ratajc made a donation (2013/4). ++Alessandro Gorreta made a donation (2013/4). ++POIRETTE Marc made a donation (2013/4). ++Alessandro Gorreta made a donation (2013/4). ++lauri kasvandik made a donation (2013/5). ++"pemasu from Finland" made a donation (2013/7). ++The Parted Magic Project made a donation (2013/9 and 11). ++Pavel Barta made a donation (2013/10). ++Nikolay Pertsev made a donation (2014/5). ++James B made a donation (2014/7 and 2015/7). ++Stefano Di Biase made a donation (2014/8). ++Daniel Epellei made a donation (2015/1). ++OmegaPhil made a donation (2016/1, 2018/4). ++Tomasz Szewczyk made a donation (2016/4). ++James Burry made a donation (2016/12). ++Carsten Rose made a donation (2018/9). ++Porteus Kiosk made a donation (2018/10). ++ ++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 -Nurp linux-5.4/drivers/block/loop.c linux-5.4-aufs/drivers/block/loop.c +--- linux-5.4/drivers/block/loop.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/drivers/block/loop.c 2019-11-28 01:25:59.062925618 +0200 +@@ -738,6 +738,24 @@ out_err: + return error; + } + ++/* ++ * for AUFS ++ * no get/put for file. ++ */ ++struct file *loop_backing_file(struct super_block *sb) ++{ ++ struct file *ret; ++ struct loop_device *l; ++ ++ ret = NULL; ++ if (MAJOR(sb->s_dev) == LOOP_MAJOR) { ++ l = sb->s_bdev->bd_disk->private_data; ++ ret = l->lo_backing_file; ++ } ++ return ret; ++} ++EXPORT_SYMBOL_GPL(loop_backing_file); ++ + /* loop sysfs attributes */ + + static ssize_t loop_attr_show(struct device *dev, char *page, +diff -Nurp linux-5.4/fs/aufs/aufs.h linux-5.4-aufs/fs/aufs/aufs.h +--- linux-5.4/fs/aufs/aufs.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/aufs.h 2019-11-28 01:25:59.062925618 +0200 +@@ -0,0 +1,49 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * 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 "dirren.h" ++#include "dynop.h" ++#include "file.h" ++#include "fstype.h" ++#include "hbl.h" ++#include "inode.h" ++#include "lcnt.h" ++#include "loop.h" ++#include "module.h" ++#include "opts.h" ++#include "rwsem.h" ++#include "super.h" ++#include "sysaufs.h" ++#include "vfsub.h" ++#include "whout.h" ++#include "wkq.h" ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_H__ */ +diff -Nurp linux-5.4/fs/aufs/branch.c linux-5.4-aufs/fs/aufs/branch.c +--- linux-5.4/fs/aufs/branch.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/branch.c 2019-11-28 01:25:59.062925618 +0200 +@@ -0,0 +1,1415 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * 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); ++ /* always, regardless the mount option */ ++ au_dr_hino_free(&br->br_dirren); ++ au_xino_put(br); ++ ++ AuLCntZero(au_lcnt_read(&br->br_nfiles, /*do_rev*/0)); ++ au_lcnt_fin(&br->br_nfiles, /*do_sync*/0); ++ AuLCntZero(au_lcnt_read(&br->br_count, /*do_rev*/0)); ++ au_lcnt_fin(&br->br_count, /*do_sync*/0); ++ ++ 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); ++ } ++ ++ if (br->br_fhsm) { ++ au_br_fhsm_fin(br->br_fhsm); ++ au_kfree_try_rcu(br->br_fhsm); ++ } ++ ++ 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 */ ++ /* synchronize_rcu(); */ /* why? */ ++ lockdep_off(); ++ path_put(&br->br_path); ++ lockdep_on(); ++ au_kfree_rcu(wbr); ++ au_lcnt_wait_for_fin(&br->br_nfiles); ++ au_lcnt_wait_for_fin(&br->br_count); ++ /* I don't know why, but percpu_refcount requires this */ ++ /* synchronize_rcu(); */ ++ au_kfree_rcu(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_bbot + 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, bbot; ++ ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; 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; ++ struct inode *inode; ++ int err; ++ ++ err = -ENOMEM; ++ add_branch = kzalloc(sizeof(*add_branch), GFP_NOFS); ++ if (unlikely(!add_branch)) ++ goto out; ++ add_branch->br_xino = au_xino_alloc(/*nfile*/1); ++ if (unlikely(!add_branch->br_xino)) ++ goto out_br; ++ err = au_hnotify_init_br(add_branch, perm); ++ if (unlikely(err)) ++ goto out_xino; ++ ++ if (au_br_writable(perm)) { ++ /* may be freed separately at changing the branch permission */ ++ add_branch->br_wbr = kzalloc(sizeof(*add_branch->br_wbr), ++ GFP_NOFS); ++ if (unlikely(!add_branch->br_wbr)) ++ goto out_hnotify; ++ } ++ ++ if (au_br_fhsm(perm)) { ++ err = au_fhsm_br_alloc(add_branch); ++ if (unlikely(err)) ++ goto out_wbr; ++ } ++ ++ root = sb->s_root; ++ err = au_sbr_realloc(au_sbi(sb), new_nbranch, /*may_shrink*/0); ++ if (!err) ++ err = au_di_realloc(au_di(root), new_nbranch, /*may_shrink*/0); ++ if (!err) { ++ inode = d_inode(root); ++ err = au_hinode_realloc(au_ii(inode), new_nbranch, ++ /*may_shrink*/0); ++ } ++ if (!err) ++ return add_branch; /* success */ ++ ++out_wbr: ++ au_kfree_rcu(add_branch->br_wbr); ++out_hnotify: ++ au_hnotify_fin_br(add_branch); ++out_xino: ++ au_xino_put(add_branch); ++out_br: ++ au_kfree_rcu(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 bbot, bindex; ++ struct dentry *root, *h_dentry; ++ struct inode *inode, *h_inode; ++ ++ root = sb->s_root; ++ bbot = au_sbbot(sb); ++ if (unlikely(bbot >= 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 <= bbot)) { ++ pr_err("number of branches exceeded %s\n", add->pathname); ++ goto out; ++ } ++ ++ err = -EDOM; ++ if (unlikely(add->bindex < 0 || bbot + 1 < add->bindex)) { ++ pr_err("bad index %d\n", add->bindex); ++ goto out; ++ } ++ ++ inode = d_inode(add->path.dentry); ++ 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; ++ } ++ ++ if (unlikely(inode->i_sb->s_stack_depth)) { ++ pr_err("already stacked, %s (%s)\n", ++ add->pathname, au_sbtype(inode->i_sb)); ++ goto out; ++ } ++ ++ err = test_br(d_inode(add->path.dentry), add->perm, add->pathname); ++ if (unlikely(err)) ++ goto out; ++ ++ if (bbot < 0) ++ return 0; /* success */ ++ ++ err = -EINVAL; ++ for (bindex = 0; bindex <= bbot; 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_dentry = au_h_dptr(root, 0); ++ h_inode = d_inode(h_dentry); ++ 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) ++{ ++ int err, old_perm; ++ aufs_bindex_t bindex; ++ struct inode *h_inode; ++ struct au_wbr *wbr; ++ struct au_hinode *hdir; ++ struct dentry *h_dentry; ++ ++ err = vfsub_mnt_want_write(au_br_mnt(br)); ++ if (unlikely(err)) ++ goto out; ++ ++ wbr = br->br_wbr; ++ old_perm = br->br_perm; ++ br->br_perm = new_perm; ++ hdir = NULL; ++ h_inode = NULL; ++ bindex = au_br_index(sb, br->br_id); ++ if (0 <= bindex) { ++ hdir = au_hi(d_inode(sb->s_root), bindex); ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ } else { ++ h_dentry = au_br_dentry(br); ++ h_inode = d_inode(h_dentry); ++ inode_lock_nested(h_inode, AuLsc_I_PARENT); ++ } ++ if (!wbr) ++ err = au_wh_init(br, sb); ++ else { ++ wbr_wh_write_lock(wbr); ++ err = au_wh_init(br, sb); ++ wbr_wh_write_unlock(wbr); ++ } ++ if (hdir) ++ au_hn_inode_unlock(hdir); ++ else ++ inode_unlock(h_inode); ++ vfsub_mnt_drop_write(au_br_mnt(br)); ++ br->br_perm = old_perm; ++ ++ if (!err && wbr && !au_br_writable(new_perm)) { ++ au_kfree_rcu(wbr); ++ br->br_wbr = NULL; ++ } ++ ++out: ++ return err; ++} ++ ++static int au_wbr_init(struct au_branch *br, struct super_block *sb, ++ int perm) ++{ ++ int err; ++ struct kstatfs kst; ++ struct au_wbr *wbr; ++ ++ wbr = br->br_wbr; ++ au_rw_init(&wbr->wbr_wh_rwsem); ++ atomic_set(&wbr->wbr_wh_running, 0); ++ ++ /* ++ * a limit for rmdir/rename a dir ++ * cf. AUFS_MAX_NAMELEN in include/uapi/linux/aufs_type.h ++ */ ++ err = vfs_statfs(&br->br_path, &kst); ++ if (unlikely(err)) ++ goto out; ++ err = -EINVAL; ++ if (kst.f_namelen >= NAME_MAX) ++ err = au_br_init_wh(sb, br, perm); ++ else ++ pr_err("%pd(%s), unsupported namelen %ld\n", ++ au_br_dentry(br), ++ au_sbtype(au_br_dentry(br)->d_sb), kst.f_namelen); ++ ++out: ++ return err; ++} ++ ++/* initialize a new branch */ ++static int au_br_init(struct au_branch *br, struct super_block *sb, ++ struct au_opt_add *add) ++{ ++ int err; ++ struct au_branch *brbase; ++ struct file *xf; ++ struct inode *h_inode; ++ ++ err = 0; ++ br->br_perm = add->perm; ++ br->br_path = add->path; /* set first, path_get() later */ ++ spin_lock_init(&br->br_dykey_lock); ++ au_lcnt_init(&br->br_nfiles, /*release*/NULL); ++ au_lcnt_init(&br->br_count, /*release*/NULL); ++ br->br_id = au_new_br_id(sb); ++ AuDebugOn(br->br_id < 0); ++ ++ /* always, regardless the given option */ ++ err = au_dr_br_init(sb, br, &add->path); ++ if (unlikely(err)) ++ goto out_err; ++ ++ if (au_br_writable(add->perm)) { ++ err = au_wbr_init(br, sb, add->perm); ++ if (unlikely(err)) ++ goto out_err; ++ } ++ ++ if (au_opt_test(au_mntflags(sb), XINO)) { ++ brbase = au_sbr(sb, 0); ++ xf = au_xino_file(brbase->br_xino, /*idx*/-1); ++ AuDebugOn(!xf); ++ h_inode = d_inode(add->path.dentry); ++ err = au_xino_init_br(sb, br, h_inode->i_ino, &xf->f_path); ++ if (unlikely(err)) { ++ AuDebugOn(au_xino_file(br->br_xino, /*idx*/-1)); ++ goto out_err; ++ } ++ } ++ ++ sysaufs_br_init(br); ++ path_get(&br->br_path); ++ goto out; /* success */ ++ ++out_err: ++ memset(&br->br_path, 0, sizeof(br->br_path)); ++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 bbot, ++ 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_bbot++; ++ if (unlikely(bbot < 0)) ++ sbinfo->si_bbot = 0; ++} ++ ++static void au_br_do_add_hdp(struct au_dinfo *dinfo, aufs_bindex_t bindex, ++ aufs_bindex_t bbot, aufs_bindex_t amount) ++{ ++ struct au_hdentry *hdp; ++ ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ hdp = au_hdentry(dinfo, bindex); ++ memmove(hdp + 1, hdp, sizeof(*hdp) * amount); ++ au_h_dentry_init(hdp); ++ dinfo->di_bbot++; ++ if (unlikely(bbot < 0)) ++ dinfo->di_btop = 0; ++} ++ ++static void au_br_do_add_hip(struct au_iinfo *iinfo, aufs_bindex_t bindex, ++ aufs_bindex_t bbot, aufs_bindex_t amount) ++{ ++ struct au_hinode *hip; ++ ++ AuRwMustWriteLock(&iinfo->ii_rwsem); ++ ++ hip = au_hinode(iinfo, bindex); ++ memmove(hip + 1, hip, sizeof(*hip) * amount); ++ au_hinode_init(hip); ++ iinfo->ii_bbot++; ++ if (unlikely(bbot < 0)) ++ iinfo->ii_btop = 0; ++} ++ ++static void au_br_do_add(struct super_block *sb, struct au_branch *br, ++ aufs_bindex_t bindex) ++{ ++ struct dentry *root, *h_dentry; ++ struct inode *root_inode, *h_inode; ++ aufs_bindex_t bbot, amount; ++ ++ root = sb->s_root; ++ root_inode = d_inode(root); ++ bbot = au_sbbot(sb); ++ amount = bbot + 1 - bindex; ++ h_dentry = au_br_dentry(br); ++ au_sbilist_lock(); ++ au_br_do_add_brp(au_sbi(sb), bindex, br, bbot, amount); ++ au_br_do_add_hdp(au_di(root), bindex, bbot, amount); ++ au_br_do_add_hip(au_ii(root_inode), bindex, bbot, amount); ++ au_set_h_dptr(root, bindex, dget(h_dentry)); ++ h_inode = d_inode(h_dentry); ++ au_set_h_iptr(root_inode, bindex, au_igrab(h_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 bbot, add_bindex; ++ struct dentry *root, *h_dentry; ++ struct inode *root_inode; ++ struct au_branch *add_branch; ++ ++ root = sb->s_root; ++ root_inode = d_inode(root); ++ IMustLock(root_inode); ++ IiMustWriteLock(root_inode); ++ err = test_add(sb, add, remount); ++ if (unlikely(err < 0)) ++ goto out; ++ if (err) { ++ err = 0; ++ goto out; /* success */ ++ } ++ ++ bbot = au_sbbot(sb); ++ add_branch = au_br_alloc(sb, bbot + 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; ++ sysaufs_brs_del(sb, add_bindex); /* remove successors */ ++ au_br_do_add(sb, add_branch, add_bindex); ++ sysaufs_brs_add(sb, add_bindex); /* append successors */ ++ dbgaufs_brs_add(sb, add_bindex, /*topdown*/0); /* rename successors */ ++ ++ h_dentry = add->path.dentry; ++ 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, d_inode(h_dentry)); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static unsigned long long au_farray_cb(struct super_block *sb, void *a, ++ unsigned long long max __maybe_unused, ++ void *arg) ++{ ++ unsigned long long n; ++ struct file **p, *f; ++ struct hlist_bl_head *files; ++ struct hlist_bl_node *pos; ++ struct au_finfo *finfo; ++ ++ n = 0; ++ p = a; ++ files = &au_sbi(sb)->si_files; ++ hlist_bl_lock(files); ++ hlist_bl_for_each_entry(finfo, pos, files, fi_hlist) { ++ f = finfo->fi_file; ++ if (file_count(f) ++ && !special_file(file_inode(f)->i_mode)) { ++ get_file(f); ++ *p++ = f; ++ n++; ++ AuDebugOn(n > max); ++ } ++ } ++ hlist_bl_unlock(files); ++ ++ return n; ++} ++ ++static struct file **au_farray_alloc(struct super_block *sb, ++ unsigned long long *max) ++{ ++ struct au_sbinfo *sbi; ++ ++ sbi = au_sbi(sb); ++ *max = au_lcnt_read(&sbi->si_nfiles, /*do_rev*/1); ++ return au_array_alloc(max, au_farray_cb, sb, /*arg*/NULL); ++} ++ ++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]); ++ kvfree(a); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * 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 btop, ++ aufs_bindex_t bbot) ++{ ++ return (inode && !S_ISDIR(inode->i_mode)) || btop == bbot; ++} ++ ++static int au_test_dbusy(struct dentry *dentry, aufs_bindex_t btop, ++ aufs_bindex_t bbot) ++{ ++ return au_test_ibusy(d_inode(dentry), btop, bbot); ++} ++ ++/* ++ * 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 btop, bbot; ++ 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(au_dcount(d) <= 0); ++ 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); */ ++ btop = au_dbtop(d); ++ bbot = au_dbbot(d); ++ if (btop <= bindex ++ && bindex <= bbot ++ && au_h_dptr(d, bindex) ++ && au_test_dbusy(d, btop, bbot)) { ++ err = -EBUSY; ++ AuVerbose(verbose, "busy %pd\n", 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 btop, bbot; ++ ++ 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 (unlikely(!i)) ++ break; ++ 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; ++ } ++ } ++ ++ btop = au_ibtop(i); ++ bbot = au_ibbot(i); ++ if (btop <= bindex ++ && bindex <= bbot ++ && au_h_iptr(i, bindex) ++ && au_test_ibusy(i, btop, bbot)) { ++ 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(d_inode(root)); ++ 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 int test_dir_busy(struct file *file, aufs_bindex_t br_id, ++ struct file **to_free, int *idx) ++{ ++ int err; ++ unsigned char matched, root; ++ aufs_bindex_t bindex, bbot; ++ struct au_fidir *fidir; ++ struct au_hfile *hfile; ++ ++ err = 0; ++ root = IS_ROOT(file->f_path.dentry); ++ if (root) { ++ get_file(file); ++ to_free[*idx] = file; ++ (*idx)++; ++ goto out; ++ } ++ ++ matched = 0; ++ fidir = au_fi(file)->fi_hdir; ++ AuDebugOn(!fidir); ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); bindex <= bbot; bindex++) { ++ hfile = fidir->fd_hfile + bindex; ++ if (!hfile->hf_file) ++ continue; ++ ++ if (hfile->hf_br->br_id == br_id) { ++ matched = 1; ++ break; ++ } ++ } ++ if (matched) ++ err = -EBUSY; ++ ++out: ++ return err; ++} ++ ++static int test_file_busy(struct super_block *sb, aufs_bindex_t br_id, ++ struct file **to_free, int opened) ++{ ++ int err, idx; ++ unsigned long long ull, max; ++ aufs_bindex_t btop; ++ struct file *file, **array; ++ struct dentry *root; ++ struct au_hfile *hfile; ++ ++ array = au_farray_alloc(sb, &max); ++ err = PTR_ERR(array); ++ if (IS_ERR(array)) ++ goto out; ++ ++ err = 0; ++ idx = 0; ++ root = sb->s_root; ++ di_write_unlock(root); ++ for (ull = 0; ull < max; ull++) { ++ file = array[ull]; ++ if (unlikely(!file)) ++ break; ++ ++ /* AuDbg("%pD\n", file); */ ++ fi_read_lock(file); ++ btop = au_fbtop(file); ++ if (!d_is_dir(file->f_path.dentry)) { ++ hfile = &au_fi(file)->fi_htop; ++ if (hfile->hf_br->br_id == br_id) ++ err = -EBUSY; ++ } else ++ err = test_dir_busy(file, br_id, to_free, &idx); ++ fi_read_unlock(file); ++ if (unlikely(err)) ++ break; ++ } ++ di_write_lock_child(root); ++ au_farray_free(array, max); ++ AuDebugOn(idx > opened); ++ ++out: ++ return err; ++} ++ ++static void br_del_file(struct file **to_free, unsigned long long opened, ++ aufs_bindex_t br_id) ++{ ++ unsigned long long ull; ++ aufs_bindex_t bindex, btop, bbot, bfound; ++ struct file *file; ++ struct au_fidir *fidir; ++ struct au_hfile *hfile; ++ ++ for (ull = 0; ull < opened; ull++) { ++ file = to_free[ull]; ++ if (unlikely(!file)) ++ break; ++ ++ /* AuDbg("%pD\n", file); */ ++ AuDebugOn(!d_is_dir(file->f_path.dentry)); ++ bfound = -1; ++ fidir = au_fi(file)->fi_hdir; ++ AuDebugOn(!fidir); ++ fi_write_lock(file); ++ btop = au_fbtop(file); ++ bbot = au_fbbot_dir(file); ++ for (bindex = btop; bindex <= bbot; bindex++) { ++ hfile = fidir->fd_hfile + bindex; ++ if (!hfile->hf_file) ++ continue; ++ ++ if (hfile->hf_br->br_id == br_id) { ++ bfound = bindex; ++ break; ++ } ++ } ++ AuDebugOn(bfound < 0); ++ au_set_h_fptr(file, bfound, NULL); ++ if (bfound == btop) { ++ for (btop++; btop <= bbot; btop++) ++ if (au_hf_dir(file, btop)) { ++ au_set_fbtop(file, btop); ++ break; ++ } ++ } ++ fi_write_unlock(file); ++ } ++} ++ ++static void au_br_do_del_brp(struct au_sbinfo *sbinfo, ++ const aufs_bindex_t bindex, ++ const aufs_bindex_t bbot) ++{ ++ struct au_branch **brp, **p; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ brp = sbinfo->si_branch + bindex; ++ if (bindex < bbot) ++ memmove(brp, brp + 1, sizeof(*brp) * (bbot - bindex)); ++ sbinfo->si_branch[0 + bbot] = NULL; ++ sbinfo->si_bbot--; ++ ++ p = au_krealloc(sbinfo->si_branch, sizeof(*p) * bbot, AuGFP_SBILIST, ++ /*may_shrink*/1); ++ 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 bbot) ++{ ++ struct au_hdentry *hdp, *p; ++ ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ hdp = au_hdentry(dinfo, bindex); ++ if (bindex < bbot) ++ memmove(hdp, hdp + 1, sizeof(*hdp) * (bbot - bindex)); ++ /* au_h_dentry_init(au_hdentry(dinfo, bbot); */ ++ dinfo->di_bbot--; ++ ++ p = au_krealloc(dinfo->di_hdentry, sizeof(*p) * bbot, AuGFP_SBILIST, ++ /*may_shrink*/1); ++ 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 bbot) ++{ ++ struct au_hinode *hip, *p; ++ ++ AuRwMustWriteLock(&iinfo->ii_rwsem); ++ ++ hip = au_hinode(iinfo, bindex); ++ if (bindex < bbot) ++ memmove(hip, hip + 1, sizeof(*hip) * (bbot - bindex)); ++ /* au_hinode_init(au_hinode(iinfo, bbot)); */ ++ iinfo->ii_bbot--; ++ ++ p = au_krealloc(iinfo->ii_hinode, sizeof(*p) * bbot, AuGFP_SBILIST, ++ /*may_shrink*/1); ++ 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 bbot; ++ 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 = d_inode(root); ++ sbinfo = au_sbi(sb); ++ bbot = sbinfo->si_bbot; ++ ++ 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, bbot); ++ au_br_do_del_hdp(au_di(root), bindex, bbot); ++ au_br_do_del_hip(au_ii(inode), bindex, bbot); ++ au_sbilist_unlock(); ++ ++ /* ignore an error */ ++ au_dr_br_fin(sb, br); /* always, regardless the mount option */ ++ ++ dput(h_root); ++ iput(h_inode); ++ au_br_do_free(br); ++} ++ ++static unsigned long long empty_cb(struct super_block *sb, void *array, ++ unsigned long long max, void *arg) ++{ ++ return max; ++} ++ ++int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount) ++{ ++ int err, rerr, i; ++ unsigned long long opened; ++ unsigned int mnt_flags; ++ aufs_bindex_t bindex, bbot, br_id; ++ unsigned char do_wh, verbose; ++ struct au_branch *br; ++ struct au_wbr *wbr; ++ struct dentry *root; ++ struct file **to_free; ++ ++ err = 0; ++ opened = 0; ++ to_free = NULL; ++ root = sb->s_root; ++ bindex = au_find_dbindex(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); ++ bbot = au_sbbot(sb); ++ if (unlikely(!bbot)) { ++ AuVerbose(verbose, "no more branches left\n"); ++ goto out; ++ } ++ ++ br = au_sbr(sb, bindex); ++ AuDebugOn(!path_equal(&br->br_path, &del->h_path)); ++ if (unlikely(au_lcnt_read(&br->br_count, /*do_rev*/1))) { ++ AuVerbose(verbose, "br %pd2 is busy now\n", del->h_path.dentry); ++ goto out; ++ } ++ ++ br_id = br->br_id; ++ opened = au_lcnt_read(&br->br_nfiles, /*do_rev*/1); ++ if (unlikely(opened)) { ++ to_free = au_array_alloc(&opened, empty_cb, sb, NULL); ++ err = PTR_ERR(to_free); ++ if (IS_ERR(to_free)) ++ goto out; ++ ++ err = test_file_busy(sb, br_id, to_free, opened); ++ if (unlikely(err)) { ++ AuVerbose(verbose, "%llu file(s) opened\n", opened); ++ 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(root, bindex, verbose); ++ if (unlikely(err)) { ++ if (do_wh) ++ goto out_wh; ++ goto out; ++ } ++ ++ err = 0; ++ if (to_free) { ++ /* ++ * now we confirmed the branch is deletable. ++ * let's free the remaining opened dirs on the branch. ++ */ ++ di_write_unlock(root); ++ br_del_file(to_free, opened, br_id); ++ di_write_lock_child(root); ++ } ++ ++ sysaufs_brs_del(sb, bindex); /* remove successors */ ++ dbgaufs_xino_del(br); /* remove one */ ++ au_br_do_del(sb, bindex, br); ++ sysaufs_brs_add(sb, bindex); /* append successors */ ++ dbgaufs_brs_add(sb, bindex, /*topdown*/1); /* rename successors */ ++ ++ if (!bindex) { ++ au_cpup_attr_all(d_inode(root), /*force*/1); ++ sb->s_maxbytes = au_sbr_sb(sb, 0)->s_maxbytes; ++ } else ++ au_sub_nlink(d_inode(root), d_inode(del->h_path.dentry)); ++ if (au_opt_test(mnt_flags, PLINK)) ++ au_plink_half_refresh(sb, br_id); ++ ++ goto out; /* success */ ++ ++out_wh: ++ /* revert */ ++ rerr = au_br_init_wh(sb, br, br->br_perm); ++ if (rerr) ++ pr_warn("failed re-creating base whiteout, %s. (%d)\n", ++ del->pathname, rerr); ++out: ++ if (to_free) ++ au_farray_free(to_free, opened); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_ibusy(struct super_block *sb, struct aufs_ibusy __user *arg) ++{ ++ int err; ++ aufs_bindex_t btop, bbot; ++ 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) ++ /* VERIFY_WRITE */ ++ err = !access_ok(&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_sbbot(sb))) ++ goto out_unlock; ++ ++ err = 0; ++ ibusy.h_ino = 0; /* invalid */ ++ inode = ilookup(sb, ibusy.ino); ++ if (!inode ++ || inode->i_ino == AUFS_ROOT_INO ++ || au_is_bad_inode(inode)) ++ goto out_unlock; ++ ++ ii_read_lock_child(inode); ++ btop = au_ibtop(inode); ++ bbot = au_ibbot(inode); ++ if (btop <= ibusy.bindex && ibusy.bindex <= bbot) { ++ h_inode = au_h_iptr(inode, ibusy.bindex); ++ if (h_inode && au_test_ibusy(inode, btop, bbot)) ++ 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_path.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_path.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 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, writer; ++ struct file *file, *hf, **array; ++ struct au_hfile *hfile; ++ struct inode *h_inode; ++ ++ 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]; ++ if (unlikely(!file)) ++ break; ++ ++ /* AuDbg("%pD\n", file); */ ++ fi_read_lock(file); ++ if (unlikely(au_test_mmapped(file))) { ++ err = -EBUSY; ++ AuVerbose(verbose, "mmapped %pD\n", file); ++ AuDbgFile(file); ++ FiMustNoWaiters(file); ++ fi_read_unlock(file); ++ goto out_array; ++ } ++ ++ hfile = &au_fi(file)->fi_htop; ++ hf = hfile->hf_file; ++ if (!d_is_reg(file->f_path.dentry) ++ || !(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? */ ++ /* ++ * fs/super.c:mark_files_ro() is gone, but aufs keeps its ++ * approach which resets f_mode and calls mnt_drop_write() and ++ * file_release_write() for each file, because the branch ++ * attribute in aufs world is totally different from the native ++ * fs rw/ro mode. ++ */ ++ /* fi_read_lock(file); */ ++ hfile = &au_fi(file)->fi_htop; ++ hf = hfile->hf_file; ++ /* fi_read_unlock(file); */ ++ spin_lock(&hf->f_lock); ++ writer = !!(hf->f_mode & FMODE_WRITER); ++ hf->f_mode &= ~(FMODE_WRITE | FMODE_WRITER); ++ spin_unlock(&hf->f_lock); ++ if (writer) { ++ h_inode = file_inode(hf); ++ put_write_access(h_inode); ++ __mnt_drop_write(hf->f_path.mnt); ++ if ((hf->f_mode & (FMODE_READ | FMODE_WRITE)) ++ == FMODE_READ) ++ i_readcount_inc(h_inode); ++ } ++ } ++ ++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 dentry *root; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ 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(d_inode(mod->h_root), mod->perm, mod->path); ++ if (unlikely(err)) ++ goto out; ++ ++ br = au_sbr(sb, bindex); ++ AuDebugOn(mod->h_root != au_br_dentry(br)); ++ if (br->br_perm == mod->perm) ++ return 0; /* success */ ++ ++ /* pre-allocate for non-fhsm --> fhsm */ ++ bf = NULL; ++ if (!au_br_fhsm(br->br_perm) && au_br_fhsm(mod->perm)) { ++ err = au_fhsm_br_alloc(br); ++ if (unlikely(err)) ++ goto out; ++ bf = br->br_fhsm; ++ br->br_fhsm = NULL; ++ } ++ ++ if (au_br_writable(br->br_perm)) { ++ /* remove whiteout base */ ++ err = au_br_init_wh(sb, br, mod->perm); ++ if (unlikely(err)) ++ goto out_bf; ++ ++ if (!au_br_writable(mod->perm)) { ++ /* rw --> ro, file might be mmapped */ ++ DiMustNoWaiters(root); ++ IiMustNoWaiters(d_inode(root)); ++ 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 = kzalloc(sizeof(*br->br_wbr), ++ GFP_NOFS); ++ if (br->br_wbr) ++ rerr = au_wbr_init(br, sb, br->br_perm); ++ 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 = kzalloc(sizeof(*br->br_wbr), GFP_NOFS); ++ if (br->br_wbr) { ++ err = au_wbr_init(br, sb, mod->perm); ++ if (unlikely(err)) { ++ au_kfree_rcu(br->br_wbr); ++ br->br_wbr = NULL; ++ } ++ } ++ } ++ if (unlikely(err)) ++ goto out_bf; ++ ++ if (au_br_fhsm(br->br_perm)) { ++ if (!au_br_fhsm(mod->perm)) { ++ /* fhsm --> non-fhsm */ ++ au_br_fhsm_fin(br->br_fhsm); ++ au_kfree_rcu(br->br_fhsm); ++ br->br_fhsm = NULL; ++ } ++ } else if (au_br_fhsm(mod->perm)) ++ /* non-fhsm --> fhsm */ ++ br->br_fhsm = bf; ++ ++ *do_refresh |= need_sigen_inc(br->br_perm, mod->perm); ++ br->br_perm = mod->perm; ++ goto out; /* success */ ++ ++out_bf: ++ au_kfree_try_rcu(bf); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_br_stfs(struct au_branch *br, struct aufs_stfs *stfs) ++{ ++ int err; ++ struct kstatfs kstfs; ++ ++ err = vfs_statfs(&br->br_path, &kstfs); ++ if (!err) { ++ stfs->f_blocks = kstfs.f_blocks; ++ stfs->f_bavail = kstfs.f_bavail; ++ stfs->f_files = kstfs.f_files; ++ stfs->f_ffree = kstfs.f_ffree; ++ } ++ ++ return err; ++} +diff -Nurp linux-5.4/fs/aufs/branch.h linux-5.4-aufs/fs/aufs/branch.h +--- linux-5.4/fs/aufs/branch.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/branch.h 2019-11-28 01:25:59.062925618 +0200 +@@ -0,0 +1,353 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * branch filesystems and xino for them ++ */ ++ ++#ifndef __AUFS_BRANCH_H__ ++#define __AUFS_BRANCH_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "dirren.h" ++#include "dynop.h" ++#include "lcnt.h" ++#include "rwsem.h" ++#include "super.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* a xino file */ ++struct au_xino { ++ struct file **xi_file; ++ unsigned int xi_nfile; ++ ++ struct { ++ spinlock_t spin; ++ ino_t *array; ++ int total; ++ /* reserved for future use */ ++ /* unsigned long *bitmap; */ ++ wait_queue_head_t wqh; ++ } xi_nondir; ++ ++ struct mutex xi_mtx; /* protects xi_file array */ ++ struct hlist_bl_head xi_writing; ++ ++ atomic_t xi_truncating; ++ ++ struct kref xi_kref; ++}; ++ ++/* File-based Hierarchical Storage Management */ ++struct au_br_fhsm { ++#ifdef CONFIG_AUFS_FHSM ++ struct mutex bf_lock; ++ unsigned long bf_jiffy; ++ struct aufs_stfs bf_stfs; ++ int bf_readable; ++#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 ++ ++/* sysfs entries */ ++struct au_brsysfs { ++ char name[16]; ++ struct attribute attr; ++}; ++ ++enum { ++ AuBrSysfs_BR, ++ AuBrSysfs_BRID, ++ AuBrSysfs_Last ++}; ++ ++/* protected by superblock rwsem */ ++struct au_branch { ++ struct au_xino *br_xino; ++ ++ aufs_bindex_t br_id; ++ ++ int br_perm; ++ struct path br_path; ++ spinlock_t br_dykey_lock; ++ struct au_dykey *br_dykey[AuBrDynOp]; ++ au_lcnt_t br_nfiles; /* opened files */ ++ au_lcnt_t br_count; /* in-use for other */ ++ ++ struct au_wbr *br_wbr; ++ struct au_br_fhsm *br_fhsm; ++ ++#ifdef CONFIG_AUFS_HFSNOTIFY ++ struct au_br_hfsnotify *br_hfsn; ++#endif ++ ++#ifdef CONFIG_SYSFS ++ /* entries under sysfs per mount-point */ ++ struct au_brsysfs br_sysfs[AuBrSysfs_Last]; ++#endif ++ ++#ifdef CONFIG_DEBUG_FS ++ struct dentry *br_dbgaufs; /* xino */ ++#endif ++ ++ struct au_dr_br br_dirren; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct vfsmount *au_br_mnt(struct au_branch *br) ++{ ++ return br->br_path.mnt; ++} ++ ++static inline struct dentry *au_br_dentry(struct au_branch *br) ++{ ++ return br->br_path.dentry; ++} ++ ++static inline struct super_block *au_br_sb(struct au_branch *br) ++{ ++ return au_br_mnt(br)->mnt_sb; ++} ++ ++static inline int au_br_rdonly(struct au_branch *br) ++{ ++ return (sb_rdonly(au_br_sb(br)) ++ || !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 ++} ++ ++static inline int au_br_test_oflag(int oflag, struct au_branch *br) ++{ ++ int err, exec_flag; ++ ++ err = 0; ++ exec_flag = oflag & __FMODE_EXEC; ++ if (unlikely(exec_flag && path_noexec(&br->br_path))) ++ err = -EACCES; ++ ++ return err; ++} ++ ++static inline void au_xino_get(struct au_branch *br) ++{ ++ struct au_xino *xi; ++ ++ xi = br->br_xino; ++ if (xi) ++ kref_get(&xi->xi_kref); ++} ++ ++static inline int au_xino_count(struct au_branch *br) ++{ ++ int v; ++ struct au_xino *xi; ++ ++ v = 0; ++ xi = br->br_xino; ++ if (xi) ++ v = kref_read(&xi->xi_kref); ++ ++ return v; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* 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); ++struct aufs_stfs; ++int au_br_stfs(struct au_branch *br, struct aufs_stfs *stfs); ++ ++/* xino.c */ ++static const loff_t au_loff_max = LLONG_MAX; ++ ++aufs_bindex_t au_xi_root(struct super_block *sb, struct dentry *dentry); ++struct file *au_xino_create(struct super_block *sb, char *fpath, int silent, ++ int wbrtop); ++struct file *au_xino_create2(struct super_block *sb, struct path *base, ++ struct file *copy_src); ++struct au_xi_new { ++ struct au_xino *xi; /* switch between xino and xigen */ ++ int idx; ++ struct path *base; ++ struct file *copy_src; ++}; ++struct file *au_xi_new(struct super_block *sb, struct au_xi_new *xinew); ++ ++int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t *ino); ++int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t ino); ++ssize_t xino_fread(vfs_readf_t func, struct file *file, void *buf, size_t size, ++ loff_t *pos); ++ssize_t xino_fwrite(vfs_writef_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos); ++ ++int au_xib_trunc(struct super_block *sb); ++int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex, int idx_begin); ++ ++struct au_xino *au_xino_alloc(unsigned int nfile); ++int au_xino_put(struct au_branch *br); ++struct file *au_xino_file1(struct au_xino *xi); ++ ++struct au_opt_xino; ++void au_xino_clr(struct super_block *sb); ++int au_xino_set(struct super_block *sb, struct au_opt_xino *xiopt, int remount); ++struct file *au_xino_def(struct super_block *sb); ++int au_xino_init_br(struct super_block *sb, struct au_branch *br, ino_t hino, ++ struct path *base); ++ ++ino_t au_xino_new_ino(struct super_block *sb); ++void au_xino_delete_inode(struct inode *inode, const int unlinked); ++ ++void au_xinondir_leave(struct super_block *sb, aufs_bindex_t bindex, ++ ino_t h_ino, int idx); ++int au_xinondir_enter(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ int *idx); ++ ++int au_xino_path(struct seq_file *seq, struct file *file); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* @idx is signed to accept -1 meaning the first file */ ++static inline struct file *au_xino_file(struct au_xino *xi, int idx) ++{ ++ struct file *file; ++ ++ file = NULL; ++ if (!xi) ++ goto out; ++ ++ if (idx >= 0) { ++ if (idx < xi->xi_nfile) ++ file = xi->xi_file[idx]; ++ } else ++ file = au_xino_file1(xi); ++ ++out: ++ return 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_br_mnt(au_sbr(sb, bindex)); ++} ++ ++static inline ++struct super_block *au_sbr_sb(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_br_sb(au_sbr(sb, bindex)); ++} ++ ++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)); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define wbr_wh_read_lock(wbr) au_rw_read_lock(&(wbr)->wbr_wh_rwsem) ++#define wbr_wh_write_lock(wbr) au_rw_write_lock(&(wbr)->wbr_wh_rwsem) ++#define wbr_wh_read_trylock(wbr) au_rw_read_trylock(&(wbr)->wbr_wh_rwsem) ++#define wbr_wh_write_trylock(wbr) au_rw_write_trylock(&(wbr)->wbr_wh_rwsem) ++/* ++#define wbr_wh_read_trylock_nested(wbr) \ ++ au_rw_read_trylock_nested(&(wbr)->wbr_wh_rwsem) ++#define wbr_wh_write_trylock_nested(wbr) \ ++ au_rw_write_trylock_nested(&(wbr)->wbr_wh_rwsem) ++*/ ++ ++#define wbr_wh_read_unlock(wbr) au_rw_read_unlock(&(wbr)->wbr_wh_rwsem) ++#define wbr_wh_write_unlock(wbr) au_rw_write_unlock(&(wbr)->wbr_wh_rwsem) ++#define wbr_wh_downgrade_lock(wbr) au_rw_dgrade_lock(&(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) ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_FHSM ++static inline void au_br_fhsm_init(struct au_br_fhsm *brfhsm) ++{ ++ mutex_init(&brfhsm->bf_lock); ++ brfhsm->bf_jiffy = 0; ++ brfhsm->bf_readable = 0; ++} ++ ++static inline void au_br_fhsm_fin(struct au_br_fhsm *brfhsm) ++{ ++ mutex_destroy(&brfhsm->bf_lock); ++} ++#else ++AuStubVoid(au_br_fhsm_init, struct au_br_fhsm *brfhsm) ++AuStubVoid(au_br_fhsm_fin, struct au_br_fhsm *brfhsm) ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_BRANCH_H__ */ +diff -Nurp linux-5.4/fs/aufs/cpup.c linux-5.4-aufs/fs/aufs/cpup.c +--- linux-5.4/fs/aufs/cpup.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/cpup.c 2019-11-28 01:25:59.063925618 +0200 +@@ -0,0 +1,1445 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * copy-up functions, see wbr_policy.c for copy-down ++ */ ++ ++#include ++#include ++#include ++#include "aufs.h" ++ ++void au_cpup_attr_flags(struct inode *dst, unsigned int iflags) ++{ ++ const unsigned int mask = S_DEAD | S_SWAPFILE | S_PRIVATE ++ | S_NOATIME | S_NOCMTIME | S_AUTOMOUNT; ++ ++ BUILD_BUG_ON(sizeof(iflags) != sizeof(dst->i_flags)); ++ ++ dst->i_flags |= iflags & ~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_ibtop(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, bbot; ++ ++ sb = inode->i_sb; ++ bindex = au_ibtop(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 may not be held here, but it is harmless since once ++ * i_nlink reaches 0, it will never become positive except O_TMPFILE ++ * case. ++ * todo: O_TMPFILE+linkat(AT_SYMLINK_FOLLOW) bypassing aufs may cause ++ * the incorrect link count. ++ */ ++ 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)) { ++ bbot = au_ibbot(inode); ++ for (bindex++; bindex <= bbot; 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_ibtop(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->i_flags); ++} ++ ++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_ibtop(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 = d_inode(h_path->dentry); ++ 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; ++ ++ /* no delegation since this is a directory */ ++ err = vfsub_notify_change(&dt->dt_h_path, &attr, /*delegated*/NULL); ++ if (unlikely(err)) ++ pr_warn("restoring timestamps failed(%d). ignored\n", err); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* internal use only */ ++struct au_cpup_reg_attr { ++ int valid; ++ struct kstat st; ++ unsigned int iflags; /* inode->i_flags */ ++}; ++ ++static noinline_for_stack ++int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct dentry *h_src, ++ struct au_cpup_reg_attr *h_src_attr) ++{ ++ int err, sbits, icex; ++ unsigned int mnt_flags; ++ unsigned char verbose; ++ struct iattr ia; ++ struct path h_path; ++ struct inode *h_isrc, *h_idst; ++ struct kstat *h_st; ++ struct au_branch *br; ++ ++ h_path.dentry = au_h_dptr(dst, bindex); ++ h_idst = d_inode(h_path.dentry); ++ br = au_sbr(dst->d_sb, bindex); ++ h_path.mnt = au_br_mnt(br); ++ h_isrc = d_inode(h_src); ++ ia.ia_valid = ATTR_FORCE | ATTR_UID | ATTR_GID ++ | ATTR_ATIME | ATTR_MTIME ++ | ATTR_ATIME_SET | ATTR_MTIME_SET; ++ if (h_src_attr && h_src_attr->valid) { ++ h_st = &h_src_attr->st; ++ ia.ia_uid = h_st->uid; ++ ia.ia_gid = h_st->gid; ++ ia.ia_atime = h_st->atime; ++ ia.ia_mtime = h_st->mtime; ++ if (h_idst->i_mode != h_st->mode ++ && !S_ISLNK(h_idst->i_mode)) { ++ ia.ia_valid |= ATTR_MODE; ++ ia.ia_mode = h_st->mode; ++ } ++ sbits = !!(h_st->mode & (S_ISUID | S_ISGID)); ++ au_cpup_attr_flags(h_idst, h_src_attr->iflags); ++ } else { ++ 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->i_flags); ++ } ++ /* no delegation since it is just created */ ++ err = vfsub_notify_change(&h_path, &ia, /*delegated*/NULL); ++ ++ /* 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, /*delegated*/NULL); ++ } ++ ++ icex = br->br_perm & AuBrAttr_ICEX; ++ if (!err) { ++ mnt_flags = au_mntflags(dst->d_sb); ++ verbose = !!au_opt_test(mnt_flags, VERBOSE); ++ err = au_cpup_xattr(h_path.dentry, h_src, icex, verbose); ++ } ++ ++ 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 inode *h_inode; ++ /* 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; ++ } ++ if (unlikely(err < 0)) ++ break; ++ } 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_path.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_inode = file_inode(dst); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD2); ++ /* no delegation since it is just created */ ++ err = vfsub_notify_change(&dst->f_path, ia, ++ /*delegated*/NULL); ++ inode_unlock(h_inode); ++ } ++ } ++ ++ 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; ++ struct super_block *h_sb; ++ ++ err = -ENOMEM; ++ h_sb = file_inode(dst)->i_sb; ++ blksize = h_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) { ++ AuDebugOn(!au_kfree_do_sz_test(blksize)); ++ au_kfree_do_rcu(buf); ++ } else ++ free_page((unsigned long)buf); ++ ++out: ++ return err; ++} ++ ++static int au_do_copy(struct file *dst, struct file *src, loff_t len) ++{ ++ int err; ++ struct super_block *h_src_sb; ++ struct inode *h_src_inode; ++ ++ h_src_inode = file_inode(src); ++ h_src_sb = h_src_inode->i_sb; ++ ++ /* XFS acquires inode_lock */ ++ if (!au_test_xfs(h_src_sb)) ++ err = au_copy_file(dst, src, len); ++ else { ++ inode_unlock_shared(h_src_inode); ++ err = au_copy_file(dst, src, len); ++ inode_lock_shared_nested(h_src_inode, AuLsc_I_CHILD); ++ } ++ ++ return err; ++} ++ ++static int au_clone_or_copy(struct file *dst, struct file *src, loff_t len) ++{ ++ int err; ++ loff_t lo; ++ struct super_block *h_src_sb; ++ struct inode *h_src_inode; ++ ++ h_src_inode = file_inode(src); ++ h_src_sb = h_src_inode->i_sb; ++ if (h_src_sb != file_inode(dst)->i_sb ++ || !dst->f_op->remap_file_range) { ++ err = au_do_copy(dst, src, len); ++ goto out; ++ } ++ ++ if (!au_test_nfs(h_src_sb)) { ++ inode_unlock_shared(h_src_inode); ++ lo = vfsub_clone_file_range(src, dst, len); ++ inode_lock_shared_nested(h_src_inode, AuLsc_I_CHILD); ++ } else ++ lo = vfsub_clone_file_range(src, dst, len); ++ if (lo == len) { ++ err = 0; ++ goto out; /* success */ ++ } else if (lo >= 0) ++ /* todo: possible? */ ++ /* paritially succeeded */ ++ AuDbg("lo %lld, len %lld. Retrying.\n", lo, len); ++ else if (lo != -EOPNOTSUPP) { ++ /* older XFS has a condition in cloning */ ++ err = lo; ++ goto out; ++ } ++ ++ /* the backend fs on NFS may not support cloning */ ++ err = au_do_copy(dst, src, len); ++ ++out: ++ AuTraceErr(err); ++ 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 au_cp_generic *cpg) ++{ ++ int err, i; ++ enum { SRC, DST }; ++ struct { ++ aufs_bindex_t bindex; ++ unsigned int flags; ++ struct dentry *dentry; ++ int force_wr; ++ struct file *file; ++ } *f, file[] = { ++ { ++ .bindex = cpg->bsrc, ++ .flags = O_RDONLY | O_NOATIME | O_LARGEFILE, ++ }, ++ { ++ .bindex = cpg->bdst, ++ .flags = O_WRONLY | O_NOATIME | O_LARGEFILE, ++ .force_wr = !!au_ftest_cpup(cpg->flags, RWDST), ++ } ++ }; ++ struct au_branch *br; ++ struct super_block *sb, *h_src_sb; ++ struct inode *h_src_inode; ++ struct task_struct *tsk = current; ++ ++ /* bsrc branch can be ro/rw. */ ++ sb = cpg->dentry->d_sb; ++ f = file; ++ for (i = 0; i < 2; i++, f++) { ++ f->dentry = au_h_dptr(cpg->dentry, f->bindex); ++ f->file = au_h_open(cpg->dentry, f->bindex, f->flags, ++ /*file*/NULL, f->force_wr); ++ if (IS_ERR(f->file)) { ++ err = PTR_ERR(f->file); ++ if (i == SRC) ++ goto out; ++ else ++ goto out_src; ++ } ++ } ++ ++ /* try stopping to update while we copyup */ ++ h_src_inode = d_inode(file[SRC].dentry); ++ h_src_sb = h_src_inode->i_sb; ++ if (!au_test_nfs(h_src_sb)) ++ IMustLock(h_src_inode); ++ err = au_clone_or_copy(file[DST].file, file[SRC].file, cpg->len); ++ ++ /* i wonder if we had O_NO_DELAY_FPUT flag */ ++ if (tsk->flags & PF_KTHREAD) ++ __fput_sync(file[DST].file); ++ else { ++ /* it happened actually */ ++ fput(file[DST].file); ++ /* ++ * too bad. ++ * we have to call both since we don't know which place the file ++ * was added to. ++ */ ++ task_work_run(); ++ flush_delayed_fput(); ++ } ++ br = au_sbr(sb, file[DST].bindex); ++ au_lcnt_dec(&br->br_nfiles); ++ ++out_src: ++ fput(file[SRC].file); ++ br = au_sbr(sb, file[SRC].bindex); ++ au_lcnt_dec(&br->br_nfiles); ++out: ++ return err; ++} ++ ++static int au_do_cpup_regular(struct au_cp_generic *cpg, ++ struct au_cpup_reg_attr *h_src_attr) ++{ ++ int err, rerr; ++ loff_t l; ++ struct path h_path; ++ struct inode *h_src_inode, *h_dst_inode; ++ ++ err = 0; ++ h_src_inode = au_h_iptr(d_inode(cpg->dentry), cpg->bsrc); ++ l = i_size_read(h_src_inode); ++ if (cpg->len == -1 || l < cpg->len) ++ cpg->len = l; ++ if (cpg->len) { ++ /* try stopping to update while we are referencing */ ++ inode_lock_shared_nested(h_src_inode, AuLsc_I_CHILD); ++ au_pin_hdir_unlock(cpg->pin); ++ ++ h_path.dentry = au_h_dptr(cpg->dentry, cpg->bsrc); ++ h_path.mnt = au_sbr_mnt(cpg->dentry->d_sb, cpg->bsrc); ++ h_src_attr->iflags = h_src_inode->i_flags; ++ if (!au_test_nfs(h_src_inode->i_sb)) ++ err = vfsub_getattr(&h_path, &h_src_attr->st); ++ else { ++ inode_unlock_shared(h_src_inode); ++ err = vfsub_getattr(&h_path, &h_src_attr->st); ++ inode_lock_shared_nested(h_src_inode, AuLsc_I_CHILD); ++ } ++ if (unlikely(err)) { ++ inode_unlock_shared(h_src_inode); ++ goto out; ++ } ++ h_src_attr->valid = 1; ++ if (!au_test_nfs(h_src_inode->i_sb)) { ++ err = au_cp_regular(cpg); ++ inode_unlock_shared(h_src_inode); ++ } else { ++ inode_unlock_shared(h_src_inode); ++ err = au_cp_regular(cpg); ++ } ++ rerr = au_pin_hdir_relock(cpg->pin); ++ if (!err && rerr) ++ err = rerr; ++ } ++ if (!err && (h_src_inode->i_state & I_LINKABLE)) { ++ h_path.dentry = au_h_dptr(cpg->dentry, cpg->bdst); ++ h_dst_inode = d_inode(h_path.dentry); ++ spin_lock(&h_dst_inode->i_lock); ++ h_dst_inode->i_state |= I_LINKABLE; ++ spin_unlock(&h_dst_inode->i_lock); ++ } ++ ++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 = -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 = vfs_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; ++} ++ ++/* ++ * regardless 'acl' option, reset all ACL. ++ * All ACL will be copied up later from the original entry on the lower branch. ++ */ ++static int au_reset_acl(struct inode *h_dir, struct path *h_path, umode_t mode) ++{ ++ int err; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ ++ h_dentry = h_path->dentry; ++ h_inode = d_inode(h_dentry); ++ /* forget_all_cached_acls(h_inode)); */ ++ err = vfsub_removexattr(h_dentry, XATTR_NAME_POSIX_ACL_ACCESS); ++ AuTraceErr(err); ++ if (err == -EOPNOTSUPP) ++ err = 0; ++ if (!err) ++ err = vfsub_acl_chmod(h_inode, mode); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_do_cpup_dir(struct au_cp_generic *cpg, struct dentry *dst_parent, ++ struct inode *h_dir, struct path *h_path) ++{ ++ int err; ++ struct inode *dir, *inode; ++ ++ err = vfsub_removexattr(h_path->dentry, XATTR_NAME_POSIX_ACL_DEFAULT); ++ AuTraceErr(err); ++ if (err == -EOPNOTSUPP) ++ err = 0; ++ if (unlikely(err)) ++ goto out; ++ ++ /* ++ * strange behaviour from the users view, ++ * particularly setattr case ++ */ ++ dir = d_inode(dst_parent); ++ if (au_ibtop(dir) == cpg->bdst) ++ au_cpup_attr_nlink(dir, /*force*/1); ++ inode = d_inode(cpg->dentry); ++ au_cpup_attr_nlink(inode, /*force*/1); ++ ++out: ++ return err; ++} ++ ++static noinline_for_stack ++int cpup_entry(struct au_cp_generic *cpg, struct dentry *dst_parent, ++ struct au_cpup_reg_attr *h_src_attr) ++{ ++ int err; ++ umode_t mode; ++ unsigned int mnt_flags; ++ unsigned char isdir, isreg, force; ++ const unsigned char do_dt = !!au_ftest_cpup(cpg->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(cpg->dentry, cpg->bsrc); ++ h_inode = d_inode(h_src); ++ AuDebugOn(h_inode != au_h_iptr(d_inode(cpg->dentry), cpg->bsrc)); ++ ++ /* try stopping to be referenced while we are creating */ ++ h_dst = au_h_dptr(cpg->dentry, cpg->bdst); ++ if (au_ftest_cpup(cpg->flags, RENAME)) ++ AuDebugOn(strncmp(h_dst->d_name.name, AUFS_WH_PFX, ++ AUFS_WH_PFX_LEN)); ++ h_parent = h_dst->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ AuDebugOn(h_parent != h_dst->d_parent); ++ ++ sb = cpg->dentry->d_sb; ++ h_path.mnt = au_sbr_mnt(sb, cpg->bdst); ++ if (do_dt) { ++ h_path.dentry = h_parent; ++ au_dtime_store(&dt, dst_parent, &h_path); ++ } ++ h_path.dentry = h_dst; ++ ++ isreg = 0; ++ isdir = 0; ++ mode = h_inode->i_mode; ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ isreg = 1; ++ err = vfsub_create(h_dir, &h_path, 0600, /*want_excl*/true); ++ if (!err) ++ err = au_do_cpup_regular(cpg, h_src_attr); ++ break; ++ case S_IFDIR: ++ isdir = 1; ++ err = vfsub_mkdir(h_dir, &h_path, mode); ++ if (!err) ++ err = au_do_cpup_dir(cpg, dst_parent, h_dir, &h_path); ++ 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; ++ } ++ if (!err) ++ err = au_reset_acl(h_dir, &h_path, mode); ++ ++ 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 ++ || (h_inode->i_state & I_LINKABLE)) ++ /* todo: unnecessary? */ ++ /* && d_inode(cpg->dentry)->i_nlink == 1 */ ++ && cpg->bdst < cpg->bsrc ++ && !au_ftest_cpup(cpg->flags, KEEPLINO)) ++ au_xino_write(sb, cpg->bsrc, h_inode->i_ino, /*ino*/0); ++ /* ignore this error */ ++ ++ if (!err) { ++ force = 0; ++ if (isreg) { ++ force = !!cpg->len; ++ if (cpg->len == -1) ++ force = !!i_size_read(h_inode); ++ } ++ au_fhsm_wrote(sb, cpg->bdst, force); ++ } ++ ++ if (do_dt) ++ au_dtime_revert(&dt); ++ return err; ++} ++ ++static int au_do_ren_after_cpup(struct au_cp_generic *cpg, struct path *h_path) ++{ ++ int err; ++ struct dentry *dentry, *h_dentry, *h_parent, *parent; ++ struct inode *h_dir; ++ aufs_bindex_t bdst; ++ ++ dentry = cpg->dentry; ++ bdst = cpg->bdst; ++ h_dentry = au_h_dptr(dentry, bdst); ++ if (!au_ftest_cpup(cpg->flags, OVERWRITE)) { ++ dget(h_dentry); ++ au_set_h_dptr(dentry, bdst, NULL); ++ err = au_lkup_neg(dentry, bdst, /*wh*/0); ++ if (!err) ++ h_path->dentry = dget(au_h_dptr(dentry, bdst)); ++ au_set_h_dptr(dentry, bdst, h_dentry); ++ } else { ++ err = 0; ++ parent = dget_parent(dentry); ++ h_parent = au_h_dptr(parent, bdst); ++ dput(parent); ++ h_path->dentry = vfsub_lkup_one(&dentry->d_name, h_parent); ++ if (IS_ERR(h_path->dentry)) ++ err = PTR_ERR(h_path->dentry); ++ } ++ if (unlikely(err)) ++ goto out; ++ ++ h_parent = h_dentry->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ AuDbg("%pd %pd\n", h_dentry, h_path->dentry); ++ /* no delegation since it is just created */ ++ err = vfsub_rename(h_dir, h_dentry, h_dir, h_path, /*delegated*/NULL, ++ /*flags*/0); ++ dput(h_path->dentry); ++ ++out: ++ 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. ++ * basic->bsrc can be larger than basic->bdst. ++ * aufs doesn't touch the credential so ++ * security_inode_copy_up{,_xattr}() are unnecessary. ++ */ ++static int au_cpup_single(struct au_cp_generic *cpg, struct dentry *dst_parent) ++{ ++ int err, rerr; ++ aufs_bindex_t old_ibtop; ++ unsigned char isdir, plink; ++ struct dentry *h_src, *h_dst, *h_parent; ++ struct inode *dst_inode, *h_dir, *inode, *delegated, *src_inode; ++ struct super_block *sb; ++ struct au_branch *br; ++ /* to reduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct path h_path; ++ struct au_cpup_reg_attr h_src_attr; ++ } *a; ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ a->h_src_attr.valid = 0; ++ ++ sb = cpg->dentry->d_sb; ++ br = au_sbr(sb, cpg->bdst); ++ a->h_path.mnt = au_br_mnt(br); ++ h_dst = au_h_dptr(cpg->dentry, cpg->bdst); ++ h_parent = h_dst->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ ++ h_src = au_h_dptr(cpg->dentry, cpg->bsrc); ++ inode = d_inode(cpg->dentry); ++ ++ if (!dst_parent) ++ dst_parent = dget_parent(cpg->dentry); ++ else ++ dget(dst_parent); ++ ++ plink = !!au_opt_test(au_mntflags(sb), PLINK); ++ dst_inode = au_h_iptr(inode, cpg->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, cpg->bdst); ++ goto out_parent; ++ } ++ ++ if (dst_inode->i_nlink) { ++ const int do_dt = au_ftest_cpup(cpg->flags, DTIME); ++ ++ h_src = au_plink_lkup(inode, cpg->bdst); ++ err = PTR_ERR(h_src); ++ if (IS_ERR(h_src)) ++ goto out_parent; ++ if (unlikely(d_is_negative(h_src))) { ++ err = -EIO; ++ AuIOErr("i%lu exists on b%d " ++ "but not pseudo-linked\n", ++ inode->i_ino, cpg->bdst); ++ dput(h_src); ++ goto out_parent; ++ } ++ ++ if (do_dt) { ++ a->h_path.dentry = h_parent; ++ au_dtime_store(&a->dt, dst_parent, &a->h_path); ++ } ++ ++ a->h_path.dentry = h_dst; ++ delegated = NULL; ++ err = vfsub_link(h_src, h_dir, &a->h_path, &delegated); ++ if (!err && au_ftest_cpup(cpg->flags, RENAME)) ++ err = au_do_ren_after_cpup(cpg, &a->h_path); ++ if (do_dt) ++ au_dtime_revert(&a->dt); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ dput(h_src); ++ goto out_parent; ++ } else ++ /* todo: cpup_wh_file? */ ++ /* udba work */ ++ au_update_ibrange(inode, /*do_put_zero*/1); ++ } ++ ++ isdir = S_ISDIR(inode->i_mode); ++ old_ibtop = au_ibtop(inode); ++ err = cpup_entry(cpg, dst_parent, &a->h_src_attr); ++ if (unlikely(err)) ++ goto out_rev; ++ dst_inode = d_inode(h_dst); ++ inode_lock_nested(dst_inode, AuLsc_I_CHILD2); ++ /* todo: necessary? */ ++ /* au_pin_hdir_unlock(cpg->pin); */ ++ ++ err = cpup_iattr(cpg->dentry, cpg->bdst, h_src, &a->h_src_attr); ++ if (unlikely(err)) { ++ /* todo: necessary? */ ++ /* au_pin_hdir_relock(cpg->pin); */ /* ignore an error */ ++ inode_unlock(dst_inode); ++ goto out_rev; ++ } ++ ++ if (cpg->bdst < old_ibtop) { ++ if (S_ISREG(inode->i_mode)) { ++ err = au_dy_iaop(inode, cpg->bdst, dst_inode); ++ if (unlikely(err)) { ++ /* ignore an error */ ++ /* au_pin_hdir_relock(cpg->pin); */ ++ inode_unlock(dst_inode); ++ goto out_rev; ++ } ++ } ++ au_set_ibtop(inode, cpg->bdst); ++ } else ++ au_set_ibbot(inode, cpg->bdst); ++ au_set_h_iptr(inode, cpg->bdst, au_igrab(dst_inode), ++ au_hi_flags(inode, isdir)); ++ ++ /* todo: necessary? */ ++ /* err = au_pin_hdir_relock(cpg->pin); */ ++ inode_unlock(dst_inode); ++ if (unlikely(err)) ++ goto out_rev; ++ ++ src_inode = d_inode(h_src); ++ if (!isdir ++ && (src_inode->i_nlink > 1 ++ || src_inode->i_state & I_LINKABLE) ++ && plink) ++ au_plink_append(inode, cpg->bdst, h_dst); ++ ++ if (au_ftest_cpup(cpg->flags, RENAME)) { ++ a->h_path.dentry = h_dst; ++ err = au_do_ren_after_cpup(cpg, &a->h_path); ++ } ++ if (!err) ++ goto out_parent; /* success */ ++ ++ /* revert */ ++out_rev: ++ a->h_path.dentry = h_parent; ++ au_dtime_store(&a->dt, dst_parent, &a->h_path); ++ a->h_path.dentry = h_dst; ++ rerr = 0; ++ if (d_is_positive(h_dst)) { ++ if (!isdir) { ++ /* no delegation since it is just created */ ++ rerr = vfsub_unlink(h_dir, &a->h_path, ++ /*delegated*/NULL, /*force*/0); ++ } else ++ rerr = vfsub_rmdir(h_dir, &a->h_path); ++ } ++ au_dtime_revert(&a->dt); ++ if (rerr) { ++ AuIOErr("failed removing broken entry(%d, %d)\n", err, rerr); ++ err = -EIO; ++ } ++out_parent: ++ dput(dst_parent); ++ au_kfree_rcu(a); ++out: ++ return err; ++} ++ ++#if 0 /* reserved */ ++struct au_cpup_single_args { ++ int *errp; ++ struct au_cp_generic *cpg; ++ struct dentry *dst_parent; ++}; ++ ++static void au_call_cpup_single(void *args) ++{ ++ struct au_cpup_single_args *a = args; ++ ++ au_pin_hdir_acquire_nest(a->cpg->pin); ++ *a->errp = au_cpup_single(a->cpg, a->dst_parent); ++ au_pin_hdir_release(a->cpg->pin); ++} ++#endif ++ ++/* ++ * 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 au_pin *pin, umode_t mode) ++{ ++ int do_sio; ++ struct super_block *sb; ++ struct inode *h_dir; ++ ++ do_sio = 0; ++ sb = au_pinned_parent(pin)->d_sb; ++ 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)); ++ /* this workaround may be removed in the future */ ++ if (!do_sio) { ++ h_dir = au_pinned_h_dir(pin); ++ do_sio = h_dir->i_mode & S_ISVTX; ++ } ++ } ++ ++ return do_sio; ++} ++ ++#if 0 /* reserved */ ++int au_sio_cpup_single(struct au_cp_generic *cpg, struct dentry *dst_parent) ++{ ++ int err, wkq_err; ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(cpg->dentry, cpg->bsrc); ++ if (!au_cpup_sio_test(pin, d_inode(h_dentry)->i_mode)) ++ err = au_cpup_single(cpg, dst_parent); ++ else { ++ struct au_cpup_single_args args = { ++ .errp = &err, ++ .cpg = cpg, ++ .dst_parent = dst_parent ++ }; ++ wkq_err = au_wkq_wait(au_call_cpup_single, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ return err; ++} ++#endif ++ ++/* ++ * copyup the @dentry from the first active lower branch to @bdst, ++ * using au_cpup_single(). ++ */ ++static int au_cpup_simple(struct au_cp_generic *cpg) ++{ ++ int err; ++ unsigned int flags_orig; ++ struct dentry *dentry; ++ ++ AuDebugOn(cpg->bsrc < 0); ++ ++ dentry = cpg->dentry; ++ DiMustWriteLock(dentry); ++ ++ err = au_lkup_neg(dentry, cpg->bdst, /*wh*/1); ++ if (!err) { ++ flags_orig = cpg->flags; ++ au_fset_cpup(cpg->flags, RENAME); ++ err = au_cpup_single(cpg, NULL); ++ cpg->flags = flags_orig; ++ if (!err) ++ return 0; /* success */ ++ ++ /* revert */ ++ au_set_h_dptr(dentry, cpg->bdst, NULL); ++ au_set_dbtop(dentry, cpg->bsrc); ++ } ++ ++ return err; ++} ++ ++struct au_cpup_simple_args { ++ int *errp; ++ struct au_cp_generic *cpg; ++}; ++ ++static void au_call_cpup_simple(void *args) ++{ ++ struct au_cpup_simple_args *a = args; ++ ++ au_pin_hdir_acquire_nest(a->cpg->pin); ++ *a->errp = au_cpup_simple(a->cpg); ++ au_pin_hdir_release(a->cpg->pin); ++} ++ ++static int au_do_sio_cpup_simple(struct au_cp_generic *cpg) ++{ ++ int err, wkq_err; ++ struct dentry *dentry, *parent; ++ struct file *h_file; ++ struct inode *h_dir; ++ ++ dentry = cpg->dentry; ++ h_file = NULL; ++ if (au_ftest_cpup(cpg->flags, HOPEN)) { ++ AuDebugOn(cpg->bsrc < 0); ++ h_file = au_h_open_pre(dentry, cpg->bsrc, /*force_wr*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ } ++ ++ parent = dget_parent(dentry); ++ h_dir = au_h_iptr(d_inode(parent), cpg->bdst); ++ if (!au_test_h_perm_sio(h_dir, MAY_EXEC | MAY_WRITE) ++ && !au_cpup_sio_test(cpg->pin, d_inode(dentry)->i_mode)) ++ err = au_cpup_simple(cpg); ++ else { ++ struct au_cpup_simple_args args = { ++ .errp = &err, ++ .cpg = cpg ++ }; ++ wkq_err = au_wkq_wait(au_call_cpup_simple, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ dput(parent); ++ if (h_file) ++ au_h_open_post(dentry, cpg->bsrc, h_file); ++ ++out: ++ return err; ++} ++ ++int au_sio_cpup_simple(struct au_cp_generic *cpg) ++{ ++ aufs_bindex_t bsrc, bbot; ++ struct dentry *dentry, *h_dentry; ++ ++ if (cpg->bsrc < 0) { ++ dentry = cpg->dentry; ++ bbot = au_dbbot(dentry); ++ for (bsrc = cpg->bdst + 1; bsrc <= bbot; bsrc++) { ++ h_dentry = au_h_dptr(dentry, bsrc); ++ if (h_dentry) { ++ AuDebugOn(d_is_negative(h_dentry)); ++ break; ++ } ++ } ++ AuDebugOn(bsrc > bbot); ++ cpg->bsrc = bsrc; ++ } ++ AuDebugOn(cpg->bsrc <= cpg->bdst); ++ return au_do_sio_cpup_simple(cpg); ++} ++ ++int au_sio_cpdown_simple(struct au_cp_generic *cpg) ++{ ++ AuDebugOn(cpg->bdst <= cpg->bsrc); ++ return au_do_sio_cpup_simple(cpg); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * copyup the deleted file for writing. ++ */ ++static int au_do_cpup_wh(struct au_cp_generic *cpg, struct dentry *wh_dentry, ++ struct file *file) ++{ ++ int err; ++ unsigned int flags_orig; ++ aufs_bindex_t bsrc_orig; ++ struct au_dinfo *dinfo; ++ struct { ++ struct au_hdentry *hd; ++ struct dentry *h_dentry; ++ } hdst, hsrc; ++ ++ dinfo = au_di(cpg->dentry); ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ bsrc_orig = cpg->bsrc; ++ cpg->bsrc = dinfo->di_btop; ++ hdst.hd = au_hdentry(dinfo, cpg->bdst); ++ hdst.h_dentry = hdst.hd->hd_dentry; ++ hdst.hd->hd_dentry = wh_dentry; ++ dinfo->di_btop = cpg->bdst; ++ ++ hsrc.h_dentry = NULL; ++ if (file) { ++ hsrc.hd = au_hdentry(dinfo, cpg->bsrc); ++ hsrc.h_dentry = hsrc.hd->hd_dentry; ++ hsrc.hd->hd_dentry = au_hf_top(file)->f_path.dentry; ++ } ++ flags_orig = cpg->flags; ++ cpg->flags = !AuCpup_DTIME; ++ err = au_cpup_single(cpg, /*h_parent*/NULL); ++ cpg->flags = flags_orig; ++ if (file) { ++ if (!err) ++ err = au_reopen_nondir(file); ++ hsrc.hd->hd_dentry = hsrc.h_dentry; ++ } ++ hdst.hd->hd_dentry = hdst.h_dentry; ++ dinfo->di_btop = cpg->bsrc; ++ cpg->bsrc = bsrc_orig; ++ ++ return err; ++} ++ ++static int au_cpup_wh(struct au_cp_generic *cpg, struct file *file) ++{ ++ int err; ++ aufs_bindex_t bdst; ++ struct au_dtime dt; ++ struct dentry *dentry, *parent, *h_parent, *wh_dentry; ++ struct au_branch *br; ++ struct path h_path; ++ ++ dentry = cpg->dentry; ++ bdst = cpg->bdst; ++ 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 = au_br_mnt(br); ++ au_dtime_store(&dt, parent, &h_path); ++ err = au_do_cpup_wh(cpg, wh_dentry, file); ++ if (unlikely(err)) ++ goto out_wh; ++ ++ dget(wh_dentry); ++ h_path.dentry = wh_dentry; ++ if (!d_is_dir(wh_dentry)) { ++ /* no delegation since it is just created */ ++ err = vfsub_unlink(d_inode(h_parent), &h_path, ++ /*delegated*/NULL, /*force*/0); ++ } else ++ err = vfsub_rmdir(d_inode(h_parent), &h_path); ++ if (unlikely(err)) { ++ AuIOErr("failed remove copied-up tmp file %pd(%d)\n", ++ wh_dentry, err); ++ err = -EIO; ++ } ++ au_dtime_revert(&dt); ++ au_set_hi_wh(d_inode(dentry), bdst, wh_dentry); ++ ++out_wh: ++ dput(wh_dentry); ++out: ++ dput(parent); ++ return err; ++} ++ ++struct au_cpup_wh_args { ++ int *errp; ++ struct au_cp_generic *cpg; ++ struct file *file; ++}; ++ ++static void au_call_cpup_wh(void *args) ++{ ++ struct au_cpup_wh_args *a = args; ++ ++ au_pin_hdir_acquire_nest(a->cpg->pin); ++ *a->errp = au_cpup_wh(a->cpg, a->file); ++ au_pin_hdir_release(a->cpg->pin); ++} ++ ++int au_sio_cpup_wh(struct au_cp_generic *cpg, struct file *file) ++{ ++ int err, wkq_err; ++ aufs_bindex_t bdst; ++ struct dentry *dentry, *parent, *h_orph, *h_parent; ++ struct inode *dir, *h_dir, *h_tmpdir; ++ struct au_wbr *wbr; ++ struct au_pin wh_pin, *pin_orig; ++ ++ dentry = cpg->dentry; ++ bdst = cpg->bdst; ++ parent = dget_parent(dentry); ++ dir = d_inode(parent); ++ h_orph = NULL; ++ h_parent = NULL; ++ h_dir = au_igrab(au_h_iptr(dir, bdst)); ++ h_tmpdir = h_dir; ++ pin_orig = NULL; ++ 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 = d_inode(h_orph); ++ au_set_h_iptr(dir, bdst, au_igrab(h_tmpdir), /*flags*/0); ++ ++ inode_lock_nested(h_tmpdir, AuLsc_I_PARENT3); ++ /* todo: au_h_open_pre()? */ ++ ++ pin_orig = cpg->pin; ++ au_pin_init(&wh_pin, dentry, bdst, AuLsc_DI_PARENT, ++ AuLsc_I_PARENT3, cpg->pin->udba, AuPin_DI_LOCKED); ++ cpg->pin = &wh_pin; ++ } ++ ++ if (!au_test_h_perm_sio(h_tmpdir, MAY_EXEC | MAY_WRITE) ++ && !au_cpup_sio_test(cpg->pin, d_inode(dentry)->i_mode)) ++ err = au_cpup_wh(cpg, file); ++ else { ++ struct au_cpup_wh_args args = { ++ .errp = &err, ++ .cpg = cpg, ++ .file = file ++ }; ++ wkq_err = au_wkq_wait(au_call_cpup_wh, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ if (h_orph) { ++ inode_unlock(h_tmpdir); ++ /* 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); ++ AuDebugOn(!pin_orig); ++ cpg->pin = pin_orig; ++ } ++ 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 au_pin *pin, ++ struct dentry *h_parent, void *arg), ++ void *arg) ++{ ++ int err; ++ struct au_pin pin; ++ struct dentry *d, *parent, *h_parent, *real_parent, *h_dentry; ++ ++ 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 */ ++ h_dentry = au_h_dptr(d, bdst); ++ if (!h_dentry || d_is_negative(h_dentry)) { ++ if (h_dentry) ++ au_update_dbtop(d); ++ ++ au_pin_set_dentry(&pin, d); ++ err = au_do_pin(&pin); ++ if (!err) { ++ err = cp(d, bdst, &pin, 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 au_pin *pin, ++ struct dentry *h_parent __maybe_unused, ++ void *arg __maybe_unused) ++{ ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = bdst, ++ .bsrc = -1, ++ .len = 0, ++ .pin = pin, ++ .flags = AuCpup_DTIME ++ }; ++ return au_sio_cpup_simple(&cpg); ++} ++ ++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 = d_inode(parent); ++ 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 -Nurp linux-5.4/fs/aufs/cpup.h linux-5.4-aufs/fs/aufs/cpup.h +--- linux-5.4/fs/aufs/cpup.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/cpup.h 2019-11-28 01:25:59.063925618 +0200 +@@ -0,0 +1,87 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * copy-up/down functions ++ */ ++ ++#ifndef __AUFS_CPUP_H__ ++#define __AUFS_CPUP_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++struct inode; ++struct file; ++struct au_pin; ++ ++void au_cpup_attr_flags(struct inode *dst, unsigned int iflags); ++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); ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_cp_generic { ++ struct dentry *dentry; ++ aufs_bindex_t bdst, bsrc; ++ loff_t len; ++ struct au_pin *pin; ++ unsigned int flags; ++}; ++ ++/* 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 AuCpup_RENAME (1 << 2) /* rename after cpup */ ++#define AuCpup_HOPEN (1 << 3) /* call h_open_pre/post() in ++ cpup */ ++#define AuCpup_OVERWRITE (1 << 4) /* allow overwriting the ++ existing entry */ ++#define AuCpup_RWDST (1 << 5) /* force write target even if ++ the branch is marked as RO */ ++ ++#ifndef CONFIG_AUFS_BR_HFSPLUS ++#undef AuCpup_HOPEN ++#define AuCpup_HOPEN 0 ++#endif ++ ++#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_simple(struct au_cp_generic *cpg); ++int au_sio_cpdown_simple(struct au_cp_generic *cpg); ++int au_sio_cpup_wh(struct au_cp_generic *cpg, struct file *file); ++ ++int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst, ++ int (*cp)(struct dentry *dentry, aufs_bindex_t bdst, ++ struct au_pin *pin, ++ 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 timespec64 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 -Nurp linux-5.4/fs/aufs/dbgaufs.c linux-5.4-aufs/fs/aufs/dbgaufs.c +--- linux-5.4/fs/aufs/dbgaufs.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/dbgaufs.c 2019-11-28 01:25:59.063925618 +0200 +@@ -0,0 +1,513 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * 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 = 0444; ++ ++/* 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) ++{ ++ void *p; ++ ++ p = file->private_data; ++ if (p) { ++ /* this is struct dbgaufs_arg */ ++ AuDebugOn(!au_kfree_sz_test(p)); ++ au_kfree_do_rcu(p); ++ } ++ return 0; ++} ++ ++static int dbgaufs_xi_open(struct file *xf, struct file *file, int do_fcnt, ++ int cnt) ++{ ++ 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 = vfsub_getattr(&xf->f_path, &st); ++ if (!err) { ++ if (do_fcnt) ++ p->n = snprintf ++ (p->a, sizeof(p->a), "%d, %llux%u %lld\n", ++ cnt, st.blocks, st.blksize, ++ (long long)st.size); ++ else ++ p->n = snprintf(p->a, sizeof(p->a), "%llux%u %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); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dbgaufs_plink_arg { ++ int n; ++ char a[]; ++}; ++ ++static int dbgaufs_plink_release(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ free_page((unsigned long)file->private_data); ++ return 0; ++} ++ ++static int dbgaufs_plink_open(struct inode *inode, struct file *file) ++{ ++ int err, i, limit; ++ unsigned long n, sum; ++ struct dbgaufs_plink_arg *p; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ struct hlist_bl_head *hbl; ++ ++ err = -ENOMEM; ++ p = (void *)get_zeroed_page(GFP_NOFS); ++ if (unlikely(!p)) ++ goto out; ++ ++ err = -EFBIG; ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ if (au_opt_test(au_mntflags(sb), PLINK)) { ++ limit = PAGE_SIZE - sizeof(p->n); ++ ++ /* the number of buckets */ ++ n = snprintf(p->a + p->n, limit, "%d\n", AuPlink_NHASH); ++ p->n += n; ++ limit -= n; ++ ++ sum = 0; ++ for (i = 0, hbl = sbinfo->si_plink; i < AuPlink_NHASH; ++ i++, hbl++) { ++ n = au_hbl_count(hbl); ++ sum += n; ++ ++ n = snprintf(p->a + p->n, limit, "%lu ", n); ++ p->n += n; ++ limit -= n; ++ if (unlikely(limit <= 0)) ++ goto out_free; ++ } ++ p->a[p->n - 1] = '\n'; ++ ++ /* the sum of plinks */ ++ n = snprintf(p->a + p->n, limit, "%lu\n", sum); ++ p->n += n; ++ limit -= n; ++ if (unlikely(limit <= 0)) ++ goto out_free; ++ } else { ++#define str "1\n0\n0\n" ++ p->n = sizeof(str) - 1; ++ strcpy(p->a, str); ++#undef str ++ } ++ si_read_unlock(sb); ++ ++ err = 0; ++ file->private_data = p; ++ goto out; /* success */ ++ ++out_free: ++ free_page((unsigned long)p); ++out: ++ return err; ++} ++ ++static ssize_t dbgaufs_plink_read(struct file *file, char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct dbgaufs_plink_arg *p; ++ ++ p = file->private_data; ++ return simple_read_from_buffer(buf, count, ppos, p->a, p->n); ++} ++ ++static const struct file_operations dbgaufs_plink_fop = { ++ .owner = THIS_MODULE, ++ .open = dbgaufs_plink_open, ++ .release = dbgaufs_plink_release, ++ .read = dbgaufs_plink_read ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++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, /*cnt*/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, idx; ++ long l; ++ aufs_bindex_t bindex; ++ char *p, a[sizeof(DbgaufsXi_PREFIX) + 8]; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ struct au_xino *xi; ++ struct file *xf; ++ struct qstr *name; ++ struct au_branch *br; ++ ++ err = -ENOENT; ++ name = &file->f_path.dentry->d_name; ++ if (unlikely(name->len < sizeof(DbgaufsXi_PREFIX) ++ || memcmp(name->name, DbgaufsXi_PREFIX, ++ sizeof(DbgaufsXi_PREFIX) - 1))) ++ goto out; ++ ++ AuDebugOn(name->len >= sizeof(a)); ++ memcpy(a, name->name, name->len); ++ a[name->len] = '\0'; ++ p = strchr(a, '-'); ++ if (p) ++ *p = '\0'; ++ err = kstrtol(a + sizeof(DbgaufsXi_PREFIX) - 1, 10, &l); ++ if (unlikely(err)) ++ goto out; ++ bindex = l; ++ idx = 0; ++ if (p) { ++ err = kstrtol(p + 1, 10, &l); ++ if (unlikely(err)) ++ goto out; ++ idx = l; ++ } ++ ++ err = -ENOENT; ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ if (unlikely(bindex < 0 || bindex > au_sbbot(sb))) ++ goto out_si; ++ br = au_sbr(sb, bindex); ++ xi = br->br_xino; ++ if (unlikely(idx >= xi->xi_nfile)) ++ goto out_si; ++ xf = au_xino_file(xi, idx); ++ if (xf) ++ err = dbgaufs_xi_open(xf, file, /*do_fcnt*/1, ++ au_xino_count(br)); ++ ++out_si: ++ si_read_unlock(sb); ++out: ++ AuTraceErr(err); ++ 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_xino_del(struct au_branch *br) ++{ ++ struct dentry *dbgaufs; ++ ++ dbgaufs = br->br_dbgaufs; ++ if (!dbgaufs) ++ return; ++ ++ br->br_dbgaufs = NULL; ++ /* debugfs acquires the parent i_mutex */ ++ lockdep_off(); ++ debugfs_remove(dbgaufs); ++ lockdep_on(); ++} ++ ++void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ aufs_bindex_t bbot; ++ struct au_branch *br; ++ ++ if (!au_sbi(sb)->si_dbgaufs) ++ return; ++ ++ bbot = au_sbbot(sb); ++ for (; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ dbgaufs_xino_del(br); ++ } ++} ++ ++static void dbgaufs_br_do_add(struct super_block *sb, aufs_bindex_t bindex, ++ unsigned int idx, struct dentry *parent, ++ struct au_sbinfo *sbinfo) ++{ ++ struct au_branch *br; ++ struct dentry *d; ++ /* "xi" bindex(5) "-" idx(2) NULL */ ++ char name[sizeof(DbgaufsXi_PREFIX) + 8]; ++ ++ if (!idx) ++ snprintf(name, sizeof(name), DbgaufsXi_PREFIX "%d", bindex); ++ else ++ snprintf(name, sizeof(name), DbgaufsXi_PREFIX "%d-%u", ++ bindex, idx); ++ br = au_sbr(sb, bindex); ++ if (br->br_dbgaufs) { ++ struct qstr qstr = QSTR_INIT(name, strlen(name)); ++ ++ if (!au_qstreq(&br->br_dbgaufs->d_name, &qstr)) { ++ /* debugfs acquires the parent i_mutex */ ++ lockdep_off(); ++ d = debugfs_rename(parent, br->br_dbgaufs, parent, ++ name); ++ lockdep_on(); ++ if (unlikely(!d)) ++ pr_warn("failed renaming %pd/%s, ignored.\n", ++ parent, name); ++ } ++ } else { ++ lockdep_off(); ++ br->br_dbgaufs = debugfs_create_file(name, dbgaufs_mode, parent, ++ sbinfo, &dbgaufs_xino_fop); ++ lockdep_on(); ++ if (unlikely(!br->br_dbgaufs)) ++ pr_warn("failed creating %pd/%s, ignored.\n", ++ parent, name); ++ } ++} ++ ++static void dbgaufs_br_add(struct super_block *sb, aufs_bindex_t bindex, ++ struct dentry *parent, struct au_sbinfo *sbinfo) ++{ ++ struct au_branch *br; ++ struct au_xino *xi; ++ unsigned int u; ++ ++ br = au_sbr(sb, bindex); ++ xi = br->br_xino; ++ for (u = 0; u < xi->xi_nfile; u++) ++ dbgaufs_br_do_add(sb, bindex, u, parent, sbinfo); ++} ++ ++void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex, int topdown) ++{ ++ struct au_sbinfo *sbinfo; ++ struct dentry *parent; ++ aufs_bindex_t bbot; ++ ++ if (!au_opt_test(au_mntflags(sb), XINO)) ++ return; ++ ++ sbinfo = au_sbi(sb); ++ parent = sbinfo->si_dbgaufs; ++ if (!parent) ++ return; ++ ++ bbot = au_sbbot(sb); ++ if (topdown) ++ for (; bindex <= bbot; bindex++) ++ dbgaufs_br_add(sb, bindex, parent, sbinfo); ++ else ++ for (; bbot >= bindex; bbot--) ++ dbgaufs_br_add(sb, bbot, parent, sbinfo); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#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, /*cnt*/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' function 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 '__fin' function actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++ ++ debugfs_remove_recursive(sbinfo->si_dbgaufs); ++ sbinfo->si_dbgaufs = NULL; ++} ++ ++int dbgaufs_si_init(struct au_sbinfo *sbinfo) ++{ ++ int err; ++ char name[SysaufsSiNameLen]; ++ ++ /* ++ * This function is a dynamic '__init' function 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; ++ ++ /* regardless plink/noplink option */ ++ sbinfo->si_dbgaufs_plink = debugfs_create_file ++ ("plink", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, ++ &dbgaufs_plink_fop); ++ if (unlikely(!sbinfo->si_dbgaufs_plink)) ++ goto out_dir; ++ ++ /* regardless xino/noxino option */ ++ 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: ++ if (unlikely(err)) ++ pr_err("debugfs/aufs failed\n"); ++ 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 -Nurp linux-5.4/fs/aufs/dbgaufs.h linux-5.4-aufs/fs/aufs/dbgaufs.h +--- linux-5.4/fs/aufs/dbgaufs.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/dbgaufs.h 2019-11-28 01:25:59.063925618 +0200 +@@ -0,0 +1,40 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * debugfs interface ++ */ ++ ++#ifndef __DBGAUFS_H__ ++#define __DBGAUFS_H__ ++ ++#ifdef __KERNEL__ ++ ++struct super_block; ++struct au_sbinfo; ++struct au_branch; ++ ++#ifdef CONFIG_DEBUG_FS ++/* dbgaufs.c */ ++void dbgaufs_xino_del(struct au_branch *br); ++void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex); ++void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex, int topdown); ++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_xino_del, struct au_branch *br) ++AuStubVoid(dbgaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex) ++AuStubVoid(dbgaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex, ++ int topdown) ++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 -Nurp linux-5.4/fs/aufs/dcsub.c linux-5.4-aufs/fs/aufs/dcsub.c +--- linux-5.4/fs/aufs/dcsub.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/dcsub.c 2019-11-28 01:25:59.063925618 +0200 +@@ -0,0 +1,212 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * 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: ++ au_kfree_try_rcu(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++); ++ au_kfree_try_rcu(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, ++ /*may_shrink*/0); ++ 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(au_dcount(dentry) <= 0); ++ dpage->dentries[dpage->ndentry++] = dget_dlock(dentry); ++ return 0; /* success */ ++ ++out: ++ return err; ++} ++ ++/* todo: BAD approach */ ++/* copied from linux/fs/dcache.c */ ++enum d_walk_ret { ++ D_WALK_CONTINUE, ++ D_WALK_QUIT, ++ D_WALK_NORETRY, ++ D_WALK_SKIP, ++}; ++ ++extern void d_walk(struct dentry *parent, void *data, ++ enum d_walk_ret (*enter)(void *, struct dentry *)); ++ ++struct ac_dpages_arg { ++ int err; ++ struct au_dcsub_pages *dpages; ++ struct super_block *sb; ++ au_dpages_test test; ++ void *arg; ++}; ++ ++static enum d_walk_ret au_call_dpages_append(void *_arg, struct dentry *dentry) ++{ ++ enum d_walk_ret ret; ++ struct ac_dpages_arg *arg = _arg; ++ ++ ret = D_WALK_CONTINUE; ++ if (dentry->d_sb == arg->sb ++ && !IS_ROOT(dentry) ++ && au_dcount(dentry) > 0 ++ && au_di(dentry) ++ && (!arg->test || arg->test(dentry, arg->arg))) { ++ arg->err = au_dpages_append(arg->dpages, dentry, GFP_ATOMIC); ++ if (unlikely(arg->err)) ++ ret = D_WALK_QUIT; ++ } ++ ++ return ret; ++} ++ ++int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, ++ au_dpages_test test, void *arg) ++{ ++ struct ac_dpages_arg args = { ++ .err = 0, ++ .dpages = dpages, ++ .sb = root->d_sb, ++ .test = test, ++ .arg = arg ++ }; ++ ++ d_walk(root, &args, au_call_dpages_append); ++ ++ return args.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 ++ && au_dcount(dentry) > 0 ++ && (!test || test(dentry, arg))) ++ err = au_dpages_append(dpages, dentry, GFP_ATOMIC); ++ spin_unlock(&dentry->d_lock); ++ if (unlikely(err)) ++ goto out; ++ ++ /* ++ * RCU for vfsmount 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 (au_dcount(dentry) > 0 ++ && (!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 -Nurp linux-5.4/fs/aufs/dcsub.h linux-5.4-aufs/fs/aufs/dcsub.h +--- linux-5.4/fs/aufs/dcsub.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/dcsub.h 2019-11-28 01:25:59.063925618 +0200 +@@ -0,0 +1,124 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * sub-routines for dentry cache ++ */ ++ ++#ifndef __AUFS_DCSUB_H__ ++#define __AUFS_DCSUB_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++ ++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); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * todo: in linux-3.13, several similar (but faster) helpers are added to ++ * include/linux/dcache.h. Try them (in the future). ++ */ ++ ++static inline int au_d_hashed_positive(struct dentry *d) ++{ ++ int err; ++ struct inode *inode = d_inode(d); ++ ++ err = 0; ++ if (unlikely(d_unhashed(d) ++ || d_is_negative(d) ++ || !inode->i_nlink)) ++ err = -ENOENT; ++ return err; ++} ++ ++static inline int au_d_linkable(struct dentry *d) ++{ ++ int err; ++ struct inode *inode = d_inode(d); ++ ++ err = au_d_hashed_positive(d); ++ if (err ++ && d_is_positive(d) ++ && (inode->i_state & I_LINKABLE)) ++ err = 0; ++ 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_inode(d); ++ if (unlikely(d_unlinked(d) ++ || d_is_negative(d) ++ || !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_inode(d)))) ++ err = -ENOENT; ++ return err; ++} ++ ++static inline int au_qstreq(struct qstr *a, struct qstr *b) ++{ ++ return a->len == b->len ++ && !memcmp(a->name, b->name, a->len); ++} ++ ++/* ++ * by the commit ++ * 360f547 2015-01-25 dcache: let the dentry count go down to zero without ++ * taking d_lock ++ * the type of d_lockref.count became int, but the inlined function d_count() ++ * still returns unsigned int. ++ * I don't know why. Maybe it is for every d_count() users? ++ * Anyway au_dcount() lives on. ++ */ ++static inline int au_dcount(struct dentry *d) ++{ ++ return (int)d_count(d); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DCSUB_H__ */ +diff -Nurp linux-5.4/fs/aufs/debug.c linux-5.4-aufs/fs/aufs/debug.c +--- linux-5.4/fs/aufs/debug.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/debug.c 2019-11-28 01:25:59.063925618 +0200 +@@ -0,0 +1,428 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * debug print functions ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* Returns 0, or -errno. arg is in kp->arg. */ ++static int param_atomic_t_set(const char *val, const struct kernel_param *kp) ++{ ++ int err, n; ++ ++ err = kstrtoint(val, 0, &n); ++ if (!err) { ++ if (n > 0) ++ au_debug_on(); ++ else ++ au_debug_off(); ++ } ++ return err; ++} ++ ++/* Returns length written or -errno. Buffer is 4k (ie. be short!) */ ++static int param_atomic_t_get(char *buffer, const struct kernel_param *kp) ++{ ++ atomic_t *a; ++ ++ a = kp->arg; ++ return sprintf(buffer, "%d", atomic_read(a)); ++} ++ ++static struct kernel_param_ops param_ops_atomic_t = { ++ .set = param_atomic_t_set, ++ .get = param_atomic_t_get ++ /* void (*free)(void *arg) */ ++}; ++ ++atomic_t aufs_debug = ATOMIC_INIT(0); ++MODULE_PARM_DESC(debug, "debug print"); ++module_param_named(debug, aufs_debug, atomic_t, 0664); ++ ++DEFINE_MUTEX(au_dbg_mtx); /* just to serialize the dbg msgs */ ++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 *pos; ++ ++ n = whlist->nh_num; ++ head = whlist->nh_head; ++ for (ul = 0; ul < n; ul++) { ++ hlist_for_each_entry(pos, head, wh_hash) ++ dpri("b%d, %.*s, %d\n", ++ pos->wh_bindex, ++ pos->wh_str.len, pos->wh_str.name, ++ pos->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 %llu\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_LBDAF */ ++ 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)timespec64_to_ns(&inode->i_ctime) & 0x0ffff, ++ inode->i_mapping ? inode->i_mapping->nrpages : 0, ++ inode->i_state, inode->i_flags, inode_peek_iversion(inode), ++ inode->i_generation, ++ l ? ", wh " : "", l, n); ++ return 0; ++} ++ ++void au_dpri_inode(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ struct au_hinode *hi; ++ aufs_bindex_t bindex; ++ int err, hn; ++ ++ err = do_pri_inode(-1, inode, -1, NULL); ++ if (err || !au_test_aufs(inode->i_sb) || au_is_bad_inode(inode)) ++ return; ++ ++ iinfo = au_ii(inode); ++ dpri("i-1: btop %d, bbot %d, gen %d\n", ++ iinfo->ii_btop, iinfo->ii_bbot, au_iigen(inode, NULL)); ++ if (iinfo->ii_btop < 0) ++ return; ++ hn = 0; ++ for (bindex = iinfo->ii_btop; bindex <= iinfo->ii_bbot; bindex++) { ++ hi = au_hinode(iinfo, bindex); ++ hn = !!au_hn(hi); ++ do_pri_inode(bindex, hi->hi_inode, hn, hi->hi_whdentry); ++ } ++} ++ ++void au_dpri_dalias(struct inode *inode) ++{ ++ struct dentry *d; ++ ++ spin_lock(&inode->i_lock); ++ hlist_for_each_entry(d, &inode->i_dentry, d_u.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; ++ struct inode *inode; ++ struct au_iinfo *iinfo; ++ struct au_hinode *hi; ++ ++ 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: %p, %pd2?, %s, cnt %d, flags 0x%x, %shashed\n", ++ bindex, dentry, dentry, ++ dentry->d_sb ? au_sbtype(dentry->d_sb) : "??", ++ au_dcount(dentry), dentry->d_flags, ++ d_unhashed(dentry) ? "un" : ""); ++ hn = -1; ++ inode = NULL; ++ if (d_is_positive(dentry)) ++ inode = d_inode(dentry); ++ if (inode ++ && au_test_aufs(dentry->d_sb) ++ && bindex >= 0 ++ && !au_is_bad_inode(inode)) { ++ iinfo = au_ii(inode); ++ hi = au_hinode(iinfo, bindex); ++ hn = !!au_hn(hi); ++ wh = hi->hi_whdentry; ++ } ++ do_pri_inode(bindex, inode, hn, wh); ++ return 0; ++} ++ ++void au_dpri_dentry(struct dentry *dentry) ++{ ++ struct au_dinfo *dinfo; ++ aufs_bindex_t bindex; ++ int err; ++ ++ 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: btop %d, bbot %d, bwh %d, bdiropq %d, gen %d, tmp %d\n", ++ dinfo->di_btop, dinfo->di_bbot, ++ dinfo->di_bwh, dinfo->di_bdiropq, au_digen(dentry), ++ dinfo->di_tmpfile); ++ if (dinfo->di_btop < 0) ++ return; ++ for (bindex = dinfo->di_btop; bindex <= dinfo->di_bbot; bindex++) ++ do_pri_dentry(bindex, au_hdentry(dinfo, 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 ++ && !IS_ERR_OR_NULL(file->f_path.dentry) ++ && au_test_aufs(file->f_path.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 (!IS_ERR_OR_NULL(file->f_path.dentry)) ++ do_pri_dentry(bindex, file->f_path.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 ++ || IS_ERR_OR_NULL(file->f_path.dentry) ++ || !au_test_aufs(file->f_path.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 = au_br_mnt(br); ++ 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, wbr %p}, " ++ "%s, dev 0x%02x%02x, flags 0x%lx, cnt %d, active %d, " ++ "xino %d\n", ++ bindex, br->br_perm, br->br_id, 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), ++ !!au_xino_file(br->br_xino, /*idx*/-1)); ++ 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 reduce 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_path.mnt = &a->mnt; ++ err = do_pri_br(-1, &a->fake); ++ au_kfree_rcu(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, ++ kref_read(&sbinfo->si_kobj.kref)); ++ for (bindex = 0; bindex <= sbinfo->si_bbot; bindex++) ++ do_pri_br(bindex, sbinfo->si_branch[0 + bindex]); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line) ++{ ++ struct inode *h_inode, *inode = d_inode(dentry); ++ struct dentry *h_dentry; ++ aufs_bindex_t bindex, bbot, bi; ++ ++ if (!inode /* || au_di(dentry)->di_lsc == AuLsc_DI_TMP */) ++ return; ++ ++ bbot = au_dbbot(dentry); ++ bi = au_ibbot(inode); ++ if (bi < bbot) ++ bbot = bi; ++ bindex = au_dbtop(dentry); ++ bi = au_ibtop(inode); ++ if (bi > bindex) ++ bindex = bi; ++ ++ for (; bindex <= bbot; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ h_inode = au_h_iptr(inode, bindex); ++ if (unlikely(h_inode != d_inode(h_dentry))) { ++ au_debug_on(); ++ AuDbg("b%d, %s:%d\n", bindex, func, line); ++ AuDbgDentry(dentry); ++ AuDbgInode(inode); ++ au_debug_off(); ++ BUG(); ++ } ++ } ++} ++ ++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); */ ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++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 ++ ++ return 0; ++} +diff -Nurp linux-5.4/fs/aufs/debug.h linux-5.4-aufs/fs/aufs/debug.h +--- linux-5.4/fs/aufs/debug.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/debug.h 2019-11-28 01:25:59.063925618 +0200 +@@ -0,0 +1,213 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * debug print functions ++ */ ++ ++#ifndef __AUFS_DEBUG_H__ ++#define __AUFS_DEBUG_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_AUFS_DEBUG ++#define AuDebugOn(a) BUG_ON(a) ++ ++/* module parameter */ ++extern atomic_t aufs_debug; ++static inline void au_debug_on(void) ++{ ++ atomic_inc(&aufs_debug); ++} ++static inline void au_debug_off(void) ++{ ++ atomic_dec_if_positive(&aufs_debug); ++} ++ ++static inline int au_debug_test(void) ++{ ++ return atomic_read(&aufs_debug) > 0; ++} ++#else ++#define AuDebugOn(a) do {} while (0) ++AuStubVoid(au_debug_on, void) ++AuStubVoid(au_debug_off, void) ++AuStubInt0(au_debug_test, void) ++#endif /* CONFIG_AUFS_DEBUG */ ++ ++#define param_check_atomic_t(name, p) __param_check(name, p, atomic_t) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* 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 ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dentry; ++#ifdef CONFIG_AUFS_DEBUG ++extern struct mutex au_dbg_mtx; ++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); ++ ++#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_gen(struct dentry *parent, unsigned int sigen); ++void au_dbg_verify_kthread(void); ++ ++int __init au_debug_init(void); ++ ++#define AuDbgWhlist(w) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#w "\n"); \ ++ au_dpri_whlist(w); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgVdir(v) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#v "\n"); \ ++ au_dpri_vdir(v); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgInode(i) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#i "\n"); \ ++ au_dpri_inode(i); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgDAlias(i) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#i "\n"); \ ++ au_dpri_dalias(i); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgDentry(d) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#d "\n"); \ ++ au_dpri_dentry(d); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgFile(f) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#f "\n"); \ ++ au_dpri_file(f); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgSb(sb) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#sb "\n"); \ ++ au_dpri_sb(sb); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgSym(addr) do { \ ++ char sym[KSYM_SYMBOL_LEN]; \ ++ sprint_symbol(sym, (unsigned long)addr); \ ++ AuDbg("%s\n", sym); \ ++} while (0) ++#else ++AuStubVoid(au_dbg_verify_dinode, struct dentry *dentry) ++AuStubVoid(au_dbg_verify_gen, struct dentry *parent, unsigned int sigen) ++AuStubVoid(au_dbg_verify_kthread, void) ++AuStubInt0(__init au_debug_init, void) ++ ++#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 AuDbgSym(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 -Nurp linux-5.4/fs/aufs/dentry.c linux-5.4-aufs/fs/aufs/dentry.c +--- linux-5.4/fs/aufs/dentry.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/dentry.c 2019-11-28 01:25:59.063925618 +0200 +@@ -0,0 +1,1141 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * lookup and dentry operations ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++/* ++ * 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 au_do_lookup_args *args) ++{ ++ struct dentry *h_dentry; ++ struct inode *h_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); ++ const unsigned char ignore_perm = !!au_ftest_lkup(args->flags, ++ IGNORE_PERM); ++ ++ 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, &args->whname, ignore_perm); ++ 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_dbbot(dentry, bindex); */ ++ au_set_dbwh(dentry, bindex); ++ if (!allow_neg) ++ return NULL; /* success */ ++ ++real_lookup: ++ if (!ignore_perm) ++ h_dentry = vfsub_lkup_one(args->name, h_parent); ++ else ++ h_dentry = au_sio_lkup_one(args->name, h_parent); ++ if (IS_ERR(h_dentry)) { ++ if (PTR_ERR(h_dentry) == -ENAMETOOLONG ++ && !allow_neg) ++ h_dentry = NULL; ++ goto out; ++ } ++ ++ h_inode = d_inode(h_dentry); ++ if (d_is_negative(h_dentry)) { ++ if (!allow_neg) ++ goto out_neg; ++ } else if (wh_found ++ || (args->type && args->type != (h_inode->i_mode & S_IFMT))) ++ goto out_neg; ++ else if (au_ftest_lkup(args->flags, DIRREN) ++ /* && h_inode */ ++ && !au_dr_lkup_h_ino(args, bindex, h_inode->i_ino)) { ++ AuDbg("b%d %pd ignored hi%llu\n", bindex, h_dentry, ++ (unsigned long long)h_inode->i_ino); ++ goto out_neg; ++ } ++ ++ if (au_dbbot(dentry) <= bindex) ++ au_set_dbbot(dentry, bindex); ++ if (au_dbtop(dentry) < 0 || bindex < au_dbtop(dentry)) ++ au_set_dbtop(dentry, bindex); ++ au_set_h_dptr(dentry, bindex, h_dentry); ++ ++ if (!d_is_dir(h_dentry) ++ || !wh_able ++ || (d_really_is_positive(dentry) && !d_is_dir(dentry))) ++ goto out; /* success */ ++ ++ inode_lock_shared_nested(h_inode, AuLsc_I_CHILD); ++ opq = au_diropq_test(h_dentry); ++ inode_unlock_shared(h_inode); ++ 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 btop, ++ unsigned int flags) ++{ ++ int npositive, err; ++ aufs_bindex_t bindex, btail, bdiropq; ++ unsigned char isdir, dirperm1, dirren; ++ struct au_do_lookup_args args = { ++ .flags = flags, ++ .name = &dentry->d_name ++ }; ++ struct dentry *parent; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ err = au_test_shwh(sb, args.name); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_wh_name_alloc(&args.whname, args.name); ++ if (unlikely(err)) ++ goto out; ++ ++ isdir = !!d_is_dir(dentry); ++ dirperm1 = !!au_opt_test(au_mntflags(sb), DIRPERM1); ++ dirren = !!au_opt_test(au_mntflags(sb), DIRREN); ++ if (dirren) ++ au_fset_lkup(args.flags, DIRREN); ++ ++ npositive = 0; ++ parent = dget_parent(dentry); ++ btail = au_dbtaildir(parent); ++ for (bindex = btop; bindex <= btail; bindex++) { ++ struct dentry *h_parent, *h_dentry; ++ struct inode *h_inode, *h_dir; ++ struct au_branch *br; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry) { ++ if (d_is_positive(h_dentry)) ++ npositive++; ++ break; ++ } ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || !d_is_dir(h_parent)) ++ continue; ++ ++ if (dirren) { ++ /* if the inum matches, then use the prepared name */ ++ err = au_dr_lkup_name(&args, bindex); ++ if (unlikely(err)) ++ goto out_parent; ++ } ++ ++ h_dir = d_inode(h_parent); ++ inode_lock_shared_nested(h_dir, AuLsc_I_PARENT); ++ h_dentry = au_do_lookup(h_parent, dentry, bindex, &args); ++ inode_unlock_shared(h_dir); ++ err = PTR_ERR(h_dentry); ++ if (IS_ERR(h_dentry)) ++ goto out_parent; ++ if (h_dentry) ++ au_fclr_lkup(args.flags, ALLOW_NEG); ++ if (dirperm1) ++ au_fset_lkup(args.flags, IGNORE_PERM); ++ ++ if (au_dbwh(dentry) == bindex) ++ break; ++ if (!h_dentry) ++ continue; ++ if (d_is_negative(h_dentry)) ++ continue; ++ h_inode = d_inode(h_dentry); ++ 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; ++ } ++ br = au_sbr(sb, bindex); ++ if (dirren ++ && au_dr_hino_test_add(&br->br_dirren, h_inode->i_ino, ++ /*add_ent*/NULL)) { ++ /* prepare next name to lookup */ ++ err = au_dr_lkup(&args, dentry, bindex); ++ if (unlikely(err)) ++ goto out_parent; ++ } ++ } ++ ++ if (npositive) { ++ AuLabel(positive); ++ au_update_dbtop(dentry); ++ } ++ err = npositive; ++ if (unlikely(!au_opt_test(au_mntflags(sb), UDBA_NONE) ++ && au_dbtop(dentry) < 0)) { ++ err = -EIO; ++ AuIOErr("both of real entry and whiteout found, %pd, err %d\n", ++ dentry, err); ++ } ++ ++out_parent: ++ dput(parent); ++ au_kfree_try_rcu(args.whname.name); ++ if (dirren) ++ au_dr_lkup_fin(&args); ++out: ++ return err; ++} ++ ++struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent) ++{ ++ struct dentry *dentry; ++ int wkq_err; ++ ++ if (!au_test_h_perm_sio(d_inode(parent), 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 wh) ++{ ++ int err; ++ struct dentry *parent, *h_parent, *h_dentry; ++ struct au_branch *br; ++ ++ parent = dget_parent(dentry); ++ h_parent = au_h_dptr(parent, bindex); ++ br = au_sbr(dentry->d_sb, bindex); ++ if (wh) ++ h_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name); ++ else ++ h_dentry = au_sio_lkup_one(&dentry->d_name, h_parent); ++ err = PTR_ERR(h_dentry); ++ if (IS_ERR(h_dentry)) ++ goto out; ++ if (unlikely(d_is_positive(h_dentry))) { ++ err = -EIO; ++ AuIOErr("%pd should be negative on b%d.\n", h_dentry, bindex); ++ dput(h_dentry); ++ goto out; ++ } ++ ++ err = 0; ++ if (bindex < au_dbtop(dentry)) ++ au_set_dbtop(dentry, bindex); ++ if (au_dbbot(dentry) < bindex) ++ au_set_dbbot(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 = inode_query_iversion(h_inode); ++/* ++ 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) ++ || !inode_eq_iversion(h_inode, ia->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 = NULL; ++ if (d_is_positive(h_dentry)) { ++ h_inode = d_inode(h_dentry); ++ 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 ++ || d_inode(h_d) != 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 = (d_inode(h_dentry->d_parent) != 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, bbot, 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); ++ bbot = dinfo->di_bbot; ++ bwh = dinfo->di_bwh; ++ bdiropq = dinfo->di_bdiropq; ++ bindex = dinfo->di_btop; ++ p = au_hdentry(dinfo, bindex); ++ for (; bindex <= bbot; 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 = au_hdentry(dinfo, new_bindex); ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hd_dentry) { ++ bindex--; ++ p--; ++ } ++ } ++ ++ dinfo->di_bwh = -1; ++ if (bwh >= 0 && bwh <= au_sbbot(sb) && au_sbr_whable(sb, bwh)) ++ dinfo->di_bwh = bwh; ++ ++ dinfo->di_bdiropq = -1; ++ if (bdiropq >= 0 ++ && bdiropq <= au_sbbot(sb) ++ && au_sbr_whable(sb, bdiropq)) ++ dinfo->di_bdiropq = bdiropq; ++ ++ err = -EIO; ++ dinfo->di_btop = -1; ++ dinfo->di_bbot = -1; ++ bbot = au_dbbot(parent); ++ bindex = 0; ++ p = au_hdentry(dinfo, bindex); ++ for (; bindex <= bbot; bindex++, p++) ++ if (p->hd_dentry) { ++ dinfo->di_btop = bindex; ++ break; ++ } ++ ++ if (dinfo->di_btop >= 0) { ++ bindex = bbot; ++ p = au_hdentry(dinfo, bindex); ++ for (; bindex >= 0; bindex--, p--) ++ if (p->hd_dentry) { ++ dinfo->di_bbot = bindex; ++ err = 0; ++ break; ++ } ++ } ++ ++ return err; ++} ++ ++static void au_do_hide(struct dentry *dentry) ++{ ++ struct inode *inode; ++ ++ if (d_really_is_positive(dentry)) { ++ inode = d_inode(dentry); ++ if (!d_is_dir(dentry)) { ++ 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; ++ ++ AuDbgDentry(dentry); ++ if (d_is_dir(dentry)) { ++ /* shrink_dcache_parent(dentry); */ ++ err = au_hide_children(dentry); ++ if (unlikely(err)) ++ AuIOErr("%pd, failed hiding children, ignored %d\n", ++ 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, bbot; ++ struct { ++ struct dentry *dentry; ++ struct inode *inode; ++ mode_t mode; ++ } orig_h, tmp_h = { ++ .dentry = NULL ++ }; ++ struct au_hdentry *hd; ++ struct inode *inode, *h_inode; ++ struct dentry *h_dentry; ++ ++ err = 0; ++ AuDebugOn(dinfo->di_btop < 0); ++ orig_h.mode = 0; ++ orig_h.dentry = au_hdentry(dinfo, dinfo->di_btop)->hd_dentry; ++ orig_h.inode = NULL; ++ if (d_is_positive(orig_h.dentry)) { ++ orig_h.inode = d_inode(orig_h.dentry); ++ orig_h.mode = orig_h.inode->i_mode & S_IFMT; ++ } ++ if (tmp->di_btop >= 0) { ++ tmp_h.dentry = au_hdentry(tmp, tmp->di_btop)->hd_dentry; ++ if (d_is_positive(tmp_h.dentry)) { ++ tmp_h.inode = d_inode(tmp_h.dentry); ++ tmp_h.mode = tmp_h.inode->i_mode & S_IFMT; ++ } ++ } ++ ++ inode = NULL; ++ if (d_really_is_positive(dentry)) ++ inode = d_inode(dentry); ++ if (!orig_h.inode) { ++ AuDbg("negative originally\n"); ++ if (inode) { ++ au_hide(dentry); ++ goto out; ++ } ++ AuDebugOn(inode); ++ AuDebugOn(dinfo->di_btop != dinfo->di_bbot); ++ AuDebugOn(dinfo->di_bdiropq != -1); ++ ++ if (!tmp_h.inode) { ++ AuDbg("negative --> negative\n"); ++ /* should have only one negative lower */ ++ if (tmp->di_btop >= 0 ++ && tmp->di_btop < dinfo->di_btop) { ++ AuDebugOn(tmp->di_btop != tmp->di_bbot); ++ AuDebugOn(dinfo->di_btop != dinfo->di_bbot); ++ au_set_h_dptr(dentry, dinfo->di_btop, NULL); ++ au_di_cp(dinfo, tmp); ++ hd = au_hdentry(tmp, tmp->di_btop); ++ au_set_h_dptr(dentry, tmp->di_btop, ++ 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_btop) ++ 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_btop > tmp->di_btop) { ++ /* ++ * 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_btop > tmp->di_btop) ++ dinfo->di_btop = tmp->di_btop; ++ if (dinfo->di_bbot < tmp->di_bbot) ++ dinfo->di_bbot = tmp->di_bbot; ++ dinfo->di_bwh = tmp->di_bwh; ++ dinfo->di_bdiropq = tmp->di_bdiropq; ++ bbot = dinfo->di_bbot; ++ bindex = tmp->di_btop; ++ hd = au_hdentry(tmp, bindex); ++ for (; bindex <= bbot; bindex++, hd++) { ++ if (au_h_dptr(dentry, bindex)) ++ continue; ++ h_dentry = hd->hd_dentry; ++ if (!h_dentry) ++ continue; ++ AuDebugOn(d_is_negative(h_dentry)); ++ h_inode = d_inode(h_dentry); ++ AuDebugOn(orig_h.mode ++ != (h_inode->i_mode ++ & S_IFMT)); ++ au_set_h_dptr(dentry, bindex, ++ dget(h_dentry)); ++ } ++ if (inode) ++ 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; ++} ++ ++void au_refresh_dop(struct dentry *dentry, int force_reval) ++{ ++ const struct dentry_operations *dop ++ = force_reval ? &aufs_dop : dentry->d_sb->s_d_op; ++ static const unsigned int mask ++ = DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE; ++ ++ BUILD_BUG_ON(sizeof(mask) != sizeof(dentry->d_flags)); ++ ++ if (dentry->d_op == dop) ++ return; ++ ++ AuDbg("%pd\n", dentry); ++ spin_lock(&dentry->d_lock); ++ if (dop == &aufs_dop) ++ dentry->d_flags |= mask; ++ else ++ dentry->d_flags &= ~mask; ++ dentry->d_op = dop; ++ spin_unlock(&dentry->d_lock); ++} ++ ++int au_refresh_dentry(struct dentry *dentry, struct dentry *parent) ++{ ++ int err, ebrange, nbr; ++ unsigned int sigen; ++ struct au_dinfo *dinfo, *tmp; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ DiMustWriteLock(dentry); ++ AuDebugOn(IS_ROOT(dentry)); ++ AuDebugOn(d_really_is_negative(parent)); ++ ++ sb = dentry->d_sb; ++ sigen = au_sigen(sb); ++ err = au_digen_test(parent, sigen); ++ if (unlikely(err)) ++ goto out; ++ ++ nbr = au_sbbot(sb) + 1; ++ dinfo = au_di(dentry); ++ err = au_di_realloc(dinfo, nbr, /*may_shrink*/0); ++ if (unlikely(err)) ++ goto out; ++ ebrange = au_dbrange_test(dentry); ++ if (!ebrange) ++ ebrange = au_do_refresh_hdentry(dentry, parent); ++ ++ if (d_unhashed(dentry) || ebrange /* || dinfo->di_tmpfile */) { ++ AuDebugOn(au_dbtop(dentry) < 0 && au_dbbot(dentry) >= 0); ++ if (d_really_is_positive(dentry)) { ++ inode = d_inode(dentry); ++ 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, /*btop*/0, AuLkup_ALLOW_NEG); ++ 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_di_realloc(dinfo, nbr, /*may_shrink*/1); /* harmless if 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 %pd, %d\n", 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 dirren) ++{ ++ int err; ++ umode_t mode, h_mode; ++ aufs_bindex_t bindex, btail, btop, ibs, ibe; ++ unsigned char plus, unhashed, is_root, h_plus, h_nfs, tmpfile; ++ 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; ++ tmpfile = au_di(dentry)->di_tmpfile; ++ ++ /* ++ * 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 ++ * Let's do REVAL test too. ++ */ ++ if (do_udba && inode) { ++ mode = (inode->i_mode & S_IFMT); ++ plus = (inode->i_nlink > 0); ++ ibs = au_ibtop(inode); ++ ibe = au_ibbot(inode); ++ } ++ ++ btop = au_dbtop(dentry); ++ btail = btop; ++ if (inode && S_ISDIR(inode->i_mode)) ++ btail = au_dbtaildir(dentry); ++ for (bindex = btop; bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ ++ AuDbg("b%d, %pd\n", bindex, h_dentry); ++ h_nfs = !!au_test_nfs(h_dentry->d_sb); ++ spin_lock(&h_dentry->d_lock); ++ h_name = &h_dentry->d_name; ++ if (unlikely(do_udba ++ && !is_root ++ && ((!h_nfs ++ && (unhashed != !!d_unhashed(h_dentry) ++ || (!tmpfile && !dirren ++ && !au_qstreq(name, h_name)) ++ )) ++ || (h_nfs ++ && !(flags & LOOKUP_OPEN) ++ && (h_dentry->d_flags ++ & DCACHE_NFSFS_RENAMED))) ++ )) { ++ int h_unhashed; ++ ++ h_unhashed = d_unhashed(h_dentry); ++ spin_unlock(&h_dentry->d_lock); ++ AuDbg("unhash 0x%x 0x%x, %pd %pd\n", ++ unhashed, h_unhashed, dentry, h_dentry); ++ 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 */ ++ if (unlikely(!!inode != d_is_positive(h_dentry))) ++ goto err; ++ ++ h_inode = NULL; ++ if (d_is_positive(h_dentry)) ++ h_inode = d_inode(h_dentry); ++ 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 (!h_nfs) { ++ if (unlikely(plus != h_plus && !tmpfile)) ++ goto err; ++ } else { ++ if (unlikely(!(h_dentry->d_flags & DCACHE_NFSFS_RENAMED) ++ && !is_root ++ && !IS_ROOT(h_dentry) ++ && unhashed != d_unhashed(h_dentry))) ++ goto err; ++ } ++ if (unlikely(mode != h_mode ++ || h_cached_inode != h_inode)) ++ goto err; ++ continue; ++ ++err: ++ err = -EINVAL; ++ break; ++ } ++ ++ AuTraceErr(err); ++ 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; ++ ++ 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; ++ } ++ ++ 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, dirren; ++ 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; ++ ++ 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; ++ } ++ inode = NULL; ++ if (d_really_is_positive(dentry)) ++ inode = d_inode(dentry); ++ if (unlikely(inode && au_is_bad_inode(inode))) { ++ err = -EINVAL; ++ AuTraceErr(err); ++ goto out_dgrade; ++ } ++ 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 (!(flags & (LOOKUP_OPEN | LOOKUP_EMPTY)) ++ && inode ++ && !(inode->i_state && I_LINKABLE) ++ && (IS_DEADDIR(inode) || !inode->i_nlink)) { ++ AuTraceErr(err); ++ goto out_inval; ++ } ++ ++ do_udba = !au_opt_test(au_mntflags(sb), UDBA_NONE); ++ if (do_udba && inode) { ++ aufs_bindex_t btop = au_ibtop(inode); ++ struct inode *h_inode; ++ ++ if (btop >= 0) { ++ h_inode = au_h_iptr(inode, btop); ++ if (h_inode && au_test_higen(inode, h_inode)) { ++ AuTraceErr(err); ++ goto out_inval; ++ } ++ } ++ } ++ ++ dirren = !!au_opt_test(au_mntflags(sb), DIRREN); ++ err = h_d_revalidate(dentry, inode, flags, do_udba, dirren); ++ if (unlikely(!err && do_udba && au_dbtop(dentry) < 0)) { ++ err = -EIO; ++ AuDbg("both of real entry and whiteout found, %p, err %d\n", ++ 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("%pd invalid, %d\n", 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_weak_revalidate = aufs_d_revalidate, ++ .d_release = aufs_d_release ++}; ++ ++/* aufs_dop without d_revalidate */ ++const struct dentry_operations aufs_dop_noreval = { ++ .d_release = aufs_d_release ++}; +diff -Nurp linux-5.4/fs/aufs/dentry.h linux-5.4-aufs/fs/aufs/dentry.h +--- linux-5.4/fs/aufs/dentry.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/dentry.h 2019-11-28 01:25:59.063925618 +0200 +@@ -0,0 +1,255 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * lookup and dentry operations ++ */ ++ ++#ifndef __AUFS_DENTRY_H__ ++#define __AUFS_DENTRY_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "dirren.h" ++#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_btop, di_bbot, di_bwh, di_bdiropq; ++ unsigned char di_tmpfile; /* to allow the different name */ ++ struct au_hdentry *di_hdentry; ++ struct rcu_head rcu; ++} ____cacheline_aligned_in_smp; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* flags for au_lkup_dentry() */ ++#define AuLkup_ALLOW_NEG 1 ++#define AuLkup_IGNORE_PERM (1 << 1) ++#define AuLkup_DIRREN (1 << 2) ++#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) ++ ++#ifndef CONFIG_AUFS_DIRREN ++#undef AuLkup_DIRREN ++#define AuLkup_DIRREN 0 ++#endif ++ ++struct au_do_lookup_args { ++ unsigned int flags; ++ mode_t type; ++ struct qstr whname, *name; ++ struct au_dr_lookup dirren; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dentry.c */ ++extern const struct dentry_operations aufs_dop, aufs_dop_noreval; ++struct au_branch; ++struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent); ++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 btop, ++ unsigned int flags); ++int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex, int wh); ++int au_refresh_dentry(struct dentry *dentry, struct dentry *parent); ++int au_reval_dpath(struct dentry *dentry, unsigned int sigen); ++void au_refresh_dop(struct dentry *dentry, int force_reval); ++ ++/* 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, int may_shrink); ++ ++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_dbtop(struct dentry *dentry); ++void au_update_dbbot(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 struct au_hdentry *au_hdentry(struct au_dinfo *di, ++ aufs_bindex_t bindex) ++{ ++ return di->di_hdentry + bindex; ++} ++ ++static inline void au_hdput(struct au_hdentry *hd) ++{ ++ if (hd) ++ dput(hd->hd_dentry); ++} ++ ++static inline aufs_bindex_t au_dbtop(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_btop; ++} ++ ++static inline aufs_bindex_t au_dbbot(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_bbot; ++} ++ ++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_dbtop(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ au_di(dentry)->di_btop = bindex; ++} ++ ++static inline void au_set_dbbot(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ au_di(dentry)->di_bbot = bindex; ++} ++ ++static inline void au_set_dbwh(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ /* dbwh can be outside of btop - bbot 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 -Nurp linux-5.4/fs/aufs/dinfo.c linux-5.4-aufs/fs/aufs/dinfo.c +--- linux-5.4/fs/aufs/dinfo.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/dinfo.c 2019-11-28 01:25:59.063925618 +0200 +@@ -0,0 +1,541 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * dentry private data ++ */ ++ ++#include "aufs.h" ++ ++void au_di_init_once(void *_dinfo) ++{ ++ struct au_dinfo *dinfo = _dinfo; ++ ++ au_rw_init(&dinfo->di_rwsem); ++} ++ ++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_sbbot(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_btop = -1; ++ dinfo->di_bbot = -1; ++ dinfo->di_bwh = -1; ++ dinfo->di_bdiropq = -1; ++ dinfo->di_tmpfile = 0; ++ 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 bbot, bindex; ++ ++ /* dentry may not be revalidated */ ++ bindex = dinfo->di_btop; ++ if (bindex >= 0) { ++ bbot = dinfo->di_bbot; ++ p = au_hdentry(dinfo, bindex); ++ while (bindex++ <= bbot) ++ au_hdput(p++); ++ } ++ au_kfree_try_rcu(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, btop); ++ DiSwap(bi, bbot); ++ 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_btop = src->di_btop; ++ dst->di_bbot = src->di_bbot; ++ 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 may_shrink) ++{ ++ int err, sz; ++ struct au_hdentry *hdp; ++ ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ err = -ENOMEM; ++ sz = sizeof(*hdp) * (dinfo->di_bbot + 1); ++ if (!sz) ++ sz = sizeof(*hdp); ++ hdp = au_kzrealloc(dinfo->di_hdentry, sz, sizeof(*hdp) * nbr, GFP_NOFS, ++ may_shrink); ++ 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) ++{ ++ struct inode *inode; ++ ++ au_rw_read_lock_nested(&au_di(d)->di_rwsem, lsc); ++ if (d_really_is_positive(d)) { ++ inode = d_inode(d); ++ if (au_ftest_lock(flags, IW)) ++ do_ii_write_lock(inode, lsc); ++ else if (au_ftest_lock(flags, IR)) ++ do_ii_read_lock(inode, lsc); ++ } ++} ++ ++void di_read_unlock(struct dentry *d, int flags) ++{ ++ struct inode *inode; ++ ++ if (d_really_is_positive(d)) { ++ inode = d_inode(d); ++ if (au_ftest_lock(flags, IW)) { ++ au_dbg_verify_dinode(d); ++ ii_write_unlock(inode); ++ } else if (au_ftest_lock(flags, IR)) { ++ au_dbg_verify_dinode(d); ++ ii_read_unlock(inode); ++ } ++ } ++ au_rw_read_unlock(&au_di(d)->di_rwsem); ++} ++ ++void di_downgrade_lock(struct dentry *d, int flags) ++{ ++ if (d_really_is_positive(d) && au_ftest_lock(flags, IR)) ++ ii_downgrade_lock(d_inode(d)); ++ 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_really_is_positive(d)) ++ do_ii_write_lock(d_inode(d), lsc); ++} ++ ++void di_write_unlock(struct dentry *d) ++{ ++ au_dbg_verify_dinode(d); ++ if (d_really_is_positive(d)) ++ ii_write_unlock(d_inode(d)); ++ 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 ++ || d_inode(d1) == d_inode(d2) ++ || d1->d_sb != d2->d_sb); ++ ++ if ((isdir && au_test_subdir(d1, d2)) ++ || d1 < d2) { ++ di_write_lock_child(d1); ++ di_write_lock_child2(d2); ++ } else { ++ 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 ++ || d_inode(d1) == d_inode(d2) ++ || d1->d_sb != d2->d_sb); ++ ++ if ((isdir && au_test_subdir(d1, d2)) ++ || d1 < d2) { ++ di_write_lock_parent(d1); ++ di_write_lock_parent2(d2); ++ } else { ++ 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 (d_inode(d1) == d_inode(d2)) ++ 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_dbtop(dentry) < 0 || bindex < au_dbtop(dentry)) ++ return NULL; ++ AuDebugOn(bindex < 0); ++ d = au_hdentry(au_di(dentry), bindex)->hd_dentry; ++ AuDebugOn(d && au_dcount(d) <= 0); ++ return d; ++} ++ ++/* ++ * extended version of au_h_dptr(). ++ * returns a hashed and positive (or linkable) 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; ++ ++ AuDebugOn(d_really_is_negative(dentry)); ++ ++ h_dentry = NULL; ++ if (au_dbtop(dentry) <= bindex ++ && bindex <= au_dbbot(dentry)) ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && !au_d_linkable(h_dentry)) { ++ dget(h_dentry); ++ goto out; /* success */ ++ } ++ ++ inode = d_inode(dentry); ++ AuDebugOn(bindex < au_ibtop(inode)); ++ AuDebugOn(au_ibbot(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_linkable(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 bbot, bwh; ++ ++ bbot = au_dbbot(dentry); ++ if (0 <= bbot) { ++ bwh = au_dbwh(dentry); ++ if (!bwh) ++ return bwh; ++ if (0 < bwh && bwh < bbot) ++ return bwh - 1; ++ } ++ return bbot; ++} ++ ++aufs_bindex_t au_dbtaildir(struct dentry *dentry) ++{ ++ aufs_bindex_t bbot, bopq; ++ ++ bbot = au_dbtail(dentry); ++ if (0 <= bbot) { ++ bopq = au_dbdiropq(dentry); ++ if (0 <= bopq && bopq < bbot) ++ bbot = bopq; ++ } ++ return bbot; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_dentry) ++{ ++ struct au_dinfo *dinfo; ++ struct au_hdentry *hd; ++ struct au_branch *br; ++ ++ DiMustWriteLock(dentry); ++ ++ dinfo = au_di(dentry); ++ hd = au_hdentry(dinfo, bindex); ++ 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 btop, bbot; ++ ++ err = 0; ++ btop = au_dbtop(dentry); ++ bbot = au_dbbot(dentry); ++ if (btop >= 0) ++ AuDebugOn(bbot < 0 && btop > bbot); ++ else { ++ err = -EIO; ++ AuDebugOn(bbot >= 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(d_inode(dentry), 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; ++ aufs_bindex_t bindex, bbot; ++ ++ DiMustWriteLock(dentry); ++ ++ dinfo = au_di(dentry); ++ if (!dinfo || dinfo->di_btop < 0) ++ return; ++ ++ if (do_put_zero) { ++ bbot = dinfo->di_bbot; ++ bindex = dinfo->di_btop; ++ hdp = au_hdentry(dinfo, bindex); ++ for (; bindex <= bbot; bindex++, hdp++) { ++ h_d = hdp->hd_dentry; ++ if (h_d && d_is_negative(h_d)) ++ au_set_h_dptr(dentry, bindex, NULL); ++ } ++ } ++ ++ dinfo->di_btop = 0; ++ hdp = au_hdentry(dinfo, dinfo->di_btop); ++ for (; dinfo->di_btop <= dinfo->di_bbot; dinfo->di_btop++, hdp++) ++ if (hdp->hd_dentry) ++ break; ++ if (dinfo->di_btop > dinfo->di_bbot) { ++ dinfo->di_btop = -1; ++ dinfo->di_bbot = -1; ++ return; ++ } ++ ++ hdp = au_hdentry(dinfo, dinfo->di_bbot); ++ for (; dinfo->di_bbot >= 0; dinfo->di_bbot--, hdp--) ++ if (hdp->hd_dentry) ++ break; ++ AuDebugOn(dinfo->di_btop > dinfo->di_bbot || dinfo->di_bbot < 0); ++} ++ ++void au_update_dbtop(struct dentry *dentry) ++{ ++ aufs_bindex_t bindex, bbot; ++ struct dentry *h_dentry; ++ ++ bbot = au_dbbot(dentry); ++ for (bindex = au_dbtop(dentry); bindex <= bbot; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ if (d_is_positive(h_dentry)) { ++ au_set_dbtop(dentry, bindex); ++ return; ++ } ++ au_set_h_dptr(dentry, bindex, NULL); ++ } ++} ++ ++void au_update_dbbot(struct dentry *dentry) ++{ ++ aufs_bindex_t bindex, btop; ++ struct dentry *h_dentry; ++ ++ btop = au_dbtop(dentry); ++ for (bindex = au_dbbot(dentry); bindex >= btop; bindex--) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ if (d_is_positive(h_dentry)) { ++ au_set_dbbot(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, bbot; ++ ++ bbot = au_dbbot(dentry); ++ for (bindex = au_dbtop(dentry); bindex <= bbot; bindex++) ++ if (au_h_dptr(dentry, bindex) == h_dentry) ++ return bindex; ++ return -1; ++} +diff -Nurp linux-5.4/fs/aufs/dir.c linux-5.4-aufs/fs/aufs/dir.c +--- linux-5.4/fs/aufs/dir.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/dir.c 2019-11-28 01:25:59.064925618 +0200 +@@ -0,0 +1,750 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * directory operations ++ */ ++ ++#include ++#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; ++ smp_mb(); /* for i_nlink */ ++ /* 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; ++ smp_mb(); /* for i_nlink */ ++ /* 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, bbot; ++ struct file *h_file; ++ struct dentry *h_dentry; ++ ++ sz = 0; ++ if (file) { ++ AuDebugOn(!d_is_dir(file->f_path.dentry)); ++ ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); ++ bindex <= bbot && sz < KMALLOC_MAX_SIZE; ++ bindex++) { ++ h_file = au_hf_dir(file, bindex); ++ if (h_file && file_inode(h_file)) ++ sz += vfsub_f_size_read(h_file); ++ } ++ } else { ++ AuDebugOn(!dentry); ++ AuDebugOn(!d_is_dir(dentry)); ++ ++ bbot = au_dbtaildir(dentry); ++ for (bindex = au_dbtop(dentry); ++ bindex <= bbot && sz < KMALLOC_MAX_SIZE; ++ bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && d_is_positive(h_dentry)) ++ sz += i_size_read(d_inode(h_dentry)); ++ } ++ } ++ 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; ++} ++ ++struct au_dir_ts_arg { ++ struct dentry *dentry; ++ aufs_bindex_t brid; ++}; ++ ++static void au_do_dir_ts(void *arg) ++{ ++ struct au_dir_ts_arg *a = arg; ++ struct au_dtime dt; ++ struct path h_path; ++ struct inode *dir, *h_dir; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_hinode *hdir; ++ int err; ++ aufs_bindex_t btop, bindex; ++ ++ sb = a->dentry->d_sb; ++ if (d_really_is_negative(a->dentry)) ++ goto out; ++ /* no dir->i_mutex lock */ ++ aufs_read_lock(a->dentry, AuLock_DW); /* noflush */ ++ ++ dir = d_inode(a->dentry); ++ btop = au_ibtop(dir); ++ bindex = au_br_index(sb, a->brid); ++ if (bindex < btop) ++ goto out_unlock; ++ ++ br = au_sbr(sb, bindex); ++ h_path.dentry = au_h_dptr(a->dentry, bindex); ++ if (!h_path.dentry) ++ goto out_unlock; ++ h_path.mnt = au_br_mnt(br); ++ au_dtime_store(&dt, a->dentry, &h_path); ++ ++ br = au_sbr(sb, btop); ++ if (!au_br_writable(br->br_perm)) ++ goto out_unlock; ++ h_path.dentry = au_h_dptr(a->dentry, btop); ++ h_path.mnt = au_br_mnt(br); ++ err = vfsub_mnt_want_write(h_path.mnt); ++ if (err) ++ goto out_unlock; ++ hdir = au_hi(dir, btop); ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ h_dir = au_h_iptr(dir, btop); ++ if (h_dir->i_nlink ++ && timespec64_compare(&h_dir->i_mtime, &dt.dt_mtime) < 0) { ++ dt.dt_h_path = h_path; ++ au_dtime_revert(&dt); ++ } ++ au_hn_inode_unlock(hdir); ++ vfsub_mnt_drop_write(h_path.mnt); ++ au_cpup_attr_timesizes(dir); ++ ++out_unlock: ++ aufs_read_unlock(a->dentry, AuLock_DW); ++out: ++ dput(a->dentry); ++ au_nwt_done(&au_sbi(sb)->si_nowait); ++ au_kfree_try_rcu(arg); ++} ++ ++void au_dir_ts(struct inode *dir, aufs_bindex_t bindex) ++{ ++ int perm, wkq_err; ++ aufs_bindex_t btop; ++ struct au_dir_ts_arg *arg; ++ struct dentry *dentry; ++ struct super_block *sb; ++ ++ IMustLock(dir); ++ ++ dentry = d_find_any_alias(dir); ++ AuDebugOn(!dentry); ++ sb = dentry->d_sb; ++ btop = au_ibtop(dir); ++ if (btop == bindex) { ++ au_cpup_attr_timesizes(dir); ++ goto out; ++ } ++ ++ perm = au_sbr_perm(sb, btop); ++ if (!au_br_writable(perm)) ++ goto out; ++ ++ arg = kmalloc(sizeof(*arg), GFP_NOFS); ++ if (!arg) ++ goto out; ++ ++ arg->dentry = dget(dentry); /* will be dput-ted by au_do_dir_ts() */ ++ arg->brid = au_sbr_id(sb, bindex); ++ wkq_err = au_wkq_nowait(au_do_dir_ts, arg, sb, /*flags*/0); ++ if (unlikely(wkq_err)) { ++ pr_err("wkq %d\n", wkq_err); ++ dput(dentry); ++ au_kfree_try_rcu(arg); ++ } ++ ++out: ++ dput(dentry); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int reopen_dir(struct file *file) ++{ ++ int err; ++ unsigned int flags; ++ aufs_bindex_t bindex, btail, btop; ++ struct dentry *dentry, *h_dentry; ++ struct file *h_file; ++ ++ /* open all lower dirs */ ++ dentry = file->f_path.dentry; ++ btop = au_dbtop(dentry); ++ for (bindex = au_fbtop(file); bindex < btop; bindex++) ++ au_set_h_fptr(file, bindex, NULL); ++ au_set_fbtop(file, btop); ++ ++ btail = au_dbtaildir(dentry); ++ for (bindex = au_fbbot_dir(file); btail < bindex; bindex--) ++ au_set_h_fptr(file, bindex, NULL); ++ au_set_fbbot_dir(file, btail); ++ ++ flags = vfsub_file_flags(file); ++ for (bindex = btop; 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, /*force_wr*/0); ++ 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, struct file *h_file) ++{ ++ int err; ++ aufs_bindex_t bindex, btail; ++ struct dentry *dentry, *h_dentry; ++ struct vfsmount *mnt; ++ ++ FiMustWriteLock(file); ++ AuDebugOn(h_file); ++ ++ err = 0; ++ mnt = file->f_path.mnt; ++ dentry = file->f_path.dentry; ++ file->f_version = inode_query_iversion(d_inode(dentry)); ++ bindex = au_dbtop(dentry); ++ au_set_fbtop(file, bindex); ++ btail = au_dbtaildir(dentry); ++ au_set_fbbot_dir(file, btail); ++ for (; !err && bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ ++ err = vfsub_test_mntns(mnt, h_dentry->d_sb); ++ if (unlikely(err)) ++ break; ++ h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0); ++ 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_fbtop(file); bindex <= btail; bindex++) ++ au_set_h_fptr(file, bindex, NULL); ++ au_set_fbtop(file, -1); ++ au_set_fbbot_dir(file, -1); ++ ++ 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_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ fidir = au_fidir_alloc(sb); ++ if (fidir) { ++ struct au_do_open_args args = { ++ .open = do_open_dir, ++ .fidir = fidir ++ }; ++ err = au_do_open(file, &args); ++ if (unlikely(err)) ++ au_kfree_rcu(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; ++ struct au_hfile *hf; ++ aufs_bindex_t bindex, bbot; ++ ++ finfo = au_fi(file); ++ fidir = finfo->fi_hdir; ++ if (fidir) { ++ au_hbl_del(&finfo->fi_hlist, ++ &au_sbi(file->f_path.dentry->d_sb)->si_files); ++ vdir_cache = fidir->fd_vdir_cache; /* lock-free */ ++ if (vdir_cache) ++ au_vdir_free(vdir_cache); ++ ++ bindex = finfo->fi_btop; ++ if (bindex >= 0) { ++ hf = fidir->fd_hfile + bindex; ++ /* ++ * calls fput() instead of filp_close(), ++ * since no dnotify or lock for the lower file. ++ */ ++ bbot = fidir->fd_bbot; ++ for (; bindex <= bbot; bindex++, hf++) ++ if (hf->hf_file) ++ au_hfput(hf, /*execed*/0); ++ } ++ au_kfree_rcu(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, bbot; ++ struct file *h_file; ++ ++ err = 0; ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); !err && bindex <= bbot; 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 bbot, bindex; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ bbot = au_dbbot(dentry); ++ for (bindex = au_dbtop(dentry); !err && bindex <= bbot; 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 bbot, bindex; ++ struct file *h_file; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1, /*fi_lsc*/0); ++ if (unlikely(err)) ++ goto out; ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); !err && bindex <= bbot; 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 inode *inode; ++ struct super_block *sb; ++ ++ err = 0; ++ dentry = file->f_path.dentry; ++ inode = d_inode(dentry); ++ inode_lock(inode); ++ 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(inode); ++ di_write_unlock(dentry); ++ if (file) ++ fi_write_unlock(file); ++ ++ si_read_unlock(sb); ++ inode_unlock(inode); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_iterate_shared(struct file *file, struct dir_context *ctx) ++{ ++ int err; ++ struct dentry *dentry; ++ struct inode *inode, *h_inode; ++ struct super_block *sb; ++ ++ AuDbg("%pD, ctx{%ps, %llu}\n", file, ctx->actor, ctx->pos); ++ ++ dentry = file->f_path.dentry; ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ ++ sb = dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1, /*fi_lsc*/0); ++ 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_ibtop(inode)); ++ if (!au_test_nfsd()) { ++ err = au_vdir_fill_de(file, ctx); ++ 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, ctx); ++ 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 dir_context ctx; ++ struct au_nhash *whlist; ++ unsigned int flags; ++ int err; ++ aufs_bindex_t bindex; ++}; ++ ++static int test_empty_cb(struct dir_context *ctx, const char *__name, ++ int namelen, loff_t offset __maybe_unused, u64 ino, ++ unsigned int d_type) ++{ ++ struct test_empty_arg *arg = container_of(ctx, struct test_empty_arg, ++ ctx); ++ 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; ++ struct au_branch *br; ++ ++ h_file = au_h_open(dentry, arg->bindex, ++ O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_LARGEFILE, ++ /*file*/NULL, /*force_wr*/0); ++ 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) ++ && !file_inode(h_file)->i_nlink) ++ goto out_put; ++ ++ do { ++ arg->err = 0; ++ au_fclr_testempty(arg->flags, CALLED); ++ /* smp_mb(); */ ++ err = vfsub_iterate_dir(h_file, &arg->ctx); ++ if (err >= 0) ++ err = arg->err; ++ } while (!err && au_ftest_testempty(arg->flags, CALLED)); ++ ++out_put: ++ fput(h_file); ++ br = au_sbr(dentry->d_sb, arg->bindex); ++ au_lcnt_dec(&br->br_nfiles); ++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 = d_inode(h_dentry); ++ /* todo: i_mode changes anytime? */ ++ inode_lock_shared_nested(h_inode, AuLsc_I_CHILD); ++ err = au_test_h_perm_sio(h_inode, MAY_EXEC | MAY_READ); ++ inode_unlock_shared(h_inode); ++ 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, btop, btail; ++ struct au_nhash whlist; ++ struct test_empty_arg arg = { ++ .ctx = { ++ .actor = test_empty_cb ++ } ++ }; ++ int (*test_empty)(struct dentry *dentry, 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; ++ btop = au_dbtop(dentry); ++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)) ++ au_fset_testempty(arg.flags, SHWH); ++ test_empty = do_test_empty; ++ if (au_opt_test(au_mntflags(dentry->d_sb), DIRPERM1)) ++ test_empty = sio_test_empty; ++ arg.bindex = btop; ++ err = test_empty(dentry, &arg); ++ if (unlikely(err)) ++ goto out_whlist; ++ ++ au_fset_testempty(arg.flags, WHONLY); ++ btail = au_dbtaildir(dentry); ++ for (bindex = btop + 1; !err && bindex <= btail; bindex++) { ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && d_is_positive(h_dentry)) { ++ arg.bindex = bindex; ++ err = 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 = { ++ .ctx = { ++ .actor = test_empty_cb ++ } ++ }; ++ 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_dbtop(dentry); !err && bindex <= btail; bindex++) { ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && d_is_positive(h_dentry)) { ++ 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, ++ .iterate_shared = aufs_iterate_shared, ++ .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 -Nurp linux-5.4/fs/aufs/dir.h linux-5.4-aufs/fs/aufs/dir.h +--- linux-5.4/fs/aufs/dir.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/dir.h 2019-11-28 01:25:59.064925618 +0200 +@@ -0,0 +1,121 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * 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; ++ struct rcu_head rcu; ++} ____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; ++ ++ u64 vd_version; ++ unsigned int vd_deblk_sz; ++ unsigned long vd_jiffy; ++ struct rcu_head rcu; ++} ____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); ++void au_dir_ts(struct inode *dir, aufs_bindex_t bsrc); ++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, struct dir_context *ctx); ++ ++/* 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 ++AuStub(long, au_rdu_ioctl, return -EINVAL, struct file *file, ++ unsigned int cmd, unsigned long arg) ++#ifdef CONFIG_COMPAT ++AuStub(long, au_rdu_compat_ioctl, return -EINVAL, struct file *file, ++ unsigned int cmd, unsigned long arg) ++#endif ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DIR_H__ */ +diff -Nurp linux-5.4/fs/aufs/dirren.c linux-5.4-aufs/fs/aufs/dirren.c +--- linux-5.4/fs/aufs/dirren.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/dirren.c 2019-11-28 01:25:59.064925618 +0200 +@@ -0,0 +1,1303 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2017-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * special handling in renaming a directory ++ * in order to support looking-up the before-renamed name on the lower readonly ++ * branches ++ */ ++ ++#include ++#include "aufs.h" ++ ++static void au_dr_hino_del(struct au_dr_br *dr, struct au_dr_hino *ent) ++{ ++ int idx; ++ ++ idx = au_dr_ihash(ent->dr_h_ino); ++ au_hbl_del(&ent->dr_hnode, dr->dr_h_ino + idx); ++} ++ ++static int au_dr_hino_test_empty(struct au_dr_br *dr) ++{ ++ int ret, i; ++ struct hlist_bl_head *hbl; ++ ++ ret = 1; ++ for (i = 0; ret && i < AuDirren_NHASH; i++) { ++ hbl = dr->dr_h_ino + i; ++ hlist_bl_lock(hbl); ++ ret &= hlist_bl_empty(hbl); ++ hlist_bl_unlock(hbl); ++ } ++ ++ return ret; ++} ++ ++static struct au_dr_hino *au_dr_hino_find(struct au_dr_br *dr, ino_t ino) ++{ ++ struct au_dr_hino *found, *ent; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ int idx; ++ ++ found = NULL; ++ idx = au_dr_ihash(ino); ++ hbl = dr->dr_h_ino + idx; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(ent, pos, hbl, dr_hnode) ++ if (ent->dr_h_ino == ino) { ++ found = ent; ++ break; ++ } ++ hlist_bl_unlock(hbl); ++ ++ return found; ++} ++ ++int au_dr_hino_test_add(struct au_dr_br *dr, ino_t ino, ++ struct au_dr_hino *add_ent) ++{ ++ int found, idx; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_dr_hino *ent; ++ ++ found = 0; ++ idx = au_dr_ihash(ino); ++ hbl = dr->dr_h_ino + idx; ++#if 0 ++ { ++ struct hlist_bl_node *tmp; ++ ++ hlist_bl_for_each_entry_safe(ent, pos, tmp, hbl, dr_hnode) ++ AuDbg("hi%llu\n", (unsigned long long)ent->dr_h_ino); ++ } ++#endif ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(ent, pos, hbl, dr_hnode) ++ if (ent->dr_h_ino == ino) { ++ found = 1; ++ break; ++ } ++ if (!found && add_ent) ++ hlist_bl_add_head(&add_ent->dr_hnode, hbl); ++ hlist_bl_unlock(hbl); ++ ++ if (!found && add_ent) ++ AuDbg("i%llu added\n", (unsigned long long)add_ent->dr_h_ino); ++ ++ return found; ++} ++ ++void au_dr_hino_free(struct au_dr_br *dr) ++{ ++ int i; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos, *tmp; ++ struct au_dr_hino *ent; ++ ++ /* SiMustWriteLock(sb); */ ++ ++ for (i = 0; i < AuDirren_NHASH; i++) { ++ hbl = dr->dr_h_ino + i; ++ /* no spinlock since sbinfo must be write-locked */ ++ hlist_bl_for_each_entry_safe(ent, pos, tmp, hbl, dr_hnode) ++ au_kfree_rcu(ent); ++ INIT_HLIST_BL_HEAD(hbl); ++ } ++} ++ ++/* returns the number of inodes or an error */ ++static int au_dr_hino_store(struct super_block *sb, struct au_branch *br, ++ struct file *hinofile) ++{ ++ int err, i; ++ ssize_t ssz; ++ loff_t pos, oldsize; ++ __be64 u64; ++ struct inode *hinoinode; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *n1, *n2; ++ struct au_dr_hino *ent; ++ ++ SiMustWriteLock(sb); ++ AuDebugOn(!au_br_writable(br->br_perm)); ++ ++ hinoinode = file_inode(hinofile); ++ oldsize = i_size_read(hinoinode); ++ ++ err = 0; ++ pos = 0; ++ hbl = br->br_dirren.dr_h_ino; ++ for (i = 0; !err && i < AuDirren_NHASH; i++, hbl++) { ++ /* no bit-lock since sbinfo must be write-locked */ ++ hlist_bl_for_each_entry_safe(ent, n1, n2, hbl, dr_hnode) { ++ AuDbg("hi%llu, %pD2\n", ++ (unsigned long long)ent->dr_h_ino, hinofile); ++ u64 = cpu_to_be64(ent->dr_h_ino); ++ ssz = vfsub_write_k(hinofile, &u64, sizeof(u64), &pos); ++ if (ssz == sizeof(u64)) ++ continue; ++ ++ /* write error */ ++ pr_err("ssz %zd, %pD2\n", ssz, hinofile); ++ err = -ENOSPC; ++ if (ssz < 0) ++ err = ssz; ++ break; ++ } ++ } ++ /* regardless the error */ ++ if (pos < oldsize) { ++ err = vfsub_trunc(&hinofile->f_path, pos, /*attr*/0, hinofile); ++ AuTraceErr(err); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_dr_hino_load(struct au_dr_br *dr, struct file *hinofile) ++{ ++ int err, hidx; ++ ssize_t ssz; ++ size_t sz, n; ++ loff_t pos; ++ uint64_t u64; ++ struct au_dr_hino *ent; ++ struct inode *hinoinode; ++ struct hlist_bl_head *hbl; ++ ++ err = 0; ++ pos = 0; ++ hbl = dr->dr_h_ino; ++ hinoinode = file_inode(hinofile); ++ sz = i_size_read(hinoinode); ++ AuDebugOn(sz % sizeof(u64)); ++ n = sz / sizeof(u64); ++ while (n--) { ++ ssz = vfsub_read_k(hinofile, &u64, sizeof(u64), &pos); ++ if (unlikely(ssz != sizeof(u64))) { ++ pr_err("ssz %zd, %pD2\n", ssz, hinofile); ++ err = -EINVAL; ++ if (ssz < 0) ++ err = ssz; ++ goto out_free; ++ } ++ ++ ent = kmalloc(sizeof(*ent), GFP_NOFS); ++ if (!ent) { ++ err = -ENOMEM; ++ AuTraceErr(err); ++ goto out_free; ++ } ++ ent->dr_h_ino = be64_to_cpu((__force __be64)u64); ++ AuDbg("hi%llu, %pD2\n", ++ (unsigned long long)ent->dr_h_ino, hinofile); ++ hidx = au_dr_ihash(ent->dr_h_ino); ++ au_hbl_add(&ent->dr_hnode, hbl + hidx); ++ } ++ goto out; /* success */ ++ ++out_free: ++ au_dr_hino_free(dr); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * @bindex/@br is a switch to distinguish whether suspending hnotify or not. ++ * @path is a switch to distinguish load and store. ++ */ ++static int au_dr_hino(struct super_block *sb, aufs_bindex_t bindex, ++ struct au_branch *br, const struct path *path) ++{ ++ int err, flags; ++ unsigned char load, suspend; ++ struct file *hinofile; ++ struct au_hinode *hdir; ++ struct inode *dir, *delegated; ++ struct path hinopath; ++ struct qstr hinoname = QSTR_INIT(AUFS_WH_DR_BRHINO, ++ sizeof(AUFS_WH_DR_BRHINO) - 1); ++ ++ AuDebugOn(bindex < 0 && !br); ++ AuDebugOn(bindex >= 0 && br); ++ ++ err = -EINVAL; ++ suspend = !br; ++ if (suspend) ++ br = au_sbr(sb, bindex); ++ load = !!path; ++ if (!load) { ++ path = &br->br_path; ++ AuDebugOn(!au_br_writable(br->br_perm)); ++ if (unlikely(!au_br_writable(br->br_perm))) ++ goto out; ++ } ++ ++ hdir = NULL; ++ if (suspend) { ++ dir = d_inode(sb->s_root); ++ hdir = au_hinode(au_ii(dir), bindex); ++ dir = hdir->hi_inode; ++ au_hn_inode_lock_nested(hdir, AuLsc_I_CHILD); ++ } else { ++ dir = d_inode(path->dentry); ++ inode_lock_nested(dir, AuLsc_I_CHILD); ++ } ++ hinopath.dentry = vfsub_lkup_one(&hinoname, path->dentry); ++ err = PTR_ERR(hinopath.dentry); ++ if (IS_ERR(hinopath.dentry)) ++ goto out_unlock; ++ ++ err = 0; ++ flags = O_RDONLY; ++ if (load) { ++ if (d_is_negative(hinopath.dentry)) ++ goto out_dput; /* success */ ++ } else { ++ if (au_dr_hino_test_empty(&br->br_dirren)) { ++ if (d_is_positive(hinopath.dentry)) { ++ delegated = NULL; ++ err = vfsub_unlink(dir, &hinopath, &delegated, ++ /*force*/0); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ pr_err("ignored err %d, %pd2\n", ++ err, hinopath.dentry); ++ if (unlikely(err == -EWOULDBLOCK)) ++ iput(delegated); ++ err = 0; ++ } ++ goto out_dput; ++ } else if (!d_is_positive(hinopath.dentry)) { ++ err = vfsub_create(dir, &hinopath, 0600, ++ /*want_excl*/false); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out_dput; ++ } ++ flags = O_WRONLY; ++ } ++ hinopath.mnt = path->mnt; ++ hinofile = vfsub_dentry_open(&hinopath, flags); ++ if (suspend) ++ au_hn_inode_unlock(hdir); ++ else ++ inode_unlock(dir); ++ dput(hinopath.dentry); ++ AuTraceErrPtr(hinofile); ++ if (IS_ERR(hinofile)) { ++ err = PTR_ERR(hinofile); ++ goto out; ++ } ++ ++ if (load) ++ err = au_dr_hino_load(&br->br_dirren, hinofile); ++ else ++ err = au_dr_hino_store(sb, br, hinofile); ++ fput(hinofile); ++ goto out; ++ ++out_dput: ++ dput(hinopath.dentry); ++out_unlock: ++ if (suspend) ++ au_hn_inode_unlock(hdir); ++ else ++ inode_unlock(dir); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_dr_brid_init(struct au_dr_brid *brid, const struct path *path) ++{ ++ int err; ++ struct kstatfs kstfs; ++ dev_t dev; ++ struct dentry *dentry; ++ struct super_block *sb; ++ ++ err = vfs_statfs((void *)path, &kstfs); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out; ++ ++ /* todo: support for UUID */ ++ ++ if (kstfs.f_fsid.val[0] || kstfs.f_fsid.val[1]) { ++ brid->type = AuBrid_FSID; ++ brid->fsid = kstfs.f_fsid; ++ } else { ++ dentry = path->dentry; ++ sb = dentry->d_sb; ++ dev = sb->s_dev; ++ if (dev) { ++ brid->type = AuBrid_DEV; ++ brid->dev = dev; ++ } ++ } ++ ++out: ++ return err; ++} ++ ++int au_dr_br_init(struct super_block *sb, struct au_branch *br, ++ const struct path *path) ++{ ++ int err, i; ++ struct au_dr_br *dr; ++ struct hlist_bl_head *hbl; ++ ++ dr = &br->br_dirren; ++ hbl = dr->dr_h_ino; ++ for (i = 0; i < AuDirren_NHASH; i++, hbl++) ++ INIT_HLIST_BL_HEAD(hbl); ++ ++ err = au_dr_brid_init(&dr->dr_brid, path); ++ if (unlikely(err)) ++ goto out; ++ ++ if (au_opt_test(au_mntflags(sb), DIRREN)) ++ err = au_dr_hino(sb, /*bindex*/-1, br, path); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_dr_br_fin(struct super_block *sb, struct au_branch *br) ++{ ++ int err; ++ ++ err = 0; ++ if (au_br_writable(br->br_perm)) ++ err = au_dr_hino(sb, /*bindex*/-1, br, /*path*/NULL); ++ if (!err) ++ au_dr_hino_free(&br->br_dirren); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_brid_str(struct au_dr_brid *brid, struct inode *h_inode, ++ char *buf, size_t sz) ++{ ++ int err; ++ unsigned int major, minor; ++ char *p; ++ ++ p = buf; ++ err = snprintf(p, sz, "%d_", brid->type); ++ AuDebugOn(err > sz); ++ p += err; ++ sz -= err; ++ switch (brid->type) { ++ case AuBrid_Unset: ++ return -EINVAL; ++ case AuBrid_UUID: ++ err = snprintf(p, sz, "%pU", brid->uuid.b); ++ break; ++ case AuBrid_FSID: ++ err = snprintf(p, sz, "%08x-%08x", ++ brid->fsid.val[0], brid->fsid.val[1]); ++ break; ++ case AuBrid_DEV: ++ major = MAJOR(brid->dev); ++ minor = MINOR(brid->dev); ++ if (major <= 0xff && minor <= 0xff) ++ err = snprintf(p, sz, "%02x%02x", major, minor); ++ else ++ err = snprintf(p, sz, "%03x:%05x", major, minor); ++ break; ++ } ++ AuDebugOn(err > sz); ++ p += err; ++ sz -= err; ++ err = snprintf(p, sz, "_%llu", (unsigned long long)h_inode->i_ino); ++ AuDebugOn(err > sz); ++ p += err; ++ sz -= err; ++ ++ return p - buf; ++} ++ ++static int au_drinfo_name(struct au_branch *br, char *name, int len) ++{ ++ int rlen; ++ struct dentry *br_dentry; ++ struct inode *br_inode; ++ ++ br_dentry = au_br_dentry(br); ++ br_inode = d_inode(br_dentry); ++ rlen = au_brid_str(&br->br_dirren.dr_brid, br_inode, name, len); ++ AuDebugOn(rlen >= AUFS_DIRREN_ENV_VAL_SZ); ++ AuDebugOn(rlen > len); ++ ++ return rlen; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * from the given @h_dentry, construct drinfo at @*fdata. ++ * when the size of @*fdata is not enough, reallocate and return new @fdata and ++ * @allocated. ++ */ ++static int au_drinfo_construct(struct au_drinfo_fdata **fdata, ++ struct dentry *h_dentry, ++ unsigned char *allocated) ++{ ++ int err, v; ++ struct au_drinfo_fdata *f, *p; ++ struct au_drinfo *drinfo; ++ struct inode *h_inode; ++ struct qstr *qname; ++ ++ err = 0; ++ f = *fdata; ++ h_inode = d_inode(h_dentry); ++ qname = &h_dentry->d_name; ++ drinfo = &f->drinfo; ++ drinfo->ino = (__force uint64_t)cpu_to_be64(h_inode->i_ino); ++ drinfo->oldnamelen = qname->len; ++ if (*allocated < sizeof(*f) + qname->len) { ++ v = roundup_pow_of_two(*allocated + qname->len); ++ p = au_krealloc(f, v, GFP_NOFS, /*may_shrink*/0); ++ if (unlikely(!p)) { ++ err = -ENOMEM; ++ AuTraceErr(err); ++ goto out; ++ } ++ f = p; ++ *fdata = f; ++ *allocated = v; ++ drinfo = &f->drinfo; ++ } ++ memcpy(drinfo->oldname, qname->name, qname->len); ++ AuDbg("i%llu, %.*s\n", ++ be64_to_cpu((__force __be64)drinfo->ino), drinfo->oldnamelen, ++ drinfo->oldname); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* callers have to free the return value */ ++static struct au_drinfo *au_drinfo_read_k(struct file *file, ino_t h_ino) ++{ ++ struct au_drinfo *ret, *drinfo; ++ struct au_drinfo_fdata fdata; ++ int len; ++ loff_t pos; ++ ssize_t ssz; ++ ++ ret = ERR_PTR(-EIO); ++ pos = 0; ++ ssz = vfsub_read_k(file, &fdata, sizeof(fdata), &pos); ++ if (unlikely(ssz != sizeof(fdata))) { ++ AuIOErr("ssz %zd, %u, %pD2\n", ++ ssz, (unsigned int)sizeof(fdata), file); ++ goto out; ++ } ++ ++ fdata.magic = ntohl((__force __be32)fdata.magic); ++ switch (fdata.magic) { ++ case AUFS_DRINFO_MAGIC_V1: ++ break; ++ default: ++ AuIOErr("magic-num 0x%x, 0x%x, %pD2\n", ++ fdata.magic, AUFS_DRINFO_MAGIC_V1, file); ++ goto out; ++ } ++ ++ drinfo = &fdata.drinfo; ++ len = drinfo->oldnamelen; ++ if (!len) { ++ AuIOErr("broken drinfo %pD2\n", file); ++ goto out; ++ } ++ ++ ret = NULL; ++ drinfo->ino = be64_to_cpu((__force __be64)drinfo->ino); ++ if (unlikely(h_ino && drinfo->ino != h_ino)) { ++ AuDbg("ignored i%llu, i%llu, %pD2\n", ++ (unsigned long long)drinfo->ino, ++ (unsigned long long)h_ino, file); ++ goto out; /* success */ ++ } ++ ++ ret = kmalloc(sizeof(*ret) + len, GFP_NOFS); ++ if (unlikely(!ret)) { ++ ret = ERR_PTR(-ENOMEM); ++ AuTraceErrPtr(ret); ++ goto out; ++ } ++ ++ *ret = *drinfo; ++ ssz = vfsub_read_k(file, (void *)ret->oldname, len, &pos); ++ if (unlikely(ssz != len)) { ++ au_kfree_rcu(ret); ++ ret = ERR_PTR(-EIO); ++ AuIOErr("ssz %zd, %u, %pD2\n", ssz, len, file); ++ goto out; ++ } ++ ++ AuDbg("oldname %.*s\n", ret->oldnamelen, ret->oldname); ++ ++out: ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* in order to be revertible */ ++struct au_drinfo_rev_elm { ++ int created; ++ struct dentry *info_dentry; ++ struct au_drinfo *info_last; ++}; ++ ++struct au_drinfo_rev { ++ unsigned char already; ++ aufs_bindex_t nelm; ++ struct au_drinfo_rev_elm elm[0]; ++}; ++ ++/* todo: isn't it too large? */ ++struct au_drinfo_store { ++ struct path h_ppath; ++ struct dentry *h_dentry; ++ struct au_drinfo_fdata *fdata; ++ char *infoname; /* inside of whname, just after PFX */ ++ char whname[sizeof(AUFS_WH_DR_INFO_PFX) + AUFS_DIRREN_ENV_VAL_SZ]; ++ aufs_bindex_t btgt, btail; ++ unsigned char no_sio, ++ allocated, /* current size of *fdata */ ++ infonamelen, /* room size for p */ ++ whnamelen, /* length of the generated name */ ++ renameback; /* renamed back */ ++}; ++ ++/* on rename(2) error, the caller should revert it using @elm */ ++static int au_drinfo_do_store(struct au_drinfo_store *w, ++ struct au_drinfo_rev_elm *elm) ++{ ++ int err, len; ++ ssize_t ssz; ++ loff_t pos; ++ struct path infopath = { ++ .mnt = w->h_ppath.mnt ++ }; ++ struct inode *h_dir, *h_inode, *delegated; ++ struct file *infofile; ++ struct qstr *qname; ++ ++ AuDebugOn(elm ++ && memcmp(elm, page_address(ZERO_PAGE(0)), sizeof(*elm))); ++ ++ infopath.dentry = vfsub_lookup_one_len(w->whname, w->h_ppath.dentry, ++ w->whnamelen); ++ AuTraceErrPtr(infopath.dentry); ++ if (IS_ERR(infopath.dentry)) { ++ err = PTR_ERR(infopath.dentry); ++ goto out; ++ } ++ ++ err = 0; ++ h_dir = d_inode(w->h_ppath.dentry); ++ if (elm && d_is_negative(infopath.dentry)) { ++ err = vfsub_create(h_dir, &infopath, 0600, /*want_excl*/true); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out_dput; ++ elm->created = 1; ++ elm->info_dentry = dget(infopath.dentry); ++ } ++ ++ infofile = vfsub_dentry_open(&infopath, O_RDWR); ++ AuTraceErrPtr(infofile); ++ if (IS_ERR(infofile)) { ++ err = PTR_ERR(infofile); ++ goto out_dput; ++ } ++ ++ h_inode = d_inode(infopath.dentry); ++ if (elm && i_size_read(h_inode)) { ++ h_inode = d_inode(w->h_dentry); ++ elm->info_last = au_drinfo_read_k(infofile, h_inode->i_ino); ++ AuTraceErrPtr(elm->info_last); ++ if (IS_ERR(elm->info_last)) { ++ err = PTR_ERR(elm->info_last); ++ elm->info_last = NULL; ++ AuDebugOn(elm->info_dentry); ++ goto out_fput; ++ } ++ } ++ ++ if (elm && w->renameback) { ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, &infopath, &delegated, /*force*/0); ++ AuTraceErr(err); ++ if (unlikely(err == -EWOULDBLOCK)) ++ iput(delegated); ++ goto out_fput; ++ } ++ ++ pos = 0; ++ qname = &w->h_dentry->d_name; ++ len = sizeof(*w->fdata) + qname->len; ++ if (!elm) ++ len = sizeof(*w->fdata) + w->fdata->drinfo.oldnamelen; ++ ssz = vfsub_write_k(infofile, w->fdata, len, &pos); ++ if (ssz == len) { ++ AuDbg("hi%llu, %.*s\n", w->fdata->drinfo.ino, ++ w->fdata->drinfo.oldnamelen, w->fdata->drinfo.oldname); ++ goto out_fput; /* success */ ++ } else { ++ err = -EIO; ++ if (ssz < 0) ++ err = ssz; ++ /* the caller should revert it using @elm */ ++ } ++ ++out_fput: ++ fput(infofile); ++out_dput: ++ dput(infopath.dentry); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++struct au_call_drinfo_do_store_args { ++ int *errp; ++ struct au_drinfo_store *w; ++ struct au_drinfo_rev_elm *elm; ++}; ++ ++static void au_call_drinfo_do_store(void *args) ++{ ++ struct au_call_drinfo_do_store_args *a = args; ++ ++ *a->errp = au_drinfo_do_store(a->w, a->elm); ++} ++ ++static int au_drinfo_store_sio(struct au_drinfo_store *w, ++ struct au_drinfo_rev_elm *elm) ++{ ++ int err, wkq_err; ++ ++ if (w->no_sio) ++ err = au_drinfo_do_store(w, elm); ++ else { ++ struct au_call_drinfo_do_store_args a = { ++ .errp = &err, ++ .w = w, ++ .elm = elm ++ }; ++ wkq_err = au_wkq_wait(au_call_drinfo_do_store, &a); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ AuTraceErr(err); ++ ++ return err; ++} ++ ++static int au_drinfo_store_work_init(struct au_drinfo_store *w, ++ aufs_bindex_t btgt) ++{ ++ int err; ++ ++ memset(w, 0, sizeof(*w)); ++ w->allocated = roundup_pow_of_two(sizeof(*w->fdata) + 40); ++ strcpy(w->whname, AUFS_WH_DR_INFO_PFX); ++ w->infoname = w->whname + sizeof(AUFS_WH_DR_INFO_PFX) - 1; ++ w->infonamelen = sizeof(w->whname) - sizeof(AUFS_WH_DR_INFO_PFX); ++ w->btgt = btgt; ++ w->no_sio = !!uid_eq(current_fsuid(), GLOBAL_ROOT_UID); ++ ++ err = -ENOMEM; ++ w->fdata = kcalloc(1, w->allocated, GFP_NOFS); ++ if (unlikely(!w->fdata)) { ++ AuTraceErr(err); ++ goto out; ++ } ++ w->fdata->magic = (__force uint32_t)htonl(AUFS_DRINFO_MAGIC_V1); ++ err = 0; ++ ++out: ++ return err; ++} ++ ++static void au_drinfo_store_work_fin(struct au_drinfo_store *w) ++{ ++ au_kfree_rcu(w->fdata); ++} ++ ++static void au_drinfo_store_rev(struct au_drinfo_rev *rev, ++ struct au_drinfo_store *w) ++{ ++ struct au_drinfo_rev_elm *elm; ++ struct inode *h_dir, *delegated; ++ int err, nelm; ++ struct path infopath = { ++ .mnt = w->h_ppath.mnt ++ }; ++ ++ h_dir = d_inode(w->h_ppath.dentry); ++ IMustLock(h_dir); ++ ++ err = 0; ++ elm = rev->elm; ++ for (nelm = rev->nelm; nelm > 0; nelm--, elm++) { ++ AuDebugOn(elm->created && elm->info_last); ++ if (elm->created) { ++ AuDbg("here\n"); ++ delegated = NULL; ++ infopath.dentry = elm->info_dentry; ++ err = vfsub_unlink(h_dir, &infopath, &delegated, ++ !w->no_sio); ++ AuTraceErr(err); ++ if (unlikely(err == -EWOULDBLOCK)) ++ iput(delegated); ++ dput(elm->info_dentry); ++ } else if (elm->info_last) { ++ AuDbg("here\n"); ++ w->fdata->drinfo = *elm->info_last; ++ memcpy(w->fdata->drinfo.oldname, ++ elm->info_last->oldname, ++ elm->info_last->oldnamelen); ++ err = au_drinfo_store_sio(w, /*elm*/NULL); ++ au_kfree_rcu(elm->info_last); ++ } ++ if (unlikely(err)) ++ AuIOErr("%d, %s\n", err, w->whname); ++ /* go on even if err */ ++ } ++} ++ ++/* caller has to call au_dr_rename_fin() later */ ++static int au_drinfo_store(struct dentry *dentry, aufs_bindex_t btgt, ++ struct qstr *dst_name, void *_rev) ++{ ++ int err, sz, nelm; ++ aufs_bindex_t bindex, btail; ++ struct au_drinfo_store work; ++ struct au_drinfo_rev *rev, **p; ++ struct au_drinfo_rev_elm *elm; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_hinode *hdir; ++ ++ err = au_drinfo_store_work_init(&work, btgt); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out; ++ ++ err = -ENOMEM; ++ btail = au_dbtaildir(dentry); ++ nelm = btail - btgt; ++ sz = sizeof(*rev) + sizeof(*elm) * nelm; ++ rev = kcalloc(1, sz, GFP_NOFS); ++ if (unlikely(!rev)) { ++ AuTraceErr(err); ++ goto out_args; ++ } ++ rev->nelm = nelm; ++ elm = rev->elm; ++ p = _rev; ++ *p = rev; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ work.h_ppath.dentry = au_h_dptr(dentry, btgt); ++ work.h_ppath.mnt = au_sbr_mnt(sb, btgt); ++ hdir = au_hi(d_inode(dentry), btgt); ++ au_hn_inode_lock_nested(hdir, AuLsc_I_CHILD); ++ for (bindex = btgt + 1; bindex <= btail; bindex++, elm++) { ++ work.h_dentry = au_h_dptr(dentry, bindex); ++ if (!work.h_dentry) ++ continue; ++ ++ err = au_drinfo_construct(&work.fdata, work.h_dentry, ++ &work.allocated); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ break; ++ ++ work.renameback = au_qstreq(&work.h_dentry->d_name, dst_name); ++ br = au_sbr(sb, bindex); ++ work.whnamelen = sizeof(AUFS_WH_DR_INFO_PFX) - 1; ++ work.whnamelen += au_drinfo_name(br, work.infoname, ++ work.infonamelen); ++ AuDbg("whname %.*s, i%llu, %.*s\n", ++ work.whnamelen, work.whname, ++ be64_to_cpu((__force __be64)work.fdata->drinfo.ino), ++ work.fdata->drinfo.oldnamelen, ++ work.fdata->drinfo.oldname); ++ ++ err = au_drinfo_store_sio(&work, elm); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ break; ++ } ++ if (unlikely(err)) { ++ /* revert all drinfo */ ++ au_drinfo_store_rev(rev, &work); ++ au_kfree_try_rcu(rev); ++ *p = NULL; ++ } ++ au_hn_inode_unlock(hdir); ++ ++out_args: ++ au_drinfo_store_work_fin(&work); ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_dr_rename(struct dentry *src, aufs_bindex_t bindex, ++ struct qstr *dst_name, void *_rev) ++{ ++ int err, already; ++ ino_t ino; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_dr_br *dr; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct au_dr_hino *ent; ++ struct au_drinfo_rev *rev, **p; ++ ++ AuDbg("bindex %d\n", bindex); ++ ++ err = -ENOMEM; ++ ent = kmalloc(sizeof(*ent), GFP_NOFS); ++ if (unlikely(!ent)) ++ goto out; ++ ++ sb = src->d_sb; ++ br = au_sbr(sb, bindex); ++ dr = &br->br_dirren; ++ h_dentry = au_h_dptr(src, bindex); ++ h_inode = d_inode(h_dentry); ++ ino = h_inode->i_ino; ++ ent->dr_h_ino = ino; ++ already = au_dr_hino_test_add(dr, ino, ent); ++ AuDbg("b%d, hi%llu, already %d\n", ++ bindex, (unsigned long long)ino, already); ++ ++ err = au_drinfo_store(src, bindex, dst_name, _rev); ++ AuTraceErr(err); ++ if (!err) { ++ p = _rev; ++ rev = *p; ++ rev->already = already; ++ goto out; /* success */ ++ } ++ ++ /* revert */ ++ if (!already) ++ au_dr_hino_del(dr, ent); ++ au_kfree_rcu(ent); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_dr_rename_fin(struct dentry *src, aufs_bindex_t btgt, void *_rev) ++{ ++ struct au_drinfo_rev *rev; ++ struct au_drinfo_rev_elm *elm; ++ int nelm; ++ ++ rev = _rev; ++ elm = rev->elm; ++ for (nelm = rev->nelm; nelm > 0; nelm--, elm++) { ++ dput(elm->info_dentry); ++ au_kfree_rcu(elm->info_last); ++ } ++ au_kfree_try_rcu(rev); ++} ++ ++void au_dr_rename_rev(struct dentry *src, aufs_bindex_t btgt, void *_rev) ++{ ++ int err; ++ struct au_drinfo_store work; ++ struct au_drinfo_rev *rev = _rev; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct inode *h_inode; ++ struct au_dr_br *dr; ++ struct au_dr_hino *ent; ++ ++ err = au_drinfo_store_work_init(&work, btgt); ++ if (unlikely(err)) ++ goto out; ++ ++ sb = src->d_sb; ++ br = au_sbr(sb, btgt); ++ work.h_ppath.dentry = au_h_dptr(src, btgt); ++ work.h_ppath.mnt = au_br_mnt(br); ++ au_drinfo_store_rev(rev, &work); ++ au_drinfo_store_work_fin(&work); ++ if (rev->already) ++ goto out; ++ ++ dr = &br->br_dirren; ++ h_inode = d_inode(work.h_ppath.dentry); ++ ent = au_dr_hino_find(dr, h_inode->i_ino); ++ BUG_ON(!ent); ++ au_dr_hino_del(dr, ent); ++ au_kfree_rcu(ent); ++ ++out: ++ au_kfree_try_rcu(rev); ++ if (unlikely(err)) ++ pr_err("failed to remove dirren info\n"); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct au_drinfo *au_drinfo_do_load(struct path *h_ppath, ++ char *whname, int whnamelen, ++ struct dentry **info_dentry) ++{ ++ struct au_drinfo *drinfo; ++ struct file *f; ++ struct inode *h_dir; ++ struct path infopath; ++ int unlocked; ++ ++ AuDbg("%pd/%.*s\n", h_ppath->dentry, whnamelen, whname); ++ ++ *info_dentry = NULL; ++ drinfo = NULL; ++ unlocked = 0; ++ h_dir = d_inode(h_ppath->dentry); ++ inode_lock_shared_nested(h_dir, AuLsc_I_PARENT); ++ infopath.dentry = vfsub_lookup_one_len(whname, h_ppath->dentry, ++ whnamelen); ++ if (IS_ERR(infopath.dentry)) { ++ drinfo = (void *)infopath.dentry; ++ goto out; ++ } ++ ++ if (d_is_negative(infopath.dentry)) ++ goto out_dput; /* success */ ++ ++ infopath.mnt = h_ppath->mnt; ++ f = vfsub_dentry_open(&infopath, O_RDONLY); ++ inode_unlock_shared(h_dir); ++ unlocked = 1; ++ if (IS_ERR(f)) { ++ drinfo = (void *)f; ++ goto out_dput; ++ } ++ ++ drinfo = au_drinfo_read_k(f, /*h_ino*/0); ++ if (IS_ERR_OR_NULL(drinfo)) ++ goto out_fput; ++ ++ AuDbg("oldname %.*s\n", drinfo->oldnamelen, drinfo->oldname); ++ *info_dentry = dget(infopath.dentry); /* keep it alive */ ++ ++out_fput: ++ fput(f); ++out_dput: ++ dput(infopath.dentry); ++out: ++ if (!unlocked) ++ inode_unlock_shared(h_dir); ++ AuTraceErrPtr(drinfo); ++ return drinfo; ++} ++ ++struct au_drinfo_do_load_args { ++ struct au_drinfo **drinfop; ++ struct path *h_ppath; ++ char *whname; ++ int whnamelen; ++ struct dentry **info_dentry; ++}; ++ ++static void au_call_drinfo_do_load(void *args) ++{ ++ struct au_drinfo_do_load_args *a = args; ++ ++ *a->drinfop = au_drinfo_do_load(a->h_ppath, a->whname, a->whnamelen, ++ a->info_dentry); ++} ++ ++struct au_drinfo_load { ++ struct path h_ppath; ++ struct qstr *qname; ++ unsigned char no_sio; ++ ++ aufs_bindex_t ninfo; ++ struct au_drinfo **drinfo; ++}; ++ ++static int au_drinfo_load(struct au_drinfo_load *w, aufs_bindex_t bindex, ++ struct au_branch *br) ++{ ++ int err, wkq_err, whnamelen, e; ++ char whname[sizeof(AUFS_WH_DR_INFO_PFX) + AUFS_DIRREN_ENV_VAL_SZ] ++ = AUFS_WH_DR_INFO_PFX; ++ struct au_drinfo *drinfo; ++ struct qstr oldname; ++ struct inode *h_dir, *delegated; ++ struct dentry *info_dentry; ++ struct path infopath; ++ ++ whnamelen = sizeof(AUFS_WH_DR_INFO_PFX) - 1; ++ whnamelen += au_drinfo_name(br, whname + whnamelen, ++ sizeof(whname) - whnamelen); ++ if (w->no_sio) ++ drinfo = au_drinfo_do_load(&w->h_ppath, whname, whnamelen, ++ &info_dentry); ++ else { ++ struct au_drinfo_do_load_args args = { ++ .drinfop = &drinfo, ++ .h_ppath = &w->h_ppath, ++ .whname = whname, ++ .whnamelen = whnamelen, ++ .info_dentry = &info_dentry ++ }; ++ wkq_err = au_wkq_wait(au_call_drinfo_do_load, &args); ++ if (unlikely(wkq_err)) ++ drinfo = ERR_PTR(wkq_err); ++ } ++ err = PTR_ERR(drinfo); ++ if (IS_ERR_OR_NULL(drinfo)) ++ goto out; ++ ++ err = 0; ++ oldname.len = drinfo->oldnamelen; ++ oldname.name = drinfo->oldname; ++ if (au_qstreq(w->qname, &oldname)) { ++ /* the name is renamed back */ ++ au_kfree_rcu(drinfo); ++ drinfo = NULL; ++ ++ infopath.dentry = info_dentry; ++ infopath.mnt = w->h_ppath.mnt; ++ h_dir = d_inode(w->h_ppath.dentry); ++ delegated = NULL; ++ inode_lock_nested(h_dir, AuLsc_I_PARENT); ++ e = vfsub_unlink(h_dir, &infopath, &delegated, !w->no_sio); ++ inode_unlock(h_dir); ++ if (unlikely(e)) ++ AuIOErr("ignored %d, %pd2\n", e, &infopath.dentry); ++ if (unlikely(e == -EWOULDBLOCK)) ++ iput(delegated); ++ } ++ au_kfree_rcu(w->drinfo[bindex]); ++ w->drinfo[bindex] = drinfo; ++ dput(info_dentry); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_dr_lkup_free(struct au_drinfo **drinfo, int n) ++{ ++ struct au_drinfo **p = drinfo; ++ ++ while (n-- > 0) ++ au_kfree_rcu(*drinfo++); ++ au_kfree_try_rcu(p); ++} ++ ++int au_dr_lkup(struct au_do_lookup_args *lkup, struct dentry *dentry, ++ aufs_bindex_t btgt) ++{ ++ int err, ninfo; ++ struct au_drinfo_load w; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ struct inode *h_dir; ++ struct au_dr_hino *ent; ++ struct super_block *sb; ++ ++ AuDbg("%.*s, name %.*s, whname %.*s, b%d\n", ++ AuLNPair(&dentry->d_name), AuLNPair(&lkup->dirren.dr_name), ++ AuLNPair(&lkup->whname), btgt); ++ ++ sb = dentry->d_sb; ++ bbot = au_sbbot(sb); ++ w.ninfo = bbot + 1; ++ if (!lkup->dirren.drinfo) { ++ lkup->dirren.drinfo = kcalloc(w.ninfo, ++ sizeof(*lkup->dirren.drinfo), ++ GFP_NOFS); ++ if (unlikely(!lkup->dirren.drinfo)) { ++ err = -ENOMEM; ++ goto out; ++ } ++ lkup->dirren.ninfo = w.ninfo; ++ } ++ w.drinfo = lkup->dirren.drinfo; ++ w.no_sio = !!uid_eq(current_fsuid(), GLOBAL_ROOT_UID); ++ w.h_ppath.dentry = au_h_dptr(dentry, btgt); ++ AuDebugOn(!w.h_ppath.dentry); ++ w.h_ppath.mnt = au_sbr_mnt(sb, btgt); ++ w.qname = &dentry->d_name; ++ ++ ninfo = 0; ++ for (bindex = btgt + 1; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ err = au_drinfo_load(&w, bindex, br); ++ if (unlikely(err)) ++ goto out_free; ++ if (w.drinfo[bindex]) ++ ninfo++; ++ } ++ if (!ninfo) { ++ br = au_sbr(sb, btgt); ++ h_dir = d_inode(w.h_ppath.dentry); ++ ent = au_dr_hino_find(&br->br_dirren, h_dir->i_ino); ++ AuDebugOn(!ent); ++ au_dr_hino_del(&br->br_dirren, ent); ++ au_kfree_rcu(ent); ++ } ++ goto out; /* success */ ++ ++out_free: ++ au_dr_lkup_free(lkup->dirren.drinfo, lkup->dirren.ninfo); ++ lkup->dirren.ninfo = 0; ++ lkup->dirren.drinfo = NULL; ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_dr_lkup_fin(struct au_do_lookup_args *lkup) ++{ ++ au_dr_lkup_free(lkup->dirren.drinfo, lkup->dirren.ninfo); ++} ++ ++int au_dr_lkup_name(struct au_do_lookup_args *lkup, aufs_bindex_t btgt) ++{ ++ int err; ++ struct au_drinfo *drinfo; ++ ++ err = 0; ++ if (!lkup->dirren.drinfo) ++ goto out; ++ AuDebugOn(lkup->dirren.ninfo < btgt + 1); ++ drinfo = lkup->dirren.drinfo[btgt + 1]; ++ if (!drinfo) ++ goto out; ++ ++ au_kfree_try_rcu(lkup->whname.name); ++ lkup->whname.name = NULL; ++ lkup->dirren.dr_name.len = drinfo->oldnamelen; ++ lkup->dirren.dr_name.name = drinfo->oldname; ++ lkup->name = &lkup->dirren.dr_name; ++ err = au_wh_name_alloc(&lkup->whname, lkup->name); ++ if (!err) ++ AuDbg("name %.*s, whname %.*s, b%d\n", ++ AuLNPair(lkup->name), AuLNPair(&lkup->whname), ++ btgt); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_dr_lkup_h_ino(struct au_do_lookup_args *lkup, aufs_bindex_t bindex, ++ ino_t h_ino) ++{ ++ int match; ++ struct au_drinfo *drinfo; ++ ++ match = 1; ++ if (!lkup->dirren.drinfo) ++ goto out; ++ AuDebugOn(lkup->dirren.ninfo < bindex + 1); ++ drinfo = lkup->dirren.drinfo[bindex + 1]; ++ if (!drinfo) ++ goto out; ++ ++ match = (drinfo->ino == h_ino); ++ AuDbg("match %d\n", match); ++ ++out: ++ return match; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_dr_opt_set(struct super_block *sb) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ err = 0; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; !err && bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ err = au_dr_hino(sb, bindex, /*br*/NULL, &br->br_path); ++ } ++ ++ return err; ++} ++ ++int au_dr_opt_flush(struct super_block *sb) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ err = 0; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; !err && bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_writable(br->br_perm)) ++ err = au_dr_hino(sb, bindex, /*br*/NULL, /*path*/NULL); ++ } ++ ++ return err; ++} ++ ++int au_dr_opt_clr(struct super_block *sb, int no_flush) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ err = 0; ++ if (!no_flush) { ++ err = au_dr_opt_flush(sb); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ au_dr_hino_free(&br->br_dirren); ++ } ++ ++out: ++ return err; ++} +diff -Nurp linux-5.4/fs/aufs/dirren.h linux-5.4-aufs/fs/aufs/dirren.h +--- linux-5.4/fs/aufs/dirren.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/dirren.h 2019-11-28 01:25:59.064925618 +0200 +@@ -0,0 +1,127 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2017-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * renamed dir info ++ */ ++ ++#ifndef __AUFS_DIRREN_H__ ++#define __AUFS_DIRREN_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include "hbl.h" ++ ++#define AuDirren_NHASH 100 ++ ++#ifdef CONFIG_AUFS_DIRREN ++enum au_brid_type { ++ AuBrid_Unset, ++ AuBrid_UUID, ++ AuBrid_FSID, ++ AuBrid_DEV ++}; ++ ++struct au_dr_brid { ++ enum au_brid_type type; ++ union { ++ uuid_t uuid; /* unimplemented yet */ ++ fsid_t fsid; ++ dev_t dev; ++ }; ++}; ++ ++/* 20 is the max digits length of ulong 64 */ ++/* brid-type "_" uuid "_" inum */ ++#define AUFS_DIRREN_FNAME_SZ (1 + 1 + UUID_STRING_LEN + 20) ++#define AUFS_DIRREN_ENV_VAL_SZ (AUFS_DIRREN_FNAME_SZ + 1 + 20) ++ ++struct au_dr_hino { ++ struct hlist_bl_node dr_hnode; ++ ino_t dr_h_ino; ++}; ++ ++struct au_dr_br { ++ struct hlist_bl_head dr_h_ino[AuDirren_NHASH]; ++ struct au_dr_brid dr_brid; ++}; ++ ++struct au_dr_lookup { ++ /* dr_name is pointed by struct au_do_lookup_args.name */ ++ struct qstr dr_name; /* subset of dr_info */ ++ aufs_bindex_t ninfo; ++ struct au_drinfo **drinfo; ++}; ++#else ++struct au_dr_hino; ++/* empty */ ++struct au_dr_br { }; ++struct au_dr_lookup { }; ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_branch; ++struct au_do_lookup_args; ++struct au_hinode; ++#ifdef CONFIG_AUFS_DIRREN ++int au_dr_hino_test_add(struct au_dr_br *dr, ino_t h_ino, ++ struct au_dr_hino *add_ent); ++void au_dr_hino_free(struct au_dr_br *dr); ++int au_dr_br_init(struct super_block *sb, struct au_branch *br, ++ const struct path *path); ++int au_dr_br_fin(struct super_block *sb, struct au_branch *br); ++int au_dr_rename(struct dentry *src, aufs_bindex_t bindex, ++ struct qstr *dst_name, void *_rev); ++void au_dr_rename_fin(struct dentry *src, aufs_bindex_t btgt, void *rev); ++void au_dr_rename_rev(struct dentry *src, aufs_bindex_t bindex, void *rev); ++int au_dr_lkup(struct au_do_lookup_args *lkup, struct dentry *dentry, ++ aufs_bindex_t bindex); ++int au_dr_lkup_name(struct au_do_lookup_args *lkup, aufs_bindex_t btgt); ++int au_dr_lkup_h_ino(struct au_do_lookup_args *lkup, aufs_bindex_t bindex, ++ ino_t h_ino); ++void au_dr_lkup_fin(struct au_do_lookup_args *lkup); ++int au_dr_opt_set(struct super_block *sb); ++int au_dr_opt_flush(struct super_block *sb); ++int au_dr_opt_clr(struct super_block *sb, int no_flush); ++#else ++AuStubInt0(au_dr_hino_test_add, struct au_dr_br *dr, ino_t h_ino, ++ struct au_dr_hino *add_ent); ++AuStubVoid(au_dr_hino_free, struct au_dr_br *dr); ++AuStubInt0(au_dr_br_init, struct super_block *sb, struct au_branch *br, ++ const struct path *path); ++AuStubInt0(au_dr_br_fin, struct super_block *sb, struct au_branch *br); ++AuStubInt0(au_dr_rename, struct dentry *src, aufs_bindex_t bindex, ++ struct qstr *dst_name, void *_rev); ++AuStubVoid(au_dr_rename_fin, struct dentry *src, aufs_bindex_t btgt, void *rev); ++AuStubVoid(au_dr_rename_rev, struct dentry *src, aufs_bindex_t bindex, ++ void *rev); ++AuStubInt0(au_dr_lkup, struct au_do_lookup_args *lkup, struct dentry *dentry, ++ aufs_bindex_t bindex); ++AuStubInt0(au_dr_lkup_name, struct au_do_lookup_args *lkup, aufs_bindex_t btgt); ++AuStubInt0(au_dr_lkup_h_ino, struct au_do_lookup_args *lkup, ++ aufs_bindex_t bindex, ino_t h_ino); ++AuStubVoid(au_dr_lkup_fin, struct au_do_lookup_args *lkup); ++AuStubInt0(au_dr_opt_set, struct super_block *sb); ++AuStubInt0(au_dr_opt_flush, struct super_block *sb); ++AuStubInt0(au_dr_opt_clr, struct super_block *sb, int no_flush); ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_DIRREN ++static inline int au_dr_ihash(ino_t h_ino) ++{ ++ return h_ino % AuDirren_NHASH; ++} ++#else ++AuStubInt0(au_dr_ihash, ino_t h_ino); ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DIRREN_H__ */ +diff -Nurp linux-5.4/fs/aufs/dynop.c linux-5.4-aufs/fs/aufs/dynop.c +--- linux-5.4/fs/aufs/dynop.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/dynop.c 2019-11-28 01:25:59.064925618 +0200 +@@ -0,0 +1,354 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2010-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * 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 hlist_bl_head dynop[AuDyLast]; ++ ++static struct au_dykey *dy_gfind_get(struct hlist_bl_head *hbl, ++ const void *h_op) ++{ ++ struct au_dykey *key, *tmp; ++ struct hlist_bl_node *pos; ++ ++ key = NULL; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(tmp, pos, hbl, dk_hnode) ++ if (tmp->dk_op.dy_hop == h_op) { ++ if (kref_get_unless_zero(&tmp->dk_kref)) ++ key = tmp; ++ break; ++ } ++ hlist_bl_unlock(hbl); ++ ++ 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 hlist_bl_head *hbl, struct au_dykey *key) ++{ ++ struct au_dykey *tmp, *found; ++ struct hlist_bl_node *pos; ++ const void *h_op = key->dk_op.dy_hop; ++ ++ found = NULL; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(tmp, pos, hbl, dk_hnode) ++ if (tmp->dk_op.dy_hop == h_op) { ++ if (kref_get_unless_zero(&tmp->dk_kref)) ++ found = tmp; ++ break; ++ } ++ if (!found) ++ hlist_bl_add_head(&key->dk_hnode, hbl); ++ hlist_bl_unlock(hbl); ++ ++ 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 hlist_bl_head *hbl; ++ ++ key = container_of(kref, struct au_dykey, dk_kref); ++ hbl = dynop + key->dk_op.dy_type; ++ au_hbl_del(&key->dk_hnode, hbl); ++ 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); ++ /* this one will be changed according to an aufs mount option */ ++ DySetAop(direct_IO); ++ DySetAop(migratepage); ++ DySetAop(isolate_page); ++ DySetAop(putback_page); ++ DySetAop(launder_page); ++ DySetAop(is_partially_uptodate); ++ DySetAop(is_dirty_writeback); ++ DySetAop(error_remove_page); ++ DySetAop(swap_activate); ++ DySetAop(swap_deactivate); ++ ++ DyDbgSize(cnt, *h_aop); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++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 hlist_bl_head *hbl; ++ 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; ++ ++ hbl = dynop + op->dy_type; ++ key = dy_gfind_get(hbl, 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, au_br_sb(br)); ++ old = dy_gadd(hbl, key); ++ if (old) { ++ au_kfree_rcu(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 default even if the branch supports it. ++ * This behaviour is necessary 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. ++ */ ++static void dy_adx(struct au_dyaop *dyaop, int do_dx) ++{ ++ if (!do_dx) ++ dyaop->da_op.direct_IO = NULL; ++ else ++ dyaop->da_op.direct_IO = aufs_aop.direct_IO; ++} ++ ++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 btop; ++ struct inode *h_inode; ++ ++ err = 0; ++ if (S_ISREG(inode->i_mode)) { ++ btop = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, btop); ++ err = au_dy_iaop(inode, btop, h_inode); ++ } ++ return err; ++} ++ ++void au_dy_arefresh(int do_dx) ++{ ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_dykey *key; ++ ++ hbl = dynop + AuDy_AOP; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(key, pos, hbl, dk_hnode) ++ dy_adx((void *)key, do_dx); ++ hlist_bl_unlock(hbl); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void __init au_dy_init(void) ++{ ++ int i; ++ ++ for (i = 0; i < AuDyLast; i++) ++ INIT_HLIST_BL_HEAD(dynop + i); ++} ++ ++void au_dy_fin(void) ++{ ++ int i; ++ ++ for (i = 0; i < AuDyLast; i++) ++ WARN_ON(!hlist_bl_empty(dynop + i)); ++} +diff -Nurp linux-5.4/fs/aufs/dynop.h linux-5.4-aufs/fs/aufs/dynop.h +--- linux-5.4/fs/aufs/dynop.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/dynop.h 2019-11-28 01:25:59.064925618 +0200 +@@ -0,0 +1,64 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2010-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * dynamically customizable operations (for regular files only) ++ */ ++ ++#ifndef __AUFS_DYNOP_H__ ++#define __AUFS_DYNOP_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++ ++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 hlist_bl_node dk_hnode; ++ 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 */ ++}; ++/* make sure that 'struct au_dykey *' can be any type */ ++static_assert(!offsetof(struct au_dyaop, da_key)); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* 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 -Nurp linux-5.4/fs/aufs/export.c linux-5.4-aufs/fs/aufs/export.c +--- linux-5.4/fs/aufs/export.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/export.c 2019-11-28 01:25:59.064925618 +0200 +@@ -0,0 +1,825 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * export via nfs ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#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 (vfsub_f_size_read(file) ++ < 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 path *path) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ file = au_xino_create2(sb, path, 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: ++ AuTraceErr(err); ++ 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; ++ ++ dentry = NULL; ++ inode = ilookup(sb, ino); ++ if (!inode) ++ goto out; ++ ++ dentry = ERR_PTR(-ESTALE); ++ sigen = au_sigen(sb); ++ if (unlikely(au_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, &inode->i_dentry, d_u.d_alias) { ++ spin_lock(&d->d_lock); ++ if (!au_test_anon(d) ++ && d_inode(d->d_parent)->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); ++ rcu_read_lock(); ++ err = iterate_mounts(au_compare_mnt, &args, root.mnt); ++ rcu_read_unlock(); ++ 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 { ++ struct dir_context ctx; ++ int called, found; ++ ino_t ino; ++ char *name; ++ int namelen; ++}; ++ ++static int ++find_name_by_ino(struct dir_context *ctx, const char *name, int namelen, ++ loff_t offset, u64 ino, unsigned int d_type) ++{ ++ struct find_name_by_ino *a = container_of(ctx, struct find_name_by_ino, ++ ctx); ++ ++ 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 = { ++ .ctx = { ++ .actor = find_name_by_ino ++ } ++ }; ++ 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_iterate_dir(file, &arg.ctx); ++ } 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 = d_inode(parent); ++ dentry = vfsub_lookup_one_len_unlocked(arg.name, parent, arg.namelen); ++ AuTraceErrPtr(dentry); ++ if (IS_ERR(dentry)) ++ goto out_name; ++ AuDebugOn(au_test_anon(dentry)); ++ if (unlikely(d_really_is_negative(dentry))) { ++ 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 = au_br_mnt(br); ++ h_sb = h_mnt->mnt_sb; ++ /* todo: call lower fh_to_dentry()? fh_to_parent()? */ ++ lockdep_off(); ++ h_parent = exportfs_decode_fh(h_mnt, (void *)(fh + Fh_tail), ++ fh_len - Fh_tail, fh[Fh_h_type], ++ h_acceptable, /*context*/NULL); ++ lockdep_on(); ++ 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(d_really_is_negative(path.dentry))) ++ goto out_path; ++ ++ if (ino != d_inode(path.dentry)->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_unlock; ++ ++ 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); ++ au_lcnt_inc(&br->br_nfiles); ++ 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)) ++ && d_inode(dentry)->i_generation == fh[Fh_igen]) ++ goto out_unlock; /* success */ ++ ++ dput(dentry); ++ dentry = ERR_PTR(-ESTALE); ++out_unlock: ++ if (br) ++ au_lcnt_dec(&br->br_nfiles); ++ 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_ibtop(inode); ++ if (!dir) { ++ dentry = d_find_any_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; ++ if (d_really_is_positive(parent)) ++ dir = d_inode(parent); ++ } ++ ++ 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_any_alias(h_dir); ++ if (unlikely(!h_parent)) ++ goto out_hparent; ++ ++ err = -EPERM; ++ br = au_sbr(sb, bindex); ++ h_sb = au_br_sb(br); ++ 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_ibtop(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; ++ ++ BUILD_BUG_ON_MSG(IS_BUILTIN(CONFIG_AUFS_FS) ++ && IS_MODULE(CONFIG_EXPORTFS), ++ AUFS_NAME ": unsupported configuration " ++ "CONFIG_EXPORTFS=m and CONFIG_AUFS_FS=y"); ++ ++ 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 -Nurp linux-5.4/fs/aufs/fhsm.c linux-5.4-aufs/fs/aufs/fhsm.c +--- linux-5.4/fs/aufs/fhsm.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/fhsm.c 2019-11-28 01:25:59.064925618 +0200 +@@ -0,0 +1,413 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2011-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * File-based Hierarchy Storage Management ++ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++static aufs_bindex_t au_fhsm_bottom(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ AuDebugOn(!fhsm); ++ return fhsm->fhsm_bottom; ++} ++ ++void au_fhsm_set_bottom(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ AuDebugOn(!fhsm); ++ fhsm->fhsm_bottom = bindex; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_fhsm_test_jiffy(struct au_sbinfo *sbinfo, struct au_branch *br) ++{ ++ struct au_br_fhsm *bf; ++ ++ bf = br->br_fhsm; ++ MtxMustLock(&bf->bf_lock); ++ ++ return !bf->bf_readable ++ || time_after(jiffies, ++ bf->bf_jiffy + sbinfo->si_fhsm.fhsm_expire); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_fhsm_notify(struct super_block *sb, int val) ++{ ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ if (au_fhsm_pid(fhsm) ++ && atomic_read(&fhsm->fhsm_readable) != -1) { ++ atomic_set(&fhsm->fhsm_readable, val); ++ if (val) ++ wake_up(&fhsm->fhsm_wqh); ++ } ++} ++ ++static int au_fhsm_stfs(struct super_block *sb, aufs_bindex_t bindex, ++ struct aufs_stfs *rstfs, int do_lock, int do_notify) ++{ ++ int err; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ br = au_sbr(sb, bindex); ++ AuDebugOn(au_br_rdonly(br)); ++ bf = br->br_fhsm; ++ AuDebugOn(!bf); ++ ++ if (do_lock) ++ mutex_lock(&bf->bf_lock); ++ else ++ MtxMustLock(&bf->bf_lock); ++ ++ /* sb->s_root for NFS is unreliable */ ++ err = au_br_stfs(br, &bf->bf_stfs); ++ if (unlikely(err)) { ++ AuErr1("FHSM failed (%d), b%d, ignored.\n", bindex, err); ++ goto out; ++ } ++ ++ bf->bf_jiffy = jiffies; ++ bf->bf_readable = 1; ++ if (do_notify) ++ au_fhsm_notify(sb, /*val*/1); ++ if (rstfs) ++ *rstfs = bf->bf_stfs; ++ ++out: ++ if (do_lock) ++ mutex_unlock(&bf->bf_lock); ++ au_fhsm_notify(sb, /*val*/1); ++ ++ return err; ++} ++ ++void au_fhsm_wrote(struct super_block *sb, aufs_bindex_t bindex, int force) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ AuDbg("b%d, force %d\n", bindex, force); ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ if (!au_ftest_si(sbinfo, FHSM) ++ || fhsm->fhsm_bottom == bindex) ++ return; ++ ++ br = au_sbr(sb, bindex); ++ bf = br->br_fhsm; ++ AuDebugOn(!bf); ++ mutex_lock(&bf->bf_lock); ++ if (force ++ || au_fhsm_pid(fhsm) ++ || au_fhsm_test_jiffy(sbinfo, br)) ++ err = au_fhsm_stfs(sb, bindex, /*rstfs*/NULL, /*do_lock*/0, ++ /*do_notify*/1); ++ mutex_unlock(&bf->bf_lock); ++} ++ ++void au_fhsm_wrote_all(struct super_block *sb, int force) ++{ ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ /* exclude the bottom */ ++ bbot = au_fhsm_bottom(sb); ++ for (bindex = 0; bindex < bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm)) ++ au_fhsm_wrote(sb, bindex, force); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static __poll_t au_fhsm_poll(struct file *file, struct poll_table_struct *wait) ++{ ++ __poll_t mask; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ mask = 0; ++ sbinfo = file->private_data; ++ fhsm = &sbinfo->si_fhsm; ++ poll_wait(file, &fhsm->fhsm_wqh, wait); ++ if (atomic_read(&fhsm->fhsm_readable)) ++ mask = EPOLLIN /* | EPOLLRDNORM */; ++ ++ if (!mask) ++ AuDbg("mask 0x%x\n", mask); ++ return mask; ++} ++ ++static int au_fhsm_do_read_one(struct aufs_stbr __user *stbr, ++ struct aufs_stfs *stfs, __s16 brid) ++{ ++ int err; ++ ++ err = copy_to_user(&stbr->stfs, stfs, sizeof(*stfs)); ++ if (!err) ++ err = __put_user(brid, &stbr->brid); ++ if (unlikely(err)) ++ err = -EFAULT; ++ ++ return err; ++} ++ ++static ssize_t au_fhsm_do_read(struct super_block *sb, ++ struct aufs_stbr __user *stbr, size_t count) ++{ ++ ssize_t err; ++ int nstbr; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ /* except the bottom branch */ ++ err = 0; ++ nstbr = 0; ++ bbot = au_fhsm_bottom(sb); ++ for (bindex = 0; !err && bindex < bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!au_br_fhsm(br->br_perm)) ++ continue; ++ ++ bf = br->br_fhsm; ++ mutex_lock(&bf->bf_lock); ++ if (bf->bf_readable) { ++ err = -EFAULT; ++ if (count >= sizeof(*stbr)) ++ err = au_fhsm_do_read_one(stbr++, &bf->bf_stfs, ++ br->br_id); ++ if (!err) { ++ bf->bf_readable = 0; ++ count -= sizeof(*stbr); ++ nstbr++; ++ } ++ } ++ mutex_unlock(&bf->bf_lock); ++ } ++ if (!err) ++ err = sizeof(*stbr) * nstbr; ++ ++ return err; ++} ++ ++static ssize_t au_fhsm_read(struct file *file, char __user *buf, size_t count, ++ loff_t *pos) ++{ ++ ssize_t err; ++ int readable; ++ aufs_bindex_t nfhsm, bindex, bbot; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ struct au_branch *br; ++ struct super_block *sb; ++ ++ err = 0; ++ sbinfo = file->private_data; ++ fhsm = &sbinfo->si_fhsm; ++need_data: ++ spin_lock_irq(&fhsm->fhsm_wqh.lock); ++ if (!atomic_read(&fhsm->fhsm_readable)) { ++ if (vfsub_file_flags(file) & O_NONBLOCK) ++ err = -EAGAIN; ++ else ++ err = wait_event_interruptible_locked_irq ++ (fhsm->fhsm_wqh, ++ atomic_read(&fhsm->fhsm_readable)); ++ } ++ spin_unlock_irq(&fhsm->fhsm_wqh.lock); ++ if (unlikely(err)) ++ goto out; ++ ++ /* sb may already be dead */ ++ au_rw_read_lock(&sbinfo->si_rwsem); ++ readable = atomic_read(&fhsm->fhsm_readable); ++ if (readable > 0) { ++ sb = sbinfo->si_sb; ++ AuDebugOn(!sb); ++ /* exclude the bottom branch */ ++ nfhsm = 0; ++ bbot = au_fhsm_bottom(sb); ++ for (bindex = 0; bindex < bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm)) ++ nfhsm++; ++ } ++ err = -EMSGSIZE; ++ if (nfhsm * sizeof(struct aufs_stbr) <= count) { ++ atomic_set(&fhsm->fhsm_readable, 0); ++ err = au_fhsm_do_read(sbinfo->si_sb, (void __user *)buf, ++ count); ++ } ++ } ++ au_rw_read_unlock(&sbinfo->si_rwsem); ++ if (!readable) ++ goto need_data; ++ ++out: ++ return err; ++} ++ ++static int au_fhsm_release(struct inode *inode, struct file *file) ++{ ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ /* sb may already be dead */ ++ sbinfo = file->private_data; ++ fhsm = &sbinfo->si_fhsm; ++ spin_lock(&fhsm->fhsm_spin); ++ fhsm->fhsm_pid = 0; ++ spin_unlock(&fhsm->fhsm_spin); ++ kobject_put(&sbinfo->si_kobj); ++ ++ return 0; ++} ++ ++static const struct file_operations au_fhsm_fops = { ++ .owner = THIS_MODULE, ++ .llseek = noop_llseek, ++ .read = au_fhsm_read, ++ .poll = au_fhsm_poll, ++ .release = au_fhsm_release ++}; ++ ++int au_fhsm_fd(struct super_block *sb, int oflags) ++{ ++ int err, fd; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ err = -EPERM; ++ if (unlikely(!capable(CAP_SYS_ADMIN))) ++ goto out; ++ ++ err = -EINVAL; ++ if (unlikely(oflags & ~(O_CLOEXEC | O_NONBLOCK))) ++ goto out; ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ spin_lock(&fhsm->fhsm_spin); ++ if (!fhsm->fhsm_pid) ++ fhsm->fhsm_pid = current->pid; ++ else ++ err = -EBUSY; ++ spin_unlock(&fhsm->fhsm_spin); ++ if (unlikely(err)) ++ goto out; ++ ++ oflags |= O_RDONLY; ++ /* oflags |= FMODE_NONOTIFY; */ ++ fd = anon_inode_getfd("[aufs_fhsm]", &au_fhsm_fops, sbinfo, oflags); ++ err = fd; ++ if (unlikely(fd < 0)) ++ goto out_pid; ++ ++ /* succeed regardless 'fhsm' status */ ++ kobject_get(&sbinfo->si_kobj); ++ si_noflush_read_lock(sb); ++ if (au_ftest_si(sbinfo, FHSM)) ++ au_fhsm_wrote_all(sb, /*force*/0); ++ si_read_unlock(sb); ++ goto out; /* success */ ++ ++out_pid: ++ spin_lock(&fhsm->fhsm_spin); ++ fhsm->fhsm_pid = 0; ++ spin_unlock(&fhsm->fhsm_spin); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_fhsm_br_alloc(struct au_branch *br) ++{ ++ int err; ++ ++ err = 0; ++ br->br_fhsm = kmalloc(sizeof(*br->br_fhsm), GFP_NOFS); ++ if (br->br_fhsm) ++ au_br_fhsm_init(br->br_fhsm); ++ else ++ err = -ENOMEM; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_fhsm_fin(struct super_block *sb) ++{ ++ au_fhsm_notify(sb, /*val*/-1); ++} ++ ++void au_fhsm_init(struct au_sbinfo *sbinfo) ++{ ++ struct au_fhsm *fhsm; ++ ++ fhsm = &sbinfo->si_fhsm; ++ spin_lock_init(&fhsm->fhsm_spin); ++ init_waitqueue_head(&fhsm->fhsm_wqh); ++ atomic_set(&fhsm->fhsm_readable, 0); ++ fhsm->fhsm_expire ++ = msecs_to_jiffies(AUFS_FHSM_CACHE_DEF_SEC * MSEC_PER_SEC); ++ fhsm->fhsm_bottom = -1; ++} ++ ++void au_fhsm_set(struct au_sbinfo *sbinfo, unsigned int sec) ++{ ++ sbinfo->si_fhsm.fhsm_expire ++ = msecs_to_jiffies(sec * MSEC_PER_SEC); ++} ++ ++void au_fhsm_show(struct seq_file *seq, struct au_sbinfo *sbinfo) ++{ ++ unsigned int u; ++ ++ if (!au_ftest_si(sbinfo, FHSM)) ++ return; ++ ++ u = jiffies_to_msecs(sbinfo->si_fhsm.fhsm_expire) / MSEC_PER_SEC; ++ if (u != AUFS_FHSM_CACHE_DEF_SEC) ++ seq_printf(seq, ",fhsm_sec=%u", u); ++} +diff -Nurp linux-5.4/fs/aufs/file.c linux-5.4-aufs/fs/aufs/file.c +--- linux-5.4/fs/aufs/file.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/file.c 2019-11-28 01:25:59.065925618 +0200 +@@ -0,0 +1,850 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * 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, int force_wr) ++{ ++ 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; ++ ++ /* 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 || d_is_negative(h_dentry))) ++ goto out; ++ h_inode = d_inode(h_dentry); ++ spin_lock(&h_dentry->d_lock); ++ err = (!d_unhashed(dentry) && d_unlinked(h_dentry)) ++ /* || !d_inode(dentry)->i_nlink */ ++ ; ++ spin_unlock(&h_dentry->d_lock); ++ if (unlikely(err)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, bindex); ++ err = au_br_test_oflag(flags, br); ++ h_file = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ /* drop flags for writing */ ++ if (au_test_ro(sb, bindex, d_inode(dentry))) { ++ if (force_wr && !(flags & O_WRONLY)) ++ force_wr = 0; ++ flags = au_file_roflags(flags); ++ if (force_wr) { ++ h_file = ERR_PTR(-EROFS); ++ flags = au_file_roflags(flags); ++ if (unlikely(vfsub_native_ro(h_inode) ++ || IS_APPEND(h_inode))) ++ goto out; ++ flags &= ~O_ACCMODE; ++ flags |= O_WRONLY; ++ } ++ } ++ flags &= ~O_CREAT; ++ au_lcnt_inc(&br->br_nfiles); ++ h_path.dentry = h_dentry; ++ h_path.mnt = au_br_mnt(br); ++ h_file = vfsub_dentry_open(&h_path, flags); ++ if (IS_ERR(h_file)) ++ goto out_br; ++ ++ if (flags & __FMODE_EXEC) { ++ 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: ++ au_lcnt_dec(&br->br_nfiles); ++out: ++ return h_file; ++} ++ ++static int au_cmoo(struct dentry *dentry) ++{ ++ int err, cmoo, matched; ++ unsigned int udba; ++ struct path h_path; ++ struct au_pin pin; ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = -1, ++ .bsrc = -1, ++ .len = -1, ++ .pin = &pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ struct inode *delegated; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ pid_t pid; ++ struct au_branch *br; ++ struct dentry *parent; ++ struct au_hinode *hdir; ++ ++ DiMustWriteLock(dentry); ++ IiMustWriteLock(d_inode(dentry)); ++ ++ err = 0; ++ if (IS_ROOT(dentry)) ++ goto out; ++ cpg.bsrc = au_dbtop(dentry); ++ if (!cpg.bsrc) ++ goto out; ++ ++ sb = dentry->d_sb; ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ pid = au_fhsm_pid(fhsm); ++ rcu_read_lock(); ++ matched = (pid ++ && (current->pid == pid ++ || rcu_dereference(current->real_parent)->pid == pid)); ++ rcu_read_unlock(); ++ if (matched) ++ goto out; ++ ++ br = au_sbr(sb, cpg.bsrc); ++ cmoo = au_br_cmoo(br->br_perm); ++ if (!cmoo) ++ goto out; ++ if (!d_is_reg(dentry)) ++ cmoo &= AuBrAttr_COO_ALL; ++ if (!cmoo) ++ goto out; ++ ++ parent = dget_parent(dentry); ++ di_write_lock_parent(parent); ++ err = au_wbr_do_copyup_bu(dentry, cpg.bsrc - 1); ++ cpg.bdst = err; ++ if (unlikely(err < 0)) { ++ err = 0; /* there is no upper writable branch */ ++ goto out_dgrade; ++ } ++ AuDbg("bsrc %d, bdst %d\n", cpg.bsrc, cpg.bdst); ++ ++ /* do not respect the coo attrib for the target branch */ ++ err = au_cpup_dirs(dentry, cpg.bdst); ++ if (unlikely(err)) ++ goto out_dgrade; ++ ++ di_downgrade_lock(parent, AuLock_IR); ++ udba = au_opt_udba(sb); ++ err = au_pin(&pin, dentry, cpg.bdst, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&pin); ++ if (unlikely(err)) ++ goto out_parent; ++ if (!(cmoo & AuBrWAttr_MOO)) ++ goto out_parent; /* success */ ++ ++ err = au_pin(&pin, dentry, cpg.bsrc, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ h_path.mnt = au_br_mnt(br); ++ h_path.dentry = au_h_dptr(dentry, cpg.bsrc); ++ hdir = au_hi(d_inode(parent), cpg.bsrc); ++ delegated = NULL; ++ err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated, /*force*/1); ++ au_unpin(&pin); ++ /* todo: keep h_dentry or not? */ ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) { ++ pr_err("unlink %pd after coo failed (%d), ignored\n", ++ dentry, err); ++ err = 0; ++ } ++ goto out_parent; /* success */ ++ ++out_dgrade: ++ di_downgrade_lock(parent, AuLock_IR); ++out_parent: ++ di_read_unlock(parent, AuLock_IR); ++ dput(parent); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_do_open(struct file *file, struct au_do_open_args *args) ++{ ++ int err, aopen = args->aopen; ++ struct dentry *dentry; ++ struct au_finfo *finfo; ++ ++ if (!aopen) ++ err = au_finfo_init(file, args->fidir); ++ else { ++ lockdep_off(); ++ err = au_finfo_init(file, args->fidir); ++ lockdep_on(); ++ } ++ if (unlikely(err)) ++ goto out; ++ ++ dentry = file->f_path.dentry; ++ AuDebugOn(IS_ERR_OR_NULL(dentry)); ++ di_write_lock_child(dentry); ++ err = au_cmoo(dentry); ++ di_downgrade_lock(dentry, AuLock_IR); ++ if (!err) { ++ if (!aopen) ++ err = args->open(file, vfsub_file_flags(file), NULL); ++ else { ++ lockdep_off(); ++ err = args->open(file, vfsub_file_flags(file), ++ args->h_file); ++ lockdep_on(); ++ } ++ } ++ di_read_unlock(dentry, AuLock_IR); ++ ++ finfo = au_fi(file); ++ if (!err) { ++ finfo->fi_file = file; ++ au_hbl_add(&finfo->fi_hlist, ++ &au_sbi(file->f_path.dentry->d_sb)->si_files); ++ } ++ if (!aopen) ++ fi_write_unlock(file); ++ else { ++ lockdep_off(); ++ fi_write_unlock(file); ++ lockdep_on(); ++ } ++ if (unlikely(err)) { ++ finfo->fi_hdir = NULL; ++ au_finfo_fin(file); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_reopen_nondir(struct file *file) ++{ ++ int err; ++ aufs_bindex_t btop; ++ struct dentry *dentry; ++ struct au_branch *br; ++ struct file *h_file, *h_file_tmp; ++ ++ dentry = file->f_path.dentry; ++ btop = au_dbtop(dentry); ++ br = au_sbr(dentry->d_sb, btop); ++ h_file_tmp = NULL; ++ if (au_fbtop(file) == btop) { ++ 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_lcnt_inc(&br->br_nfiles); ++ au_set_h_fptr(file, btop, NULL); ++ } ++ AuDebugOn(au_fi(file)->fi_hdir); ++ /* ++ * it can happen ++ * file exists on both of rw and ro ++ * open --> dbtop and fbtop are both 0 ++ * prepend a branch as rw, "rw" become ro ++ * remove rw/file ++ * delete the top branch, "rw" becomes rw again ++ * --> dbtop is 1, fbtop is still 0 ++ * write --> fbtop is 0 but dbtop is 1 ++ */ ++ /* AuDebugOn(au_fbtop(file) < btop); */ ++ ++ h_file = au_h_open(dentry, btop, vfsub_file_flags(file) & ~O_TRUNC, ++ file, /*force_wr*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) { ++ if (h_file_tmp) { ++ /* revert */ ++ au_set_h_fptr(file, btop, h_file_tmp); ++ h_file_tmp = NULL; ++ } ++ goto out; /* todo: close all? */ ++ } ++ ++ err = 0; ++ au_set_fbtop(file, btop); ++ au_set_h_fptr(file, btop, h_file); ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ ++out: ++ if (h_file_tmp) { ++ fput(h_file_tmp); ++ au_lcnt_dec(&br->br_nfiles); ++ } ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_reopen_wh(struct file *file, aufs_bindex_t btgt, ++ struct dentry *hi_wh) ++{ ++ int err; ++ aufs_bindex_t btop; ++ struct au_dinfo *dinfo; ++ struct dentry *h_dentry; ++ struct au_hdentry *hdp; ++ ++ dinfo = au_di(file->f_path.dentry); ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ btop = dinfo->di_btop; ++ dinfo->di_btop = btgt; ++ hdp = au_hdentry(dinfo, btgt); ++ h_dentry = hdp->hd_dentry; ++ hdp->hd_dentry = hi_wh; ++ err = au_reopen_nondir(file); ++ hdp->hd_dentry = h_dentry; ++ dinfo->di_btop = btop; ++ ++ return err; ++} ++ ++static int au_ready_to_write_wh(struct file *file, loff_t len, ++ aufs_bindex_t bcpup, struct au_pin *pin) ++{ ++ int err; ++ struct inode *inode, *h_inode; ++ struct dentry *h_dentry, *hi_wh; ++ struct au_cp_generic cpg = { ++ .dentry = file->f_path.dentry, ++ .bdst = bcpup, ++ .bsrc = -1, ++ .len = len, ++ .pin = pin ++ }; ++ ++ au_update_dbtop(cpg.dentry); ++ inode = d_inode(cpg.dentry); ++ h_inode = NULL; ++ if (au_dbtop(cpg.dentry) <= bcpup ++ && au_dbbot(cpg.dentry) >= bcpup) { ++ h_dentry = au_h_dptr(cpg.dentry, bcpup); ++ if (h_dentry && d_is_positive(h_dentry)) ++ h_inode = d_inode(h_dentry); ++ } ++ hi_wh = au_hi_wh(inode, bcpup); ++ if (!hi_wh && !h_inode) ++ err = au_sio_cpup_wh(&cpg, file); ++ else ++ /* already copied-up after unlink */ ++ err = au_reopen_wh(file, bcpup, hi_wh); ++ ++ if (!err ++ && (inode->i_nlink > 1 ++ || (inode->i_state & I_LINKABLE)) ++ && au_opt_test(au_mntflags(cpg.dentry->d_sb), PLINK)) ++ au_plink_append(inode, bcpup, au_h_dptr(cpg.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 dbtop; ++ struct dentry *parent; ++ struct inode *inode; ++ struct super_block *sb; ++ struct file *h_file; ++ struct au_cp_generic cpg = { ++ .dentry = file->f_path.dentry, ++ .bdst = -1, ++ .bsrc = -1, ++ .len = len, ++ .pin = pin, ++ .flags = AuCpup_DTIME ++ }; ++ ++ sb = cpg.dentry->d_sb; ++ inode = d_inode(cpg.dentry); ++ cpg.bsrc = au_fbtop(file); ++ err = au_test_ro(sb, cpg.bsrc, inode); ++ if (!err && (au_hf_top(file)->f_mode & FMODE_WRITE)) { ++ err = au_pin(pin, cpg.dentry, cpg.bsrc, AuOpt_UDBA_NONE, ++ /*flags*/0); ++ goto out; ++ } ++ ++ /* need to cpup or reopen */ ++ parent = dget_parent(cpg.dentry); ++ di_write_lock_parent(parent); ++ err = AuWbrCopyup(au_sbi(sb), cpg.dentry); ++ cpg.bdst = err; ++ if (unlikely(err < 0)) ++ goto out_dgrade; ++ err = 0; ++ ++ if (!d_unhashed(cpg.dentry) && !au_h_dptr(parent, cpg.bdst)) { ++ err = au_cpup_dirs(cpg.dentry, cpg.bdst); ++ if (unlikely(err)) ++ goto out_dgrade; ++ } ++ ++ err = au_pin(pin, cpg.dentry, cpg.bdst, AuOpt_UDBA_NONE, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_dgrade; ++ ++ dbtop = au_dbtop(cpg.dentry); ++ if (dbtop <= cpg.bdst) ++ cpg.bsrc = cpg.bdst; ++ ++ if (dbtop <= cpg.bdst /* just reopen */ ++ || !d_unhashed(cpg.dentry) /* copyup and reopen */ ++ ) { ++ h_file = au_h_open_pre(cpg.dentry, cpg.bsrc, /*force_wr*/0); ++ if (IS_ERR(h_file)) ++ err = PTR_ERR(h_file); ++ else { ++ di_downgrade_lock(parent, AuLock_IR); ++ if (dbtop > cpg.bdst) ++ err = au_sio_cpup_simple(&cpg); ++ if (!err) ++ err = au_reopen_nondir(file); ++ au_h_open_post(cpg.dentry, cpg.bsrc, h_file); ++ } ++ } else { /* copyup as wh and reopen */ ++ /* ++ * since writable hfsplus branch is not supported, ++ * h_open_pre/post() are unnecessary. ++ */ ++ err = au_ready_to_write_wh(file, len, cpg.bdst, pin); ++ di_downgrade_lock(parent, AuLock_IR); ++ } ++ ++ 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 super_block *sb; ++ struct inode *inode; ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ 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; ++ struct au_pin pin; ++ struct au_finfo *finfo; ++ struct dentry *parent, *hi_wh; ++ struct inode *inode; ++ struct super_block *sb; ++ struct au_cp_generic cpg = { ++ .dentry = file->f_path.dentry, ++ .bdst = -1, ++ .bsrc = -1, ++ .len = -1, ++ .pin = &pin, ++ .flags = AuCpup_DTIME ++ }; ++ ++ FiMustWriteLock(file); ++ ++ err = 0; ++ finfo = au_fi(file); ++ sb = cpg.dentry->d_sb; ++ inode = d_inode(cpg.dentry); ++ cpg.bdst = au_ibtop(inode); ++ if (cpg.bdst == finfo->fi_btop || IS_ROOT(cpg.dentry)) ++ goto out; ++ ++ parent = dget_parent(cpg.dentry); ++ if (au_test_ro(sb, cpg.bdst, inode)) { ++ di_read_lock_parent(parent, !AuLock_IR); ++ err = AuWbrCopyup(au_sbi(sb), cpg.dentry); ++ cpg.bdst = 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, cpg.bdst); ++ if (!S_ISDIR(inode->i_mode) ++ && au_opt_test(au_mntflags(sb), PLINK) ++ && au_plink_test(inode) ++ && !d_unhashed(cpg.dentry) ++ && cpg.bdst < au_dbtop(cpg.dentry)) { ++ err = au_test_and_cpup_dirs(cpg.dentry, cpg.bdst); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ /* always superio. */ ++ err = au_pin(&pin, cpg.dentry, cpg.bdst, AuOpt_UDBA_NONE, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (!err) { ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&pin); ++ } ++ } else if (hi_wh) { ++ /* already copied-up after unlink */ ++ err = au_reopen_wh(file, cpg.bdst, 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, bbot, 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_path.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; ++ bbot = fidir->fd_bbot; ++ for (bindex = finfo->fi_btop; bindex <= bbot; 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_path.dentry)) { ++ bbot = au_sbbot(sb); ++ for (finfo->fi_btop = 0; finfo->fi_btop <= bbot; ++ finfo->fi_btop++, p++) ++ if (p->hf_file) { ++ if (file_inode(p->hf_file)) ++ break; ++ au_hfput(p, /*execed*/0); ++ } ++ } else { ++ bbot = au_br_index(sb, brid); ++ for (finfo->fi_btop = 0; finfo->fi_btop < bbot; ++ finfo->fi_btop++, p++) ++ if (p->hf_file) ++ au_hfput(p, /*execed*/0); ++ bbot = au_sbbot(sb); ++ } ++ ++ p = fidir->fd_hfile + bbot; ++ for (fidir->fd_bbot = bbot; fidir->fd_bbot >= finfo->fi_btop; ++ fidir->fd_bbot--, p--) ++ if (p->hf_file) { ++ if (file_inode(p->hf_file)) ++ break; ++ au_hfput(p, /*execed*/0); ++ } ++ 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, nbr; ++ aufs_bindex_t bbot, bindex; ++ struct dentry *dentry; ++ struct super_block *sb; ++ struct au_finfo *finfo; ++ struct au_hfile *hfile; ++ ++ dentry = file->f_path.dentry; ++ sb = dentry->d_sb; ++ nbr = au_sbbot(sb) + 1; ++ finfo = au_fi(file); ++ if (!finfo->fi_hdir) { ++ hfile = &finfo->fi_htop; ++ AuDebugOn(!hfile->hf_file); ++ bindex = au_br_index(sb, hfile->hf_br->br_id); ++ AuDebugOn(bindex < 0); ++ if (bindex != finfo->fi_btop) ++ au_set_fbtop(file, bindex); ++ } else { ++ err = au_fidir_realloc(finfo, nbr, /*may_shrink*/0); ++ 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 (finfo->fi_hdir) ++ /* harmless if err */ ++ au_fidir_realloc(finfo, nbr, /*may_shrink*/1); ++ 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) { ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); bindex <= bbot; 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, unsigned int fi_lsc) ++{ ++ int err; ++ unsigned int sigen, figen; ++ aufs_bindex_t btop; ++ unsigned char pseudo_link; ++ struct dentry *dentry; ++ struct inode *inode; ++ ++ err = 0; ++ dentry = file->f_path.dentry; ++ inode = d_inode(dentry); ++ sigen = au_sigen(dentry->d_sb); ++ fi_write_lock_nested(file, fi_lsc); ++ figen = au_figen(file); ++ if (!fi_lsc) ++ di_write_lock_child(dentry); ++ else ++ di_write_lock_child2(dentry); ++ btop = au_dbtop(dentry); ++ pseudo_link = (btop != au_ibtop(inode)); ++ if (sigen == figen && !pseudo_link && au_fbtop(file) == btop) { ++ 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(struct kiocb *iocb, struct iov_iter *iter) ++{ 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 int offset, ++ unsigned int length) ++{ AuUnsupport(); } ++static int aufs_releasepage(struct page *page, gfp_t gfp) ++{ AuUnsupport(); return 0; } ++#if 0 /* called by memory compaction regardless file */ ++static int aufs_migratepage(struct address_space *mapping, struct page *newpage, ++ struct page *page, enum migrate_mode mode) ++{ AuUnsupport(); return 0; } ++#endif ++static bool aufs_isolate_page(struct page *page, isolate_mode_t mode) ++{ AuUnsupport(); return true; } ++static void aufs_putback_page(struct page *page) ++{ AuUnsupport(); } ++static int aufs_launder_page(struct page *page) ++{ AuUnsupport(); return 0; } ++static int aufs_is_partially_uptodate(struct page *page, ++ unsigned long from, ++ unsigned long count) ++{ AuUnsupport(); return 0; } ++static void aufs_is_dirty_writeback(struct page *page, bool *dirty, ++ bool *writeback) ++{ AuUnsupport(); } ++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, ++#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, ++ /* is fallback_migrate_page ok? */ ++ /* .migratepage = aufs_migratepage, */ ++ .isolate_page = aufs_isolate_page, ++ .putback_page = aufs_putback_page, ++ .launder_page = aufs_launder_page, ++ .is_partially_uptodate = aufs_is_partially_uptodate, ++ .is_dirty_writeback = aufs_is_dirty_writeback, ++ .error_remove_page = aufs_error_remove_page, ++ .swap_activate = aufs_swap_activate, ++ .swap_deactivate = aufs_swap_deactivate ++#endif /* CONFIG_AUFS_DEBUG */ ++}; +diff -Nurp linux-5.4/fs/aufs/file.h linux-5.4-aufs/fs/aufs/file.h +--- linux-5.4/fs/aufs/file.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/file.h 2019-11-28 01:25:59.065925618 +0200 +@@ -0,0 +1,329 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * file operations ++ */ ++ ++#ifndef __AUFS_FILE_H__ ++#define __AUFS_FILE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#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 */ ++ ++ struct hlist_bl_node fi_hlist; ++ struct file *fi_file; /* very ugly */ ++ struct rcu_head rcu; ++} ____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 force_wr); ++struct au_do_open_args { ++ int aopen; ++ int (*open)(struct file *file, int flags, ++ struct file *h_file); ++ struct au_fidir *fidir; ++ struct file *h_file; ++}; ++int au_do_open(struct file *file, struct au_do_open_args *args); ++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, unsigned int fi_lsc); ++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 ++__poll_t aufs_poll(struct file *file, struct poll_table_struct *pt); ++#endif ++ ++#ifdef CONFIG_AUFS_BR_HFSPLUS ++/* hfsplus.c */ ++struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex, ++ int force_wr); ++void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex, ++ struct file *h_file); ++#else ++AuStub(struct file *, au_h_open_pre, return NULL, struct dentry *dentry, ++ aufs_bindex_t bindex, int force_wr) ++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, struct file *h_file); ++int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file); ++struct file *au_read_pre(struct file *file, int keep_fi, unsigned int lsc); ++ ++/* finfo.c */ ++void au_hfput(struct au_hfile *hf, int execed); ++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, int may_shrink); ++ ++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); ++long aufs_compat_ioctl_nondir(struct file *file, unsigned int cmd, ++ unsigned long arg); ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_finfo *au_fi(struct file *file) ++{ ++ return file->private_data; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define fi_read_lock(f) au_rw_read_lock(&au_fi(f)->fi_rwsem) ++#define fi_write_lock(f) au_rw_write_lock(&au_fi(f)->fi_rwsem) ++#define fi_read_trylock(f) au_rw_read_trylock(&au_fi(f)->fi_rwsem) ++#define fi_write_trylock(f) au_rw_write_trylock(&au_fi(f)->fi_rwsem) ++/* ++#define fi_read_trylock_nested(f) \ ++ au_rw_read_trylock_nested(&au_fi(f)->fi_rwsem) ++#define fi_write_trylock_nested(f) \ ++ au_rw_write_trylock_nested(&au_fi(f)->fi_rwsem) ++*/ ++ ++#define fi_read_unlock(f) au_rw_read_unlock(&au_fi(f)->fi_rwsem) ++#define fi_write_unlock(f) au_rw_write_unlock(&au_fi(f)->fi_rwsem) ++#define fi_downgrade_lock(f) au_rw_dgrade_lock(&au_fi(f)->fi_rwsem) ++ ++/* lock subclass for finfo */ ++enum { ++ AuLsc_FI_1, ++ AuLsc_FI_2 ++}; ++ ++static inline void fi_read_lock_nested(struct file *f, unsigned int lsc) ++{ ++ au_rw_read_lock_nested(&au_fi(f)->fi_rwsem, lsc); ++} ++ ++static inline void fi_write_lock_nested(struct file *f, unsigned int lsc) ++{ ++ au_rw_write_lock_nested(&au_fi(f)->fi_rwsem, lsc); ++} ++ ++/* ++ * fi_read_lock_1, fi_write_lock_1, ++ * fi_read_lock_2, fi_write_lock_2 ++ */ ++#define AuReadLockFunc(name) \ ++static inline void fi_read_lock_##name(struct file *f) \ ++{ fi_read_lock_nested(f, AuLsc_FI_##name); } ++ ++#define AuWriteLockFunc(name) \ ++static inline void fi_write_lock_##name(struct file *f) \ ++{ fi_write_lock_nested(f, AuLsc_FI_##name); } ++ ++#define AuRWLockFuncs(name) \ ++ AuReadLockFunc(name) \ ++ AuWriteLockFunc(name) ++ ++AuRWLockFuncs(1); ++AuRWLockFuncs(2); ++ ++#undef AuReadLockFunc ++#undef AuWriteLockFunc ++#undef AuRWLockFuncs ++ ++#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_fbtop(struct file *file) ++{ ++ FiMustAnyLock(file); ++ return au_fi(file)->fi_btop; ++} ++ ++static inline aufs_bindex_t au_fbbot_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_fbtop(struct file *file, aufs_bindex_t bindex) ++{ ++ FiMustWriteLock(file); ++ au_fi(file)->fi_btop = bindex; ++} ++ ++static inline void au_set_fbbot_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) ++{ ++ get_file(file); ++ vma->vm_prfile = file; ++#ifndef CONFIG_MMU ++ get_file(file); ++ vma->vm_region->vm_prfile = file; ++#endif ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_FILE_H__ */ +diff -Nurp linux-5.4/fs/aufs/finfo.c linux-5.4-aufs/fs/aufs/finfo.c +--- linux-5.4/fs/aufs/finfo.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/finfo.c 2019-11-28 01:25:59.065925618 +0200 +@@ -0,0 +1,136 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * file private data ++ */ ++ ++#include "aufs.h" ++ ++void au_hfput(struct au_hfile *hf, int execed) ++{ ++ if (execed) ++ allow_write_access(hf->hf_file); ++ fput(hf->hf_file); ++ hf->hf_file = NULL; ++ au_lcnt_dec(&hf->hf_br->br_nfiles); ++ 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, vfsub_file_execed(file)); ++ if (val) { ++ FiMustWriteLock(file); ++ AuDebugOn(IS_ERR_OR_NULL(file->f_path.dentry)); ++ hf->hf_file = val; ++ hf->hf_br = au_sbr(file->f_path.dentry->d_sb, bindex); ++ } ++} ++ ++void au_update_figen(struct file *file) ++{ ++ atomic_set(&au_fi(file)->fi_generation, au_digen(file->f_path.dentry)); ++ /* smp_mb(); */ /* atomic_set */ ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_fidir *au_fidir_alloc(struct super_block *sb) ++{ ++ struct au_fidir *fidir; ++ int nbr; ++ ++ nbr = au_sbbot(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; ++ } ++ ++ return fidir; ++} ++ ++int au_fidir_realloc(struct au_finfo *finfo, int nbr, int may_shrink) ++{ ++ 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, may_shrink); ++ 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_lcnt_dec(&au_sbi(file->f_path.dentry->d_sb)->si_nfiles); ++ ++ 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; ++ ++ au_rw_init(&finfo->fi_rwsem); ++} ++ ++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_path.dentry; ++ finfo = au_cache_alloc_finfo(); ++ if (unlikely(!finfo)) ++ goto out; ++ ++ err = 0; ++ au_lcnt_inc(&au_sbi(dentry->d_sb)->si_nfiles); ++ 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 -Nurp linux-5.4/fs/aufs/f_op.c linux-5.4-aufs/fs/aufs/f_op.c +--- linux-5.4/fs/aufs/f_op.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/f_op.c 2019-11-28 01:25:59.064925618 +0200 +@@ -0,0 +1,806 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * file and vm operations ++ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++int au_do_open_nondir(struct file *file, int flags, struct file *h_file) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct dentry *dentry, *h_dentry; ++ struct au_finfo *finfo; ++ struct inode *h_inode; ++ ++ FiMustWriteLock(file); ++ ++ err = 0; ++ dentry = file->f_path.dentry; ++ AuDebugOn(IS_ERR_OR_NULL(dentry)); ++ finfo = au_fi(file); ++ memset(&finfo->fi_htop, 0, sizeof(finfo->fi_htop)); ++ atomic_set(&finfo->fi_mmapped, 0); ++ bindex = au_dbtop(dentry); ++ if (!h_file) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ err = vfsub_test_mntns(file->f_path.mnt, h_dentry->d_sb); ++ if (unlikely(err)) ++ goto out; ++ h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0); ++ if (IS_ERR(h_file)) { ++ err = PTR_ERR(h_file); ++ goto out; ++ } ++ } else { ++ h_dentry = h_file->f_path.dentry; ++ err = vfsub_test_mntns(file->f_path.mnt, h_dentry->d_sb); ++ if (unlikely(err)) ++ goto out; ++ /* br ref is already inc-ed */ ++ } ++ ++ if ((flags & __O_TMPFILE) ++ && !(flags & O_EXCL)) { ++ h_inode = file_inode(h_file); ++ spin_lock(&h_inode->i_lock); ++ h_inode->i_state |= I_LINKABLE; ++ spin_unlock(&h_inode->i_lock); ++ } ++ au_set_fbtop(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; ++ struct au_do_open_args args = { ++ .open = au_do_open_nondir ++ }; ++ ++ AuDbg("%pD, f_flags 0x%x, f_mode 0x%x\n", ++ file, vfsub_file_flags(file), file->f_mode); ++ ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ err = au_do_open(file, &args); ++ 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); ++ au_hbl_del(&finfo->fi_hlist, ++ &au_sbi(file->f_path.dentry->d_sb)->si_files); ++ 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-management (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. ++ */ ++ ++/* Callers should call au_read_post() or fput() in the end */ ++struct file *au_read_pre(struct file *file, int keep_fi, unsigned int lsc) ++{ ++ struct file *h_file; ++ int err; ++ ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0, lsc); ++ if (!err) { ++ di_read_unlock(file->f_path.dentry, AuLock_IR); ++ h_file = au_hf_top(file); ++ get_file(h_file); ++ if (!keep_fi) ++ fi_read_unlock(file); ++ } else ++ h_file = ERR_PTR(err); ++ ++ return h_file; ++} ++ ++static void au_read_post(struct inode *inode, struct file *h_file) ++{ ++ /* update without lock, I don't think it a problem */ ++ fsstack_copy_attr_atime(inode, file_inode(h_file)); ++ fput(h_file); ++} ++ ++struct au_write_pre { ++ /* input */ ++ unsigned int lsc; ++ ++ /* output */ ++ blkcnt_t blks; ++ aufs_bindex_t btop; ++}; ++ ++/* ++ * return with iinfo is write-locked ++ * callers should call au_write_post() or iinfo_write_unlock() + fput() in the ++ * end ++ */ ++static struct file *au_write_pre(struct file *file, int do_ready, ++ struct au_write_pre *wpre) ++{ ++ struct file *h_file; ++ struct dentry *dentry; ++ int err; ++ unsigned int lsc; ++ struct au_pin pin; ++ ++ lsc = 0; ++ if (wpre) ++ lsc = wpre->lsc; ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1, lsc); ++ h_file = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ dentry = file->f_path.dentry; ++ if (do_ready) { ++ err = au_ready_to_write(file, -1, &pin); ++ if (unlikely(err)) { ++ h_file = ERR_PTR(err); ++ di_write_unlock(dentry); ++ goto out_fi; ++ } ++ } ++ ++ di_downgrade_lock(dentry, /*flags*/0); ++ if (wpre) ++ wpre->btop = au_fbtop(file); ++ h_file = au_hf_top(file); ++ get_file(h_file); ++ if (wpre) ++ wpre->blks = file_inode(h_file)->i_blocks; ++ if (do_ready) ++ au_unpin(&pin); ++ di_read_unlock(dentry, /*flags*/0); ++ ++out_fi: ++ fi_write_unlock(file); ++out: ++ return h_file; ++} ++ ++static void au_write_post(struct inode *inode, struct file *h_file, ++ struct au_write_pre *wpre, ssize_t written) ++{ ++ struct inode *h_inode; ++ ++ au_cpup_attr_timesizes(inode); ++ AuDebugOn(au_ibtop(inode) != wpre->btop); ++ h_inode = file_inode(h_file); ++ inode->i_mode = h_inode->i_mode; ++ ii_write_unlock(inode); ++ /* AuDbg("blks %llu, %llu\n", (u64)blks, (u64)h_inode->i_blocks); */ ++ if (written > 0) ++ au_fhsm_wrote(inode->i_sb, wpre->btop, ++ /*force*/h_inode->i_blocks > wpre->blks); ++ fput(h_file); ++} ++ ++static ssize_t aufs_read(struct file *file, char __user *buf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ struct inode *inode; ++ struct file *h_file; ++ struct super_block *sb; ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/0, /*lsc*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ /* 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; */ ++ au_read_post(inode, 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) { ++ inode_lock(inode); ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (!err) ++ break; ++ inode_unlock(inode); ++ 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_write_pre wpre; ++ struct inode *inode; ++ struct file *h_file; ++ char __user *buf = (char __user *)ubuf; ++ ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ wpre.lsc = 0; ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = vfsub_write_u(h_file, buf, count, ppos); ++ au_write_post(inode, h_file, &wpre, err); ++ ++out: ++ si_read_unlock(inode->i_sb); ++ inode_unlock(inode); ++ return err; ++} ++ ++static ssize_t au_do_iter(struct file *h_file, int rw, struct kiocb *kio, ++ struct iov_iter *iov_iter) ++{ ++ ssize_t err; ++ struct file *file; ++ ssize_t (*iter)(struct kiocb *, struct iov_iter *); ++ ++ err = security_file_permission(h_file, rw); ++ if (unlikely(err)) ++ goto out; ++ ++ err = -ENOSYS; ++ iter = NULL; ++ if (rw == MAY_READ) ++ iter = h_file->f_op->read_iter; ++ else if (rw == MAY_WRITE) ++ iter = h_file->f_op->write_iter; ++ ++ file = kio->ki_filp; ++ kio->ki_filp = h_file; ++ if (iter) { ++ lockdep_off(); ++ err = iter(kio, iov_iter); ++ lockdep_on(); ++ } else ++ /* currently there is no such fs */ ++ WARN_ON_ONCE(1); ++ kio->ki_filp = file; ++ ++out: ++ return err; ++} ++ ++static ssize_t aufs_read_iter(struct kiocb *kio, struct iov_iter *iov_iter) ++{ ++ ssize_t err; ++ struct file *file, *h_file; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ file = kio->ki_filp; ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/1, /*lsc*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ if (au_test_loopback_kthread()) { ++ au_warn_loopback(h_file->f_path.dentry->d_sb); ++ if (file->f_mapping != h_file->f_mapping) { ++ file->f_mapping = h_file->f_mapping; ++ smp_mb(); /* unnecessary? */ ++ } ++ } ++ fi_read_unlock(file); ++ ++ err = au_do_iter(h_file, MAY_READ, kio, iov_iter); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ au_read_post(inode, h_file); ++ ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++static ssize_t aufs_write_iter(struct kiocb *kio, struct iov_iter *iov_iter) ++{ ++ ssize_t err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *file, *h_file; ++ ++ file = kio->ki_filp; ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ wpre.lsc = 0; ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = au_do_iter(h_file, MAY_WRITE, kio, iov_iter); ++ au_write_post(inode, h_file, &wpre, err); ++ ++out: ++ si_read_unlock(inode->i_sb); ++ inode_unlock(inode); ++ 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 inode *inode; ++ struct super_block *sb; ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/0, /*lsc*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = vfsub_splice_to(h_file, ppos, pipe, len, flags); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ au_read_post(inode, 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_write_pre wpre; ++ struct inode *inode; ++ struct file *h_file; ++ ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ wpre.lsc = 0; ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = vfsub_splice_from(pipe, h_file, ppos, len, flags); ++ au_write_post(inode, h_file, &wpre, err); ++ ++out: ++ si_read_unlock(inode->i_sb); ++ inode_unlock(inode); ++ return err; ++} ++ ++static long aufs_fallocate(struct file *file, int mode, loff_t offset, ++ loff_t len) ++{ ++ long err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *h_file; ++ ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ wpre.lsc = 0; ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ lockdep_off(); ++ err = vfs_fallocate(h_file, mode, offset, len); ++ lockdep_on(); ++ au_write_post(inode, h_file, &wpre, /*written*/1); ++ ++out: ++ si_read_unlock(inode->i_sb); ++ inode_unlock(inode); ++ return err; ++} ++ ++static ssize_t aufs_copy_file_range(struct file *src, loff_t src_pos, ++ struct file *dst, loff_t dst_pos, ++ size_t len, unsigned int flags) ++{ ++ ssize_t err; ++ struct au_write_pre wpre; ++ enum { SRC, DST }; ++ struct { ++ struct inode *inode; ++ struct file *h_file; ++ struct super_block *h_sb; ++ } a[2]; ++#define a_src a[SRC] ++#define a_dst a[DST] ++ ++ err = -EINVAL; ++ a_src.inode = file_inode(src); ++ if (unlikely(!S_ISREG(a_src.inode->i_mode))) ++ goto out; ++ a_dst.inode = file_inode(dst); ++ if (unlikely(!S_ISREG(a_dst.inode->i_mode))) ++ goto out; ++ ++ au_mtx_and_read_lock(a_dst.inode); ++ /* ++ * in order to match the order in di_write_lock2_{child,parent}(), ++ * use f_path.dentry for this comparison. ++ */ ++ if (src->f_path.dentry < dst->f_path.dentry) { ++ a_src.h_file = au_read_pre(src, /*keep_fi*/1, AuLsc_FI_1); ++ err = PTR_ERR(a_src.h_file); ++ if (IS_ERR(a_src.h_file)) ++ goto out_si; ++ ++ wpre.lsc = AuLsc_FI_2; ++ a_dst.h_file = au_write_pre(dst, /*do_ready*/1, &wpre); ++ err = PTR_ERR(a_dst.h_file); ++ if (IS_ERR(a_dst.h_file)) { ++ au_read_post(a_src.inode, a_src.h_file); ++ goto out_si; ++ } ++ } else { ++ wpre.lsc = AuLsc_FI_1; ++ a_dst.h_file = au_write_pre(dst, /*do_ready*/1, &wpre); ++ err = PTR_ERR(a_dst.h_file); ++ if (IS_ERR(a_dst.h_file)) ++ goto out_si; ++ ++ a_src.h_file = au_read_pre(src, /*keep_fi*/1, AuLsc_FI_2); ++ err = PTR_ERR(a_src.h_file); ++ if (IS_ERR(a_src.h_file)) { ++ au_write_post(a_dst.inode, a_dst.h_file, &wpre, ++ /*written*/0); ++ goto out_si; ++ } ++ } ++ ++ err = -EXDEV; ++ a_src.h_sb = file_inode(a_src.h_file)->i_sb; ++ a_dst.h_sb = file_inode(a_dst.h_file)->i_sb; ++ if (unlikely(a_src.h_sb != a_dst.h_sb)) { ++ AuDbgFile(src); ++ AuDbgFile(dst); ++ goto out_file; ++ } ++ ++ err = vfsub_copy_file_range(a_src.h_file, src_pos, a_dst.h_file, ++ dst_pos, len, flags); ++ ++out_file: ++ au_write_post(a_dst.inode, a_dst.h_file, &wpre, err); ++ fi_read_unlock(src); ++ au_read_post(a_src.inode, a_src.h_file); ++out_si: ++ si_read_unlock(a_dst.inode->i_sb); ++ inode_unlock(a_dst.inode); ++out: ++ return err; ++#undef a_src ++#undef a_dst ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * 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 definitely bad, but is not a problem since "si_rwsem for ++ * read" allows multiple 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_iterate() 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. ++ */ ++ ++#if 0 /* stop calling security_file_mmap() */ ++/* 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); ++} ++#endif ++ ++static int aufs_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ int err; ++ const unsigned char wlock ++ = (file->f_mode & FMODE_WRITE) && (vma->vm_flags & VM_SHARED); ++ struct super_block *sb; ++ struct file *h_file; ++ struct inode *inode; ++ ++ AuDbgVmRegion(file, vma); ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ lockdep_off(); ++ si_read_lock(sb, AuLock_NOPLMW); ++ ++ h_file = au_write_pre(file, wlock, /*wpre*/NULL); ++ lockdep_on(); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = 0; ++ au_set_mmapped(file); ++ au_vm_file_reset(vma, h_file); ++ /* ++ * we cannot call security_mmap_file() here since it may acquire ++ * mmap_sem or i_mutex. ++ * ++ * err = security_mmap_file(h_file, au_prot_conv(vma->vm_flags), ++ * au_flag_conv(vma->vm_flags)); ++ */ ++ if (!err) ++ err = call_mmap(h_file, vma); ++ if (!err) { ++ au_vm_prfile_set(vma, file); ++ fsstack_copy_attr_atime(inode, file_inode(h_file)); ++ goto out_fput; /* success */ ++ } ++ au_unset_mmapped(file); ++ au_vm_file_reset(vma, file); ++ ++out_fput: ++ lockdep_off(); ++ ii_write_unlock(inode); ++ lockdep_on(); ++ fput(h_file); ++out: ++ lockdep_off(); ++ 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_write_pre wpre; ++ struct inode *inode; ++ struct file *h_file; ++ ++ err = 0; /* -EBADF; */ /* posix? */ ++ if (unlikely(!(file->f_mode & FMODE_WRITE))) ++ goto out; ++ ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ wpre.lsc = 0; ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out_unlock; ++ ++ err = vfsub_fsync(h_file, &h_file->f_path, datasync); ++ au_write_post(inode, h_file, &wpre, /*written*/0); ++ ++out_unlock: ++ si_read_unlock(inode->i_sb); ++ inode_unlock(inode); ++out: ++ return err; ++} ++ ++static int aufs_fasync(int fd, struct file *file, int flag) ++{ ++ int err; ++ struct file *h_file; ++ struct super_block *sb; ++ ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/0, /*lsc*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ if (h_file->f_op->fasync) ++ err = h_file->f_op->fasync(fd, h_file, flag); ++ fput(h_file); /* instead of au_read_post() */ ++ ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++static int aufs_setfl(struct file *file, unsigned long arg) ++{ ++ int err; ++ struct file *h_file; ++ struct super_block *sb; ++ ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/0, /*lsc*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ /* stop calling h_file->fasync */ ++ arg |= vfsub_file_flags(file) & FASYNC; ++ err = setfl(/*unused fd*/-1, h_file, arg); ++ fput(h_file); /* instead of au_read_post() */ ++ ++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, ++ .read_iter = aufs_read_iter, ++ .write_iter = aufs_write_iter, ++ ++#ifdef CONFIG_AUFS_POLL ++ .poll = aufs_poll, ++#endif ++ .unlocked_ioctl = aufs_ioctl_nondir, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = aufs_compat_ioctl_nondir, ++#endif ++ .mmap = aufs_mmap, ++ .open = aufs_open_nondir, ++ .flush = aufs_flush_nondir, ++ .release = aufs_release_nondir, ++ .fsync = aufs_fsync_nondir, ++ .fasync = aufs_fasync, ++ /* .sendpage = aufs_sendpage, */ ++ .setfl = aufs_setfl, ++ .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 ++ .fallocate = aufs_fallocate, ++ .copy_file_range = aufs_copy_file_range ++}; +diff -Nurp linux-5.4/fs/aufs/fstype.h linux-5.4-aufs/fs/aufs/fstype.h +--- linux-5.4/fs/aufs/fstype.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/fstype.h 2019-11-28 01:25:59.065925618 +0200 +@@ -0,0 +1,388 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * judging filesystem type ++ */ ++ ++#ifndef __AUFS_FSTYPE_H__ ++#define __AUFS_FSTYPE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#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 IS_ENABLED(CONFIG_ISO9660_FS) ++ return sb->s_magic == ISOFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_romfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_ROMFS_FS) ++ return sb->s_magic == ROMFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_cramfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_CRAMFS) ++ return sb->s_magic == CRAMFS_MAGIC; ++#endif ++ return 0; ++} ++ ++static inline int au_test_nfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_NFS_FS) ++ return sb->s_magic == NFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_fuse(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_FUSE_FS) ++ return sb->s_magic == FUSE_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_xfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_XFS_FS) ++ 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 IS_ENABLED(CONFIG_ECRYPT_FS) ++ return !strcmp(au_sbtype(sb), "ecryptfs"); ++#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 IS_ENABLED(CONFIG_UBIFS_FS) ++ 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 IS_ENABLED(CONFIG_CONFIGFS_FS) ++ return sb->s_magic == CONFIGFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_minix(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_MINIX_FS) ++ 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_fat(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_FAT_FS) ++ 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 IS_ENABLED(CONFIG_SQUASHFS) ++ return sb->s_magic == SQUASHFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_btrfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_BTRFS_FS) ++ return sb->s_magic == BTRFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_xenfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_XENFS) ++ 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 IS_ENABLED(CONFIG_NILFS) ++ return sb->s_magic == NILFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_hfsplus(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_HFSPLUS_FS) ++ 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_btrfs(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_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_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_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) ++ ; ++} ++ ++/* 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); ++} ++ ++/* ++ * test if the @inode is nfs with 'noacl' option ++ * NFS always sets SB_POSIXACL regardless its mount option 'noacl.' ++ */ ++static inline int au_test_nfs_noacl(struct inode *inode) ++{ ++ return au_test_nfs(inode->i_sb) ++ /* && IS_POSIXACL(inode) */ ++ && !nfs_server_capable(inode, NFS_CAP_ACLS); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_FSTYPE_H__ */ +diff -Nurp linux-5.4/fs/aufs/hbl.h linux-5.4-aufs/fs/aufs/hbl.h +--- linux-5.4/fs/aufs/hbl.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/hbl.h 2019-11-28 01:25:59.065925618 +0200 +@@ -0,0 +1,52 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2017-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * helpers for hlist_bl.h ++ */ ++ ++#ifndef __AUFS_HBL_H__ ++#define __AUFS_HBL_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++static inline void au_hbl_add(struct hlist_bl_node *node, ++ struct hlist_bl_head *hbl) ++{ ++ hlist_bl_lock(hbl); ++ hlist_bl_add_head(node, hbl); ++ hlist_bl_unlock(hbl); ++} ++ ++static inline void au_hbl_del(struct hlist_bl_node *node, ++ struct hlist_bl_head *hbl) ++{ ++ hlist_bl_lock(hbl); ++ hlist_bl_del(node); ++ hlist_bl_unlock(hbl); ++} ++ ++#define au_hbl_for_each(pos, head) \ ++ for (pos = hlist_bl_first(head); \ ++ pos; \ ++ pos = pos->next) ++ ++static inline unsigned long au_hbl_count(struct hlist_bl_head *hbl) ++{ ++ unsigned long cnt; ++ struct hlist_bl_node *pos; ++ ++ cnt = 0; ++ hlist_bl_lock(hbl); ++ au_hbl_for_each(pos, hbl) ++ cnt++; ++ hlist_bl_unlock(hbl); ++ return cnt; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_HBL_H__ */ +diff -Nurp linux-5.4/fs/aufs/hfsnotify.c linux-5.4-aufs/fs/aufs/hfsnotify.c +--- linux-5.4/fs/aufs/hfsnotify.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/hfsnotify.c 2019-11-28 01:25:59.065925618 +0200 +@@ -0,0 +1,275 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * 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(); /* for atomic64_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, br->br_hfsn->hfsn_group); ++ mark->mask = AuHfsnMask; ++ /* ++ * by udba rename or rmdir, aufs assign a new inode to the known ++ * h_inode, so specify 1 to allow dups. ++ */ ++ lockdep_off(); ++ err = fsnotify_add_inode_mark(mark, hinode->hi_inode, /*allow_dups*/1); ++ lockdep_on(); ++ ++ 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); ++ lockdep_off(); ++ fsnotify_destroy_mark(mark, group); ++ fsnotify_put_mark(mark); ++ fsnotify_put_group(group); ++ lockdep_on(); ++ ++ /* 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_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"); */ ++ au_kfree_try_rcu(hfsn); ++} ++ ++static int au_hfsn_handle_event(struct fsnotify_group *group, ++ struct inode *inode, ++ u32 mask, const void *data, int data_type, ++ const struct qstr *file_name, u32 cookie, ++ struct fsnotify_iter_info *iter_info) ++{ ++ int err; ++ struct au_hnotify *hnotify; ++ struct inode *h_dir, *h_inode; ++ struct fsnotify_mark *inode_mark; ++ ++ AuDebugOn(data_type != FSNOTIFY_EVENT_INODE); ++ ++ err = 0; ++ /* if FS_UNMOUNT happens, there must be another bug */ ++ AuDebugOn(mask & FS_UNMOUNT); ++ if (mask & (FS_IN_IGNORED | FS_UNMOUNT)) ++ goto out; ++ ++ h_dir = inode; ++ h_inode = NULL; ++#ifdef AuDbgHnotify ++ au_debug_on(); ++ 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_off(); ++#endif ++ ++ inode_mark = fsnotify_iter_inode_mark(iter_info); ++ AuDebugOn(!inode_mark); ++ hnotify = container_of(inode_mark, struct au_hnotify, hn_mark); ++ err = au_hnotify(h_dir, hnotify, mask, file_name, h_inode); ++ ++out: ++ return err; ++} ++ ++static struct fsnotify_ops au_hfsn_ops = { ++ .handle_event = au_hfsn_handle_event, ++ .free_group_priv = au_hfsn_free_group, ++ .free_mark = au_hfsn_free_mark ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hfsn_fin_br(struct au_branch *br) ++{ ++ struct au_br_hfsnotify *hfsn; ++ ++ hfsn = br->br_hfsn; ++ if (hfsn) { ++ lockdep_off(); ++ fsnotify_put_group(hfsn->hfsn_group); ++ lockdep_on(); ++ } ++} ++ ++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: ++ au_kfree_try_rcu(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 -Nurp linux-5.4/fs/aufs/hfsplus.c linux-5.4-aufs/fs/aufs/hfsplus.c +--- linux-5.4/fs/aufs/hfsplus.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/hfsplus.c 2019-11-28 01:25:59.065925618 +0200 +@@ -0,0 +1,47 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2010-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * special support for filesystems which acquires an inode mutex ++ * at final closing a file, eg, hfsplus. ++ * ++ * This trick is very simple and stupid, just to open the file before really ++ * necessary 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, ++ int force_wr) ++{ ++ struct file *h_file; ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ AuDebugOn(!h_dentry); ++ AuDebugOn(d_is_negative(h_dentry)); ++ ++ h_file = NULL; ++ if (au_test_hfsplus(h_dentry->d_sb) ++ && d_is_reg(h_dentry)) ++ h_file = au_h_open(dentry, bindex, ++ O_RDONLY | O_NOATIME | O_LARGEFILE, ++ /*file*/NULL, force_wr); ++ return h_file; ++} ++ ++void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex, ++ struct file *h_file) ++{ ++ struct au_branch *br; ++ ++ if (h_file) { ++ fput(h_file); ++ br = au_sbr(dentry->d_sb, bindex); ++ au_lcnt_dec(&br->br_nfiles); ++ } ++} +diff -Nurp linux-5.4/fs/aufs/hnotify.c linux-5.4-aufs/fs/aufs/hnotify.c +--- linux-5.4/fs/aufs/hnotify.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/hnotify.c 2019-11-28 01:25:59.065925618 +0200 +@@ -0,0 +1,708 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * abstraction to notify the direct changes on lower directories ++ */ ++ ++/* #include */ ++#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 assigns a new inode ++ * number and set the monitor again. ++ * For the lower dir, the old monitor 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, bbot; ++ struct inode *hi; ++ struct dentry *iwhdentry; ++ ++ bbot = au_ibbot(inode); ++ for (bindex = au_ibtop(inode); bindex <= bbot; bindex++) { ++ hi = au_h_iptr(inode, bindex); ++ if (!hi) ++ continue; ++ ++ /* inode_lock_nested(hi, 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); ++ /* inode_unlock(hi); */ ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int hn_xino(struct inode *inode, struct inode *h_inode) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot, bfound, btop; ++ 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; ++ bbot = au_ibbot(inode); ++ btop = au_ibtop(inode); ++#if 0 /* reserved for future use */ ++ if (bindex == bbot) { ++ /* keep this ino in rename case */ ++ goto out; ++ } ++#endif ++ for (bindex = btop; bindex <= bbot; bindex++) ++ if (au_h_iptr(inode, bindex) == h_inode) { ++ bfound = bindex; ++ break; ++ } ++ if (bfound < 0) ++ goto out; ++ ++ for (bindex = btop; bindex <= bbot; 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_really_is_positive(d)) ++ /* todo: reset children xino? ++ cached children only? */ ++ au_iigen_dec(d_inode(d)); ++ } ++ } ++ ++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; ++ ++ 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, &inode->i_dentry, d_u.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_any_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; ++ ++ if (IS_ROOT(dentry)) { ++ pr_warn("branch root dir was changed\n"); ++ return 0; ++ } ++ ++ err = 0; ++ if (!isdir) { ++ au_digen_dec(dentry); ++ if (d_really_is_positive(dentry)) ++ au_iigen_dec(d_inode(dentry)); ++ } else { ++ au_fset_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR); ++ if (d_really_is_positive(dentry)) ++ 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); ++ int e; ++ ++ /* 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) { ++ inode_lock_shared_nested(a->h_inode, AuLsc_I_CHILD); ++ if (!a->h_inode->i_nlink ++ && !(a->h_inode->i_state & I_LINKABLE)) ++ hn_xino(a->inode, a->h_inode); /* ignore this error */ ++ inode_unlock_shared(a->h_inode); ++ } ++ ++ /* make the generation obsolete */ ++ if (au_ftest_hnjob(a->flags, GEN)) { ++ e = -1; ++ if (a->inode) ++ e = hn_gen_by_inode(a->h_name, a->h_nlen, a->inode, ++ isdir); ++ if (e && 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); */ ++ /* inode_inc_iversion(a->inode); */ ++ } ++ ++ /* can do nothing but warn */ ++ if (au_ftest_hnjob(a->flags, MNTPNT) ++ && a->dentry ++ && d_mountpoint(a->dentry)) ++ pr_warn("mount-point %pd is removed or renamed\n", 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_any_alias(dir); ++ if (!parent) ++ return NULL; ++ ++ dentry = NULL; ++ spin_lock(&parent->d_lock); ++ list_for_each_entry(d, &parent->d_subdirs, d_child) { ++ /* AuDbg("%pd\n", 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 (au_dcount(d) > 0) { ++ 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, bbot, 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); ++ ++ if (au_opt_test(sbinfo->si_mntflags, DIRREN)) ++ switch (a->mask & FS_EVENTS_POSS_ON_CHILD) { ++ case FS_MOVED_FROM: ++ case FS_MOVED_TO: ++ AuWarn1("DIRREN with UDBA may not work correctly " ++ "for the direct rename(2)\n"); ++ } ++ ++ ii_read_lock_parent(a->dir); ++ bfound = -1; ++ bbot = au_ibbot(a->dir); ++ for (bindex = au_ibtop(a->dir); bindex <= bbot; 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 && d_really_is_positive(dentry)) ++ inode = d_inode(dentry); ++ 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); ++ au_kfree_rcu(a); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask, ++ const 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 & ALL_FSNOTIFY_DIRENT_EVENTS) { ++ 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); ++ 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; ++ } ++ ++ /* NFS fires the event for silly-renamed one from kworker */ ++ f = 0; ++ if (!dir->i_nlink ++ || (au_test_nfs(h_dir->i_sb) && (mask & FS_DELETE))) ++ 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); ++ au_kfree_rcu(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_cache[AuCache_HNOTIFY]); ++ au_cache[AuCache_HNOTIFY] = NULL; ++} ++ ++int __init au_hnotify_init(void) ++{ ++ int err; ++ ++ err = -ENOMEM; ++ au_cache[AuCache_HNOTIFY] = AuCache(au_hnotify); ++ if (au_cache[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_cache[AuCache_HNOTIFY]) ++ au_hn_destroy_cache(); ++} +diff -Nurp linux-5.4/fs/aufs/iinfo.c linux-5.4-aufs/fs/aufs/iinfo.c +--- linux-5.4/fs/aufs/iinfo.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/iinfo.c 2019-11-28 01:25:59.066925618 +0200 +@@ -0,0 +1,273 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode private data ++ */ ++ ++#include "aufs.h" ++ ++struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex) ++{ ++ struct inode *h_inode; ++ struct au_hinode *hinode; ++ ++ IiMustAnyLock(inode); ++ ++ hinode = au_hinode(au_ii(inode), bindex); ++ h_inode = hinode->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 = au_hinode(iinfo, 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_btop) ++ 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_hinode(au_ii(inode), 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(&iigen->ig_spin); ++ 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(&iigen->ig_spin); ++} ++ ++/* 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, bbot; ++ ++ AuDebugOn(au_is_bad_inode(inode)); ++ IiMustWriteLock(inode); ++ ++ iinfo = au_ii(inode); ++ if (do_put_zero && iinfo->ii_btop >= 0) { ++ for (bindex = iinfo->ii_btop; bindex <= iinfo->ii_bbot; ++ bindex++) { ++ struct inode *h_i; ++ ++ h_i = au_hinode(iinfo, bindex)->hi_inode; ++ if (h_i ++ && !h_i->i_nlink ++ && !(h_i->i_state & I_LINKABLE)) ++ au_set_h_iptr(inode, bindex, NULL, 0); ++ } ++ } ++ ++ iinfo->ii_btop = -1; ++ iinfo->ii_bbot = -1; ++ bbot = au_sbbot(inode->i_sb); ++ for (bindex = 0; bindex <= bbot; bindex++) ++ if (au_hinode(iinfo, bindex)->hi_inode) { ++ iinfo->ii_btop = bindex; ++ break; ++ } ++ if (iinfo->ii_btop >= 0) ++ for (bindex = bbot; bindex >= iinfo->ii_btop; bindex--) ++ if (au_hinode(iinfo, bindex)->hi_inode) { ++ iinfo->ii_bbot = bindex; ++ break; ++ } ++ AuDebugOn(iinfo->ii_btop > iinfo->ii_bbot); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_icntnr_init_once(void *_c) ++{ ++ struct au_icntnr *c = _c; ++ struct au_iinfo *iinfo = &c->iinfo; ++ ++ spin_lock_init(&iinfo->ii_generation.ig_spin); ++ au_rw_init(&iinfo->ii_rwsem); ++ inode_init_once(&c->vfs_inode); ++} ++ ++void au_hinode_init(struct au_hinode *hinode) ++{ ++ hinode->hi_inode = NULL; ++ hinode->hi_id = -1; ++ au_hn_init(hinode); ++ hinode->hi_whdentry = NULL; ++} ++ ++int au_iinfo_init(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ struct super_block *sb; ++ struct au_hinode *hi; ++ int nbr, i; ++ ++ sb = inode->i_sb; ++ iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); ++ nbr = au_sbbot(sb) + 1; ++ if (unlikely(nbr <= 0)) ++ nbr = 1; ++ hi = kmalloc_array(nbr, sizeof(*iinfo->ii_hinode), GFP_NOFS); ++ if (hi) { ++ au_lcnt_inc(&au_sbi(sb)->si_ninodes); ++ ++ iinfo->ii_hinode = hi; ++ for (i = 0; i < nbr; i++, hi++) ++ au_hinode_init(hi); ++ ++ iinfo->ii_generation.ig_generation = au_sigen(sb); ++ iinfo->ii_btop = -1; ++ iinfo->ii_bbot = -1; ++ iinfo->ii_vdir = NULL; ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++int au_hinode_realloc(struct au_iinfo *iinfo, int nbr, int may_shrink) ++{ ++ int err, i; ++ struct au_hinode *hip; ++ ++ AuRwMustWriteLock(&iinfo->ii_rwsem); ++ ++ err = -ENOMEM; ++ hip = au_krealloc(iinfo->ii_hinode, sizeof(*hip) * nbr, GFP_NOFS, ++ may_shrink); ++ if (hip) { ++ iinfo->ii_hinode = hip; ++ i = iinfo->ii_bbot + 1; ++ hip += i; ++ for (; i < nbr; i++, hip++) ++ au_hinode_init(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, bbot; ++ const unsigned char unlinked = !inode->i_nlink; ++ ++ AuDebugOn(au_is_bad_inode(inode)); ++ ++ sb = inode->i_sb; ++ au_lcnt_dec(&au_sbi(sb)->si_ninodes); ++ 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(); ++ } ++ ++ iinfo = au_ii(inode); ++ if (iinfo->ii_vdir) ++ au_vdir_free(iinfo->ii_vdir); ++ ++ bindex = iinfo->ii_btop; ++ if (bindex >= 0) { ++ hi = au_hinode(iinfo, bindex); ++ bbot = iinfo->ii_bbot; ++ while (bindex++ <= bbot) { ++ if (hi->hi_inode) ++ au_hiput(hi); ++ hi++; ++ } ++ } ++ au_kfree_rcu(iinfo->ii_hinode); ++ AuRwDestroy(&iinfo->ii_rwsem); ++} +diff -Nurp linux-5.4/fs/aufs/inode.c linux-5.4-aufs/fs/aufs/inode.c +--- linux-5.4/fs/aufs/inode.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/inode.c 2019-11-28 01:25:59.066925618 +0200 +@@ -0,0 +1,516 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode functions ++ */ ++ ++#include ++#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_inc_iversion(inode); ++} ++ ++static int au_ii_refresh(struct inode *inode, int *update) ++{ ++ int err, e, nbr; ++ umode_t type; ++ aufs_bindex_t bindex, new_bindex; ++ struct super_block *sb; ++ struct au_iinfo *iinfo; ++ struct au_hinode *p, *q, tmp; ++ ++ AuDebugOn(au_is_bad_inode(inode)); ++ IiMustWriteLock(inode); ++ ++ *update = 0; ++ sb = inode->i_sb; ++ nbr = au_sbbot(sb) + 1; ++ type = inode->i_mode & S_IFMT; ++ iinfo = au_ii(inode); ++ err = au_hinode_realloc(iinfo, nbr, /*may_shrink*/0); ++ if (unlikely(err)) ++ goto out; ++ ++ AuDebugOn(iinfo->ii_btop < 0); ++ p = au_hinode(iinfo, iinfo->ii_btop); ++ for (bindex = iinfo->ii_btop; bindex <= iinfo->ii_bbot; ++ 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_btop) ++ iinfo->ii_btop = new_bindex; ++ if (iinfo->ii_bbot < new_bindex) ++ iinfo->ii_bbot = new_bindex; ++ /* swap two lower inode, and loop again */ ++ q = au_hinode(iinfo, new_bindex); ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hi_inode) { ++ bindex--; ++ p--; ++ } ++ } ++ au_update_ibrange(inode, /*do_put_zero*/0); ++ au_hinode_realloc(iinfo, nbr, /*may_shrink*/1); /* harmless if err */ ++ e = au_dy_irefresh(inode); ++ if (unlikely(e && !err)) ++ err = e; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_refresh_iop(struct inode *inode, int force_getattr) ++{ ++ int type; ++ struct au_sbinfo *sbi = au_sbi(inode->i_sb); ++ const struct inode_operations *iop ++ = force_getattr ? aufs_iop : sbi->si_iop_array; ++ ++ if (inode->i_op == iop) ++ return; ++ ++ switch (inode->i_mode & S_IFMT) { ++ case S_IFDIR: ++ type = AuIop_DIR; ++ break; ++ case S_IFLNK: ++ type = AuIop_SYMLINK; ++ break; ++ default: ++ type = AuIop_OTHER; ++ break; ++ } ++ ++ inode->i_op = iop + type; ++ /* unnecessary smp_wmb() */ ++} ++ ++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, bbot; ++ 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 = au_hinode(iinfo, iinfo->ii_btop); ++ mode = (inode->i_mode & S_IFMT); ++ isdir = S_ISDIR(mode); ++ flags = au_hi_flags(inode, isdir); ++ bbot = au_dbbot(dentry); ++ for (bindex = au_dbtop(dentry); bindex <= bbot; bindex++) { ++ struct inode *h_i, *h_inode; ++ struct dentry *h_d; ++ ++ h_d = au_h_dptr(dentry, bindex); ++ if (!h_d || d_is_negative(h_d)) ++ continue; ++ ++ h_inode = d_inode(h_d); ++ AuDebugOn(mode != (h_inode->i_mode & S_IFMT)); ++ if (iinfo->ii_btop <= bindex && bindex <= iinfo->ii_bbot) { ++ h_i = au_h_iptr(inode, bindex); ++ if (h_i) { ++ if (h_i == h_inode) ++ continue; ++ err = -EIO; ++ break; ++ } ++ } ++ if (bindex < iinfo->ii_btop) ++ iinfo->ii_btop = bindex; ++ if (iinfo->ii_bbot < bindex) ++ iinfo->ii_bbot = bindex; ++ au_set_h_iptr(inode, bindex, au_igrab(h_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, btop, btail; ++ unsigned char isdir; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct au_iinfo *iinfo; ++ struct inode_operations *iop; ++ ++ IiMustWriteLock(inode); ++ ++ err = 0; ++ isdir = 0; ++ iop = au_sbi(inode->i_sb)->si_iop_array; ++ btop = au_dbtop(dentry); ++ h_dentry = au_h_dptr(dentry, btop); ++ h_inode = d_inode(h_dentry); ++ mode = h_inode->i_mode; ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ btail = au_dbtail(dentry); ++ inode->i_op = iop + AuIop_OTHER; ++ inode->i_fop = &aufs_file_fop; ++ err = au_dy_iaop(inode, btop, h_inode); ++ if (unlikely(err)) ++ goto out; ++ break; ++ case S_IFDIR: ++ isdir = 1; ++ btail = au_dbtaildir(dentry); ++ inode->i_op = iop + AuIop_DIR; ++ inode->i_fop = &aufs_dir_fop; ++ break; ++ case S_IFLNK: ++ btail = au_dbtail(dentry); ++ inode->i_op = iop + AuIop_SYMLINK; ++ break; ++ case S_IFBLK: ++ case S_IFCHR: ++ case S_IFIFO: ++ case S_IFSOCK: ++ btail = au_dbtail(dentry); ++ inode->i_op = iop + AuIop_OTHER; ++ init_special_inode(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_btop = btop; ++ iinfo->ii_bbot = btail; ++ for (bindex = btop; bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry) ++ au_set_h_iptr(inode, bindex, ++ au_igrab(d_inode(h_dentry)), flags); ++ } ++ au_cpup_attr_all(inode, /*force*/1); ++ /* ++ * to force calling aufs_get_acl() every time, ++ * do not call cache_no_acl() for aufs inode. ++ */ ++ ++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, igflags; ++ aufs_bindex_t bindex, bbot; ++ struct inode *h_inode, *h_dinode; ++ struct dentry *h_dentry; ++ ++ /* ++ * 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_dentry = au_h_dptr(dentry, au_dbtop(dentry)); ++ h_dinode = d_inode(h_dentry); ++ bbot = au_ibbot(inode); ++ for (bindex = au_ibtop(inode); bindex <= bbot; bindex++) { ++ h_inode = au_h_iptr(inode, bindex); ++ if (!h_inode || h_inode != h_dinode) ++ continue; ++ ++ err = 0; ++ gen = au_iigen(inode, &igflags); ++ if (gen == au_digen(dentry) ++ && !au_ig_ftest(igflags, 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, idx; ++ const int isnondir = d_type != DT_DIR; ++ ++ /* prevent hardlinked inode number from race condition */ ++ if (isnondir) { ++ err = au_xinondir_enter(sb, bindex, h_ino, &idx); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ err = au_xino_read(sb, bindex, h_ino, ino); ++ if (unlikely(err)) ++ goto out_xinondir; ++ ++ if (!*ino) { ++ err = -EIO; ++ *ino = au_xino_new_ino(sb); ++ if (unlikely(!*ino)) ++ goto out_xinondir; ++ err = au_xino_write(sb, bindex, h_ino, *ino); ++ if (unlikely(err)) ++ goto out_xinondir; ++ } ++ ++out_xinondir: ++ if (isnondir && idx >= 0) ++ au_xinondir_leave(sb, bindex, h_ino, idx); ++out: ++ 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; ++ ino_t h_ino, ino; ++ int err, idx, hlinked; ++ aufs_bindex_t btop; ++ ++ sb = dentry->d_sb; ++ btop = au_dbtop(dentry); ++ h_dentry = au_h_dptr(dentry, btop); ++ h_inode = d_inode(h_dentry); ++ h_ino = h_inode->i_ino; ++ hlinked = !d_is_dir(h_dentry) && h_inode->i_nlink > 1; ++ ++new_ino: ++ /* ++ * stop 'race'-ing between hardlinks under different ++ * parents. ++ */ ++ if (hlinked) { ++ err = au_xinondir_enter(sb, btop, h_ino, &idx); ++ inode = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ err = au_xino_read(sb, btop, h_ino, &ino); ++ inode = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_xinondir; ++ ++ if (!ino) { ++ ino = au_xino_new_ino(sb); ++ if (unlikely(!ino)) { ++ inode = ERR_PTR(-EIO); ++ goto out_xinondir; ++ } ++ } ++ ++ AuDbg("i%lu\n", (unsigned long)ino); ++ inode = au_iget_locked(sb, ino); ++ err = PTR_ERR(inode); ++ if (IS_ERR(inode)) ++ goto out_xinondir; ++ ++ AuDbg("%lx, new %d\n", inode->i_state, !!(inode->i_state & I_NEW)); ++ if (inode->i_state & I_NEW) { ++ ii_write_lock_new_child(inode); ++ err = set_inode(inode, dentry); ++ if (!err) { ++ unlock_new_inode(inode); ++ goto out_xinondir; /* 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, btop, 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 (hlinked && idx >= 0) ++ au_xinondir_leave(sb, btop, h_ino, idx); ++ err = reval_inode(inode, dentry); ++ if (unlikely(err < 0)) { ++ hlinked = 0; ++ goto out_iput; ++ } ++ if (!err) ++ goto out; /* success */ ++ else if (hlinked && idx >= 0) { ++ err = au_xinondir_enter(sb, btop, h_ino, &idx); ++ if (unlikely(err)) { ++ iput(inode); ++ inode = ERR_PTR(err); ++ goto out; ++ } ++ } ++ } ++ ++ if (unlikely(au_test_fs_unique_ino(h_inode))) ++ AuWarn1("Warning: Un-notified UDBA or repeatedly renamed dir," ++ " b%d, %s, %pd, hi%lu, i%lu.\n", ++ btop, au_sbtype(h_dentry->d_sb), dentry, ++ (unsigned long)h_ino, (unsigned long)ino); ++ ino = 0; ++ err = au_xino_write(sb, btop, h_ino, /*ino*/0); ++ if (!err) { ++ iput(inode); ++ if (hlinked && idx >= 0) ++ au_xinondir_leave(sb, btop, h_ino, idx); ++ goto new_ino; ++ } ++ ++out_iput: ++ iput(inode); ++ inode = ERR_PTR(err); ++out_xinondir: ++ if (hlinked && idx >= 0) ++ au_xinondir_leave(sb, btop, h_ino, idx); ++out: ++ return inode; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_test_ro(struct super_block *sb, aufs_bindex_t bindex, ++ struct inode *inode) ++{ ++ int err; ++ struct inode *hi; ++ ++ err = au_br_rdonly(au_sbr(sb, bindex)); ++ ++ /* pseudo-link after flushed may happen out of bounds */ ++ if (!err ++ && inode ++ && au_ibtop(inode) <= bindex ++ && bindex <= au_ibbot(inode)) { ++ /* ++ * permission check is unnecessary since vfsub routine ++ * will be called later ++ */ ++ 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 -Nurp linux-5.4/fs/aufs/inode.h linux-5.4-aufs/fs/aufs/inode.h +--- linux-5.4/fs/aufs/inode.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/inode.h 2019-11-28 01:25:59.066925618 +0200 +@@ -0,0 +1,685 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * 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 */ ++ struct rcu_head rcu; ++#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 { ++ spinlock_t ig_spin; ++ __u32 ig_generation, ig_flags; ++}; ++ ++struct au_vdir; ++struct au_iinfo { ++ struct au_iigen ii_generation; ++ struct super_block *ii_hsb1; /* no get/put */ ++ ++ struct au_rwsem ii_rwsem; ++ aufs_bindex_t ii_btop, ii_bbot; ++ __u32 ii_higen; ++ struct au_hinode *ii_hinode; ++ struct au_vdir *ii_vdir; ++}; ++ ++struct au_icntnr { ++ struct au_iinfo iinfo; ++ struct inode vfs_inode; ++ struct hlist_bl_node plink; ++ struct rcu_head rcu; ++} ____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; ++ ++ /* temporary unlock/relock for copyup */ ++ struct dentry *h_dentry, *h_parent; ++ struct au_branch *br; ++ struct task_struct *task; ++}; ++ ++void au_pin_hdir_unlock(struct au_pin *p); ++int au_pin_hdir_lock(struct au_pin *p); ++int au_pin_hdir_relock(struct au_pin *p); ++void au_pin_hdir_acquire_nest(struct au_pin *p); ++void au_pin_hdir_release(struct au_pin *p); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_iinfo *au_ii(struct inode *inode) ++{ ++ BUG_ON(is_bad_inode(inode)); ++ return &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* inode.c */ ++struct inode *au_igrab(struct inode *inode); ++void au_refresh_iop(struct inode *inode, int force_getattr); ++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 */ ++enum { ++ AuIop_SYMLINK, ++ AuIop_DIR, ++ AuIop_OTHER, ++ AuIop_Last ++}; ++extern struct inode_operations aufs_iop[AuIop_Last], ++ aufs_iop_nogetattr[AuIop_Last]; ++ ++/* au_wr_dir flags */ ++#define AuWrDir_ADD_ENTRY 1 ++#define AuWrDir_ISDIR (1 << 1) ++#define AuWrDir_TMPFILE (1 << 2) ++#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); ++int au_reval_for_attr(struct dentry *dentry, unsigned int sigen); ++ ++#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; ++}; ++ ++int au_pin_and_icpup(struct dentry *dentry, struct iattr *ia, ++ struct au_icpup_args *a); ++ ++int au_h_path_getattr(struct dentry *dentry, int force, struct path *h_path, ++ int locked); ++ ++/* 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); ++struct vfsub_aopen_args; ++int au_aopen_or_create(struct inode *dir, struct dentry *dentry, ++ struct vfsub_aopen_args *args); ++int aufs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode); ++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, ++ unsigned int flags); ++ ++/* 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); ++void au_hinode_init(struct au_hinode *hinode); ++int au_iinfo_init(struct inode *inode); ++void au_iinfo_fin(struct inode *inode); ++int au_hinode_realloc(struct au_iinfo *iinfo, int nbr, int may_shrink); ++ ++#ifdef CONFIG_PROC_FS ++/* plink.c */ ++int au_plink_maint(struct super_block *sb, int flags); ++struct au_sbinfo; ++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 */ ++ ++#ifdef CONFIG_AUFS_XATTR ++/* xattr.c */ ++int au_cpup_xattr(struct dentry *h_dst, struct dentry *h_src, int ignore_flags, ++ unsigned int verbose); ++ssize_t aufs_listxattr(struct dentry *dentry, char *list, size_t size); ++void au_xattr_init(struct super_block *sb); ++#else ++AuStubInt0(au_cpup_xattr, struct dentry *h_dst, struct dentry *h_src, ++ int ignore_flags, unsigned int verbose); ++AuStubVoid(au_xattr_init, struct super_block *sb); ++#endif ++ ++#ifdef CONFIG_FS_POSIX_ACL ++struct posix_acl *aufs_get_acl(struct inode *inode, int type); ++int aufs_set_acl(struct inode *inode, struct posix_acl *acl, int type); ++#endif ++ ++#if IS_ENABLED(CONFIG_AUFS_XATTR) || IS_ENABLED(CONFIG_FS_POSIX_ACL) ++enum { ++ AU_XATTR_SET, ++ AU_ACL_SET ++}; ++ ++struct au_sxattr { ++ int type; ++ union { ++ struct { ++ const char *name; ++ const void *value; ++ size_t size; ++ int flags; ++ } set; ++ struct { ++ struct posix_acl *acl; ++ int type; ++ } acl_set; ++ } u; ++}; ++ssize_t au_sxattr(struct dentry *dentry, struct inode *inode, ++ struct au_sxattr *arg); ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* 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 ++ ++#define ii_read_unlock(i) au_rw_read_unlock(&au_ii(i)->ii_rwsem) ++#define ii_write_unlock(i) au_rw_write_unlock(&au_ii(i)->ii_rwsem) ++#define ii_downgrade_lock(i) au_rw_dgrade_lock(&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, unsigned int *igflags) ++{ ++ unsigned int gen; ++ struct au_iinfo *iinfo; ++ struct au_iigen *iigen; ++ ++ iinfo = au_ii(inode); ++ iigen = &iinfo->ii_generation; ++ spin_lock(&iigen->ig_spin); ++ if (igflags) ++ *igflags = iigen->ig_flags; ++ gen = iigen->ig_generation; ++ spin_unlock(&iigen->ig_spin); ++ ++ 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; ++ struct au_iigen *iigen; ++ ++ iinfo = au_ii(inode); ++ iigen = &iinfo->ii_generation; ++ spin_lock(&iigen->ig_spin); ++ iigen->ig_generation--; ++ spin_unlock(&iigen->ig_spin); ++} ++ ++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 struct au_hinode *au_hinode(struct au_iinfo *iinfo, ++ aufs_bindex_t bindex) ++{ ++ return iinfo->ii_hinode + bindex; ++} ++ ++static inline int au_is_bad_inode(struct inode *inode) ++{ ++ return !!(is_bad_inode(inode) || !au_hinode(au_ii(inode), 0)); ++} ++ ++static inline aufs_bindex_t au_ii_br_id(struct inode *inode, ++ aufs_bindex_t bindex) ++{ ++ IiMustAnyLock(inode); ++ return au_hinode(au_ii(inode), bindex)->hi_id; ++} ++ ++static inline aufs_bindex_t au_ibtop(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_btop; ++} ++ ++static inline aufs_bindex_t au_ibbot(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_bbot; ++} ++ ++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_hinode(au_ii(inode), bindex)->hi_whdentry; ++} ++ ++static inline void au_set_ibtop(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustWriteLock(inode); ++ au_ii(inode)->ii_btop = bindex; ++} ++ ++static inline void au_set_ibbot(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustWriteLock(inode); ++ au_ii(inode)->ii_bbot = 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_hinode(au_ii(inode), 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); ++ } ++} ++ ++#if 0 /* reserved */ ++static inline void au_pin_set_parent(struct au_pin *pin, struct dentry *parent) ++{ ++ if (pin) { ++ dput(pin->parent); ++ pin->parent = dget(parent); ++ } ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++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, ++ const 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 ++AuStub(int, au_hn_alloc, return -EOPNOTSUPP, ++ struct au_hinode *hinode __maybe_unused, ++ struct inode *inode __maybe_unused) ++AuStub(struct au_hnotify *, au_hn, return NULL, struct au_hinode *hinode) ++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_inode_lock(struct au_hinode *hdir) ++{ ++ inode_lock(hdir->hi_inode); ++ au_hn_suspend(hdir); ++} ++ ++static inline void au_hn_inode_lock_nested(struct au_hinode *hdir, ++ unsigned int sc __maybe_unused) ++{ ++ inode_lock_nested(hdir->hi_inode, sc); ++ au_hn_suspend(hdir); ++} ++ ++#if 0 /* unused */ ++#include "vfsub.h" ++static inline void au_hn_inode_lock_shared_nested(struct au_hinode *hdir, ++ unsigned int sc) ++{ ++ inode_lock_shared_nested(hdir->hi_inode, sc); ++ au_hn_suspend(hdir); ++} ++#endif ++ ++static inline void au_hn_inode_unlock(struct au_hinode *hdir) ++{ ++ au_hn_resume(hdir); ++ inode_unlock(hdir->hi_inode); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_INODE_H__ */ +diff -Nurp linux-5.4/fs/aufs/ioctl.c linux-5.4-aufs/fs/aufs/ioctl.c +--- linux-5.4/fs/aufs/ioctl.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/ioctl.c 2019-11-28 01:25:59.066925618 +0200 +@@ -0,0 +1,207 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * ioctl ++ * plink-management and readdir in userspace. ++ * assist the pathconf(3) wrapper library. ++ * move-down ++ * File-based Hierarchical Storage Management. ++ */ ++ ++#include ++#include ++#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, bbot; ++ 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_flags(0); ++ 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); ++ bbot = au_sbbot(sb); ++ if (wbrfd.brid >= 0) { ++ wbi = au_br_index(sb, wbrfd.brid); ++ if (unlikely(wbi < 0 || wbi > bbot)) ++ 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 <= bbot; 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, ++ /*force_wr*/0); ++ ++out_unlock: ++ aufs_read_unlock(root, AuLock_IR); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out_fd; ++ ++ au_lcnt_dec(&br->br_nfiles); /* 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; ++ struct dentry *dentry; ++ ++ 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; ++ ++ case AUFS_CTL_BRINFO: ++ err = au_brinfo_ioctl(file, arg); ++ break; ++ ++ case AUFS_CTL_FHSM_FD: ++ dentry = file->f_path.dentry; ++ if (IS_ROOT(dentry)) ++ err = au_fhsm_fd(dentry->d_sb, arg); ++ else ++ err = -ENOTTY; ++ 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_MVDOWN: ++ err = au_mvdown(file->f_path.dentry, (void __user *)arg); ++ break; ++ ++ 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; ++ ++ case AUFS_CTL_BRINFO: ++ err = au_brinfo_compat_ioctl(file, arg); ++ break; ++ ++ default: ++ err = aufs_ioctl_dir(file, cmd, arg); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++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 +diff -Nurp linux-5.4/fs/aufs/i_op_add.c linux-5.4-aufs/fs/aufs/i_op_add.c +--- linux-5.4/fs/aufs/i_op_add.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/i_op_add.c 2019-11-28 01:25:59.065925618 +0200 +@@ -0,0 +1,923 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode operations (add entry) ++ */ ++ ++#include ++#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 super_block *sb; ++ struct inode *inode, *h_dir; ++ struct dentry *wh; ++ ++ bwh = -1; ++ sb = dir->i_sb; ++ if (wh_dentry) { ++ h_dir = d_inode(wh_dentry->d_parent); /* 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(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 = d_inode(dentry->d_parent); /* dir inode is locked */ ++ IMustLock(dir); ++ au_dir_ts(dir, bindex); ++ inode_inc_iversion(dir); ++ au_fhsm_wrote(sb, bindex, /*force*/0); ++ 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("%pd reverting whiteout failed(%d, %d)\n", ++ 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(d_really_is_positive(dentry))) ++ 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); ++ if (d_really_is_negative(dentry)) { ++ err = -EEXIST; ++ if (unlikely(d_is_positive(h_dentry))) ++ goto out; ++ } else { ++ /* rename(2) case */ ++ err = -EIO; ++ if (unlikely(d_is_negative(h_dentry))) ++ goto out; ++ h_inode = d_inode(h_dentry); ++ if (unlikely(!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("%pd\n", 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_dbtop(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 = au_br_mnt(br) ++ }; ++ au_dtime_store(dt, au_pinned_parent(pin), &tmp); ++ } ++ ++ wh_dentry = NULL; ++ if (bcpup != au_dbwh(dentry)) ++ goto out; /* success */ ++ ++ /* ++ * ENAMETOOLONG here means that if we allowed create such name, then it ++ * would not be able to removed in the future. So we don't allow such ++ * name here and we don't handle ENAMETOOLONG differently here. ++ */ ++ 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; ++ bool try_aopen; ++ struct vfsub_aopen_args *aopen; ++ } 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, rerr; ++ aufs_bindex_t btop; ++ unsigned char created; ++ const unsigned char try_aopen ++ = (arg->type == Creat && arg->u.c.try_aopen); ++ struct vfsub_aopen_args *aopen = arg->u.c.aopen; ++ struct dentry *wh_dentry, *parent; ++ struct inode *h_dir; ++ struct super_block *sb; ++ struct au_branch *br; ++ /* to reduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct au_pin pin; ++ struct path h_path; ++ struct au_wr_dir_args wr_dir_args; ++ } *a; ++ ++ AuDbg("%pd\n", dentry); ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ a->wr_dir_args.force_btgt = -1; ++ a->wr_dir_args.flags = AuWrDir_ADD_ENTRY; ++ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ if (!try_aopen) { ++ 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; ++ if (!try_aopen) ++ di_write_lock_parent(parent); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL, ++ &a->pin, &a->wr_dir_args); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ btop = au_dbtop(dentry); ++ sb = dentry->d_sb; ++ br = au_sbr(sb, btop); ++ a->h_path.dentry = au_h_dptr(dentry, btop); ++ a->h_path.mnt = au_br_mnt(br); ++ h_dir = au_pinned_h_dir(&a->pin); ++ switch (arg->type) { ++ case Creat: ++ if (!try_aopen || !h_dir->i_op->atomic_open) { ++ err = vfsub_create(h_dir, &a->h_path, arg->u.c.mode, ++ arg->u.c.want_excl); ++ created = !err; ++ if (!err && try_aopen) ++ aopen->file->f_mode |= FMODE_CREATED; ++ } else { ++ aopen->br = br; ++ err = vfsub_atomic_open(h_dir, a->h_path.dentry, aopen); ++ AuDbg("err %d\n", err); ++ AuDbgFile(aopen->file); ++ created = err >= 0 ++ && !!(aopen->file->f_mode & FMODE_CREATED); ++ } ++ break; ++ case Symlink: ++ err = vfsub_symlink(h_dir, &a->h_path, arg->u.s.symname); ++ created = !err; ++ break; ++ case Mknod: ++ err = vfsub_mknod(h_dir, &a->h_path, arg->u.m.mode, ++ arg->u.m.dev); ++ created = !err; ++ break; ++ default: ++ BUG(); ++ } ++ if (unlikely(err < 0)) ++ goto out_unpin; ++ ++ err = epilog(dir, btop, wh_dentry, dentry); ++ if (!err) ++ goto out_unpin; /* success */ ++ ++ /* revert */ ++ if (created /* && d_is_positive(a->h_path.dentry) */) { ++ /* no delegation since it is just created */ ++ rerr = vfsub_unlink(h_dir, &a->h_path, /*delegated*/NULL, ++ /*force*/0); ++ if (rerr) { ++ AuIOErr("%pd revert failure(%d, %d)\n", ++ dentry, err, rerr); ++ err = -EIO; ++ } ++ au_dtime_revert(&a->dt); ++ } ++ if (try_aopen && h_dir->i_op->atomic_open ++ && (aopen->file->f_mode & FMODE_OPENED)) ++ /* aopen->file is still opened */ ++ au_lcnt_dec(&aopen->br->br_nfiles); ++ ++out_unpin: ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++out_parent: ++ if (!try_aopen) ++ di_write_unlock(parent); ++out_unlock: ++ if (unlikely(err)) { ++ au_update_dbtop(dentry); ++ d_drop(dentry); ++ } ++ if (!try_aopen) ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ au_kfree_rcu(a); ++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); ++} ++ ++int au_aopen_or_create(struct inode *dir, struct dentry *dentry, ++ struct vfsub_aopen_args *aopen_args) ++{ ++ struct simple_arg arg = { ++ .type = Creat, ++ .u.c = { ++ .mode = aopen_args->create_mode, ++ .want_excl = aopen_args->open_flag & O_EXCL, ++ .try_aopen = true, ++ .aopen = aopen_args ++ } ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int aufs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct super_block *sb; ++ struct dentry *parent, *h_parent, *h_dentry; ++ struct inode *h_dir, *inode; ++ struct vfsmount *h_mnt; ++ struct au_wr_dir_args wr_dir_args = { ++ .force_btgt = -1, ++ .flags = AuWrDir_TMPFILE ++ }; ++ ++ /* copy-up may happen */ ++ inode_lock(dir); ++ ++ sb = dir->i_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_di_init(dentry); ++ if (unlikely(err)) ++ goto out_si; ++ ++ err = -EBUSY; ++ parent = d_find_any_alias(dir); ++ AuDebugOn(!parent); ++ di_write_lock_parent(parent); ++ if (unlikely(d_inode(parent) != dir)) ++ goto out_parent; ++ ++ err = au_digen_test(parent, au_sigen(sb)); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ bindex = au_dbtop(parent); ++ au_set_dbtop(dentry, bindex); ++ au_set_dbbot(dentry, bindex); ++ err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args); ++ bindex = err; ++ if (unlikely(err < 0)) ++ goto out_parent; ++ ++ err = -EOPNOTSUPP; ++ h_dir = au_h_iptr(dir, bindex); ++ if (unlikely(!h_dir->i_op->tmpfile)) ++ goto out_parent; ++ ++ h_mnt = au_sbr_mnt(sb, bindex); ++ err = vfsub_mnt_want_write(h_mnt); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ h_parent = au_h_dptr(parent, bindex); ++ h_dentry = vfs_tmpfile(h_parent, mode, /*open_flag*/0); ++ if (IS_ERR(h_dentry)) { ++ err = PTR_ERR(h_dentry); ++ goto out_mnt; ++ } ++ ++ au_set_dbtop(dentry, bindex); ++ au_set_dbbot(dentry, bindex); ++ au_set_h_dptr(dentry, bindex, dget(h_dentry)); ++ inode = au_new_inode(dentry, /*must_new*/1); ++ if (IS_ERR(inode)) { ++ err = PTR_ERR(inode); ++ au_set_h_dptr(dentry, bindex, NULL); ++ au_set_dbtop(dentry, -1); ++ au_set_dbbot(dentry, -1); ++ } else { ++ if (!inode->i_nlink) ++ set_nlink(inode, 1); ++ d_tmpfile(dentry, inode); ++ au_di(dentry)->di_tmpfile = 1; ++ ++ /* update without i_mutex */ ++ if (au_ibtop(dir) == au_dbtop(dentry)) ++ au_cpup_attr_timesizes(dir); ++ } ++ dput(h_dentry); ++ ++out_mnt: ++ vfsub_mnt_drop_write(h_mnt); ++out_parent: ++ di_write_unlock(parent); ++ dput(parent); ++ di_write_unlock(dentry); ++ if (unlikely(err)) { ++ au_di_fin(dentry); ++ dentry->d_fsdata = NULL; ++ } ++out_si: ++ si_read_unlock(sb); ++out: ++ inode_unlock(dir); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++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 au_cp_generic cpg = { ++ .dentry = src_dentry, ++ .bdst = a->bdst, ++ .bsrc = a->bsrc, ++ .len = -1, ++ .pin = &a->pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN /* | AuCpup_KEEPLINO */ ++ }; ++ ++ 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); ++ 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; ++ ++ err = au_sio_cpup_simple(&cpg); ++ 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 dentry *dentry, ++ struct au_link_args *a) ++{ ++ int err; ++ unsigned char plink; ++ aufs_bindex_t bbot; ++ struct dentry *h_src_dentry; ++ struct inode *h_inode, *inode, *delegated; ++ struct super_block *sb; ++ struct file *h_file; ++ ++ plink = 0; ++ h_inode = NULL; ++ sb = src_dentry->d_sb; ++ inode = d_inode(src_dentry); ++ if (au_ibtop(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. */ ++ bbot = au_dbbot(dentry); ++ if (bbot < a->bsrc) ++ au_set_dbbot(dentry, a->bsrc); ++ au_set_h_dptr(dentry, a->bsrc, ++ dget(au_h_dptr(src_dentry, a->bsrc))); ++ dget(a->h_path.dentry); ++ au_set_h_dptr(dentry, a->bdst, NULL); ++ AuDbg("temporary d_inode...\n"); ++ spin_lock(&dentry->d_lock); ++ dentry->d_inode = d_inode(src_dentry); /* tmp */ ++ spin_unlock(&dentry->d_lock); ++ h_file = au_h_open_pre(dentry, a->bsrc, /*force_wr*/0); ++ if (IS_ERR(h_file)) ++ err = PTR_ERR(h_file); ++ else { ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = a->bdst, ++ .bsrc = -1, ++ .len = -1, ++ .pin = &a->pin, ++ .flags = AuCpup_KEEPLINO ++ }; ++ err = au_sio_cpup_simple(&cpg); ++ au_h_open_post(dentry, a->bsrc, h_file); ++ if (!err) { ++ dput(a->h_path.dentry); ++ a->h_path.dentry = au_h_dptr(dentry, a->bdst); ++ } else ++ au_set_h_dptr(dentry, a->bdst, ++ a->h_path.dentry); ++ } ++ spin_lock(&dentry->d_lock); ++ dentry->d_inode = NULL; /* restore */ ++ spin_unlock(&dentry->d_lock); ++ AuDbg("temporary d_inode...done\n"); ++ au_set_h_dptr(dentry, a->bsrc, NULL); ++ au_set_dbbot(dentry, bbot); ++ } 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(d_is_negative(h_src_dentry))) { ++ dput(h_src_dentry); ++ h_src_dentry = NULL; ++ } ++ ++ } ++ if (h_src_dentry) { ++ delegated = NULL; ++ err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), ++ &a->h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ 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, *delegated; ++ struct super_block *sb; ++ struct au_wr_dir_args wr_dir_args = { ++ /* .force_btgt = -1, */ ++ .flags = AuWrDir_ADD_ENTRY ++ }; ++ ++ IMustLock(dir); ++ inode = d_inode(src_dentry); ++ 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_linkable(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_ibtop(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_dbtop(dentry); ++ a->h_path.dentry = au_h_dptr(dentry, a->bdst); ++ a->h_path.mnt = au_sbr_mnt(sb, a->bdst); ++ a->bsrc = au_ibtop(inode); ++ h_src_dentry = au_h_d_alias(src_dentry, a->bsrc); ++ if (!h_src_dentry && au_di(src_dentry)->di_tmpfile) ++ h_src_dentry = dget(au_hi_wh(inode, a->bsrc)); ++ if (!h_src_dentry) { ++ a->bsrc = au_dbtop(src_dentry); ++ h_src_dentry = au_h_d_alias(src_dentry, a->bsrc); ++ AuDebugOn(!h_src_dentry); ++ } else if (IS_ERR(h_src_dentry)) { ++ err = PTR_ERR(h_src_dentry); ++ goto out_parent; ++ } ++ ++ /* ++ * aufs doesn't touch the credential so ++ * security_dentry_create_files_as() is unnecessary. ++ */ ++ 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, dentry, a); ++ else { ++ delegated = NULL; ++ err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), ++ &a->h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ } ++ 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 && d_is_positive(h_src_dentry)) { ++ delegated = NULL; ++ err = vfsub_link(h_src_dentry, ++ au_pinned_h_dir(&a->pin), ++ &a->h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry" ++ " for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ } ++ } ++ } ++ 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; ++ } ++ ++ au_dir_ts(dir, a->bdst); ++ inode_inc_iversion(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); ++ /* some filesystems consume an inode even hardlink */ ++ au_fhsm_wrote(sb, a->bdst, /*force*/0); ++ goto out_unpin; /* success */ ++ ++out_revert: ++ /* no delegation since it is just created */ ++ rerr = vfsub_unlink(au_pinned_h_dir(&a->pin), &a->h_path, ++ /*delegated*/NULL, /*force*/0); ++ if (unlikely(rerr)) { ++ AuIOErr("%pd reverting failed(%d, %d)\n", 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_dbtop(dentry); ++ d_drop(dentry); ++ } ++ aufs_read_and_write_unlock2(dentry, src_dentry); ++out_kfree: ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ 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 inode *h_inode; ++ 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_dbtop(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_inode = d_inode(h_path.dentry); ++ if (wh_dentry ++ || au_opt_test(au_mntflags(sb), ALWAYS_DIROPQ)) { ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ opq_dentry = au_diropq_create(dentry, bindex); ++ inode_unlock(h_inode); ++ 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); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ rerr = au_diropq_remove(dentry, bindex); ++ inode_unlock(h_inode); ++ if (rerr) { ++ AuIOErr("%pd reverting diropq failed(%d, %d)\n", ++ dentry, err, rerr); ++ err = -EIO; ++ } ++ } ++ ++out_dir: ++ AuLabel(revert dir); ++ rerr = vfsub_rmdir(au_pinned_h_dir(&a->pin), &h_path); ++ if (rerr) { ++ AuIOErr("%pd reverting dir failed(%d, %d)\n", ++ 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_dbtop(dentry); ++ d_drop(dentry); ++ } ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ au_kfree_rcu(a); ++out: ++ return err; ++} +diff -Nurp linux-5.4/fs/aufs/i_op.c linux-5.4-aufs/fs/aufs/i_op.c +--- linux-5.4/fs/aufs/i_op.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/i_op.c 2019-11-28 01:25:59.065925618 +0200 +@@ -0,0 +1,1492 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * 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 path *h_path, int brperm) ++{ ++ int err; ++ const unsigned char write_mask = !!(mask & (MAY_WRITE | MAY_APPEND)); ++ ++ err = -EPERM; ++ if (write_mask && IS_IMMUTABLE(h_inode)) ++ goto out; ++ ++ err = -EACCES; ++ if (((mask & MAY_EXEC) ++ && S_ISREG(h_inode->i_mode) ++ && (path_noexec(h_path) ++ || !(h_inode->i_mode & 0111)))) ++ 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. ++ * - nfs always sets SB_POSIXACL regardless its mount option 'noacl.' ++ * in this case, generic_permission() returns -EOPNOTSUPP. ++ */ ++ 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); */ ++ /* AuDbg("get_acl %ps\n", h_inode->i_op->get_acl); */ ++ err = generic_permission(h_inode, mask); ++ if (err == -EOPNOTSUPP && au_test_nfs_noacl(h_inode)) ++ err = h_inode->i_op->permission(h_inode, mask); ++ AuTraceErr(err); ++ } 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, bbot; ++ 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 ++ || au_opt_test(au_mntflags(sb), DIRPERM1)) { ++ err = au_busy_or_stale(); ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ if (unlikely(!h_inode ++ || (h_inode->i_mode & S_IFMT) ++ != (inode->i_mode & S_IFMT))) ++ goto out; ++ ++ err = 0; ++ bindex = au_ibtop(inode); ++ br = au_sbr(sb, bindex); ++ err = h_permission(h_inode, mask, &br->br_path, 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; ++ bbot = au_ibbot(inode); ++ for (bindex = au_ibtop(inode); !err && bindex <= bbot; 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_path, ++ 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) { ++ /* regardless LOOKUP_CREATE, always ALLOW_NEG */ ++ npositive = au_lkup_dentry(dentry, au_dbtop(parent), ++ AuLkup_ALLOW_NEG); ++ 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); ++ if (IS_ERR(inode)) { ++ ret = (void *)inode; ++ inode = NULL; ++ goto out_unlock; ++ } ++ } ++ ++ if (inode) ++ atomic_inc(&inode->i_count); ++ 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 (inode) { ++ if (!IS_ERR(ret)) { ++ iput(inode); ++ if (ret && ret != dentry) ++ ii_write_unlock(inode); ++ } else { ++ ii_write_unlock(inode); ++ iput(inode); ++ inode = NULL; ++ } ++ } ++ ++out_unlock: ++ di_write_unlock(dentry); ++out_si: ++ si_read_unlock(sb); ++out: ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * very dirty and complicated aufs ->atomic_open(). ++ * aufs_atomic_open() ++ * + au_aopen_or_create() ++ * + add_simple() ++ * + vfsub_atomic_open() ++ * + branch fs ->atomic_open() ++ * may call the actual 'open' for h_file ++ * + inc br_nfiles only if opened ++ * + au_aopen_no_open() or au_aopen_do_open() ++ * ++ * au_aopen_do_open() ++ * + finish_open() ++ * + au_do_aopen() ++ * + au_do_open() the body of all 'open' ++ * + au_do_open_nondir() ++ * set the passed h_file ++ * ++ * au_aopen_no_open() ++ * + finish_no_open() ++ */ ++ ++struct aopen_node { ++ struct hlist_bl_node hblist; ++ struct file *file, *h_file; ++}; ++ ++static int au_do_aopen(struct inode *inode, struct file *file) ++{ ++ struct hlist_bl_head *aopen; ++ struct hlist_bl_node *pos; ++ struct aopen_node *node; ++ struct au_do_open_args args = { ++ .aopen = 1, ++ .open = au_do_open_nondir ++ }; ++ ++ aopen = &au_sbi(inode->i_sb)->si_aopen; ++ hlist_bl_lock(aopen); ++ hlist_bl_for_each_entry(node, pos, aopen, hblist) ++ if (node->file == file) { ++ args.h_file = node->h_file; ++ break; ++ } ++ hlist_bl_unlock(aopen); ++ /* AuDebugOn(!args.h_file); */ ++ ++ return au_do_open(file, &args); ++} ++ ++static int au_aopen_do_open(struct file *file, struct dentry *dentry, ++ struct aopen_node *aopen_node) ++{ ++ int err; ++ struct hlist_bl_head *aopen; ++ ++ AuLabel(here); ++ aopen = &au_sbi(dentry->d_sb)->si_aopen; ++ au_hbl_add(&aopen_node->hblist, aopen); ++ err = finish_open(file, dentry, au_do_aopen); ++ au_hbl_del(&aopen_node->hblist, aopen); ++ /* AuDbgFile(file); */ ++ AuDbg("%pd%s%s\n", dentry, ++ (file->f_mode & FMODE_CREATED) ? " created" : "", ++ (file->f_mode & FMODE_OPENED) ? " opened" : ""); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_aopen_no_open(struct file *file, struct dentry *dentry) ++{ ++ int err; ++ ++ AuLabel(here); ++ dget(dentry); ++ err = finish_no_open(file, dentry); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int aufs_atomic_open(struct inode *dir, struct dentry *dentry, ++ struct file *file, unsigned int open_flag, ++ umode_t create_mode) ++{ ++ int err, did_open; ++ unsigned int lkup_flags; ++ aufs_bindex_t bindex; ++ struct super_block *sb; ++ struct dentry *parent, *d; ++ struct vfsub_aopen_args args = { ++ .open_flag = open_flag, ++ .create_mode = create_mode ++ }; ++ struct aopen_node aopen_node = { ++ .file = file ++ }; ++ ++ IMustLock(dir); ++ AuDbg("open_flag 0%o\n", open_flag); ++ AuDbgDentry(dentry); ++ ++ err = 0; ++ if (!au_di(dentry)) { ++ lkup_flags = LOOKUP_OPEN; ++ if (open_flag & O_CREAT) ++ lkup_flags |= LOOKUP_CREATE; ++ d = aufs_lookup(dir, dentry, lkup_flags); ++ if (IS_ERR(d)) { ++ err = PTR_ERR(d); ++ AuTraceErr(err); ++ goto out; ++ } else if (d) { ++ /* ++ * obsoleted dentry found. ++ * another error will be returned later. ++ */ ++ d_drop(d); ++ AuDbgDentry(d); ++ dput(d); ++ } ++ AuDbgDentry(dentry); ++ } ++ ++ if (d_is_positive(dentry) ++ || d_unhashed(dentry) ++ || d_unlinked(dentry) ++ || !(open_flag & O_CREAT)) { ++ err = au_aopen_no_open(file, dentry); ++ goto out; /* success */ ++ } ++ ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_GEN); ++ if (unlikely(err)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ parent = dentry->d_parent; /* dir is locked */ ++ di_write_lock_parent(parent); ++ err = au_lkup_dentry(dentry, /*btop*/0, AuLkup_ALLOW_NEG); ++ if (unlikely(err < 0)) ++ goto out_parent; ++ ++ AuDbgDentry(dentry); ++ if (d_is_positive(dentry)) { ++ err = au_aopen_no_open(file, dentry); ++ goto out_parent; /* success */ ++ } ++ ++ args.file = alloc_empty_file(file->f_flags, current_cred()); ++ err = PTR_ERR(args.file); ++ if (IS_ERR(args.file)) ++ goto out_parent; ++ ++ bindex = au_dbtop(dentry); ++ err = au_aopen_or_create(dir, dentry, &args); ++ AuTraceErr(err); ++ AuDbgFile(args.file); ++ file->f_mode = args.file->f_mode & ~FMODE_OPENED; ++ did_open = !!(args.file->f_mode & FMODE_OPENED); ++ if (!did_open) { ++ fput(args.file); ++ args.file = NULL; ++ } ++ di_write_unlock(parent); ++ di_write_unlock(dentry); ++ if (unlikely(err < 0)) { ++ if (args.file) ++ fput(args.file); ++ goto out_sb; ++ } ++ ++ if (!did_open) ++ err = au_aopen_no_open(file, dentry); ++ else { ++ aopen_node.h_file = args.file; ++ err = au_aopen_do_open(file, dentry, &aopen_node); ++ } ++ if (unlikely(err < 0)) { ++ if (args.file) ++ fput(args.file); ++ if (did_open) ++ au_lcnt_dec(&args.br->br_nfiles); ++ } ++ goto out_sb; /* success */ ++ ++out_parent: ++ di_write_unlock(parent); ++ di_write_unlock(dentry); ++out_sb: ++ si_read_unlock(sb); ++out: ++ AuTraceErr(err); ++ AuDbgFile(file); ++ return err; ++} ++ ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_wr_dir_cpup(struct dentry *dentry, struct dentry *parent, ++ const unsigned char add_entry, aufs_bindex_t bcpup, ++ aufs_bindex_t btop) ++{ ++ int err; ++ struct dentry *h_parent; ++ struct inode *h_dir; ++ ++ if (add_entry) ++ IMustLock(d_inode(parent)); ++ else ++ di_write_lock_parent(parent); ++ ++ err = 0; ++ if (!au_h_dptr(parent, bcpup)) { ++ if (btop > bcpup) ++ err = au_cpup_dirs(dentry, bcpup); ++ else if (btop < bcpup) ++ err = au_cpdown_dirs(dentry, bcpup); ++ else ++ BUG(); ++ } ++ if (!err && add_entry && !au_ftest_wrdir(add_entry, TMPFILE)) { ++ h_parent = au_h_dptr(parent, bcpup); ++ h_dir = d_inode(h_parent); ++ inode_lock_shared_nested(h_dir, AuLsc_I_PARENT); ++ err = au_lkup_neg(dentry, bcpup, /*wh*/0); ++ /* todo: no unlock here */ ++ inode_unlock_shared(h_dir); ++ ++ AuDbg("bcpup %d\n", bcpup); ++ if (!err) { ++ if (d_really_is_negative(dentry)) ++ au_set_h_dptr(dentry, btop, 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; ++ unsigned int flags; ++ aufs_bindex_t bcpup, btop, src_btop; ++ const unsigned char add_entry ++ = au_ftest_wrdir(args->flags, ADD_ENTRY) ++ | au_ftest_wrdir(args->flags, TMPFILE); ++ struct super_block *sb; ++ struct dentry *parent; ++ struct au_sbinfo *sbinfo; ++ ++ sb = dentry->d_sb; ++ sbinfo = au_sbi(sb); ++ parent = dget_parent(dentry); ++ btop = au_dbtop(dentry); ++ bcpup = btop; ++ if (args->force_btgt < 0) { ++ if (src_dentry) { ++ src_btop = au_dbtop(src_dentry); ++ if (src_btop < btop) ++ bcpup = src_btop; ++ } else if (add_entry) { ++ flags = 0; ++ if (au_ftest_wrdir(args->flags, ISDIR)) ++ au_fset_wbr(flags, DIR); ++ err = AuWbrCreate(sbinfo, dentry, flags); ++ bcpup = err; ++ } ++ ++ if (bcpup < 0 || au_test_ro(sb, bcpup, d_inode(dentry))) { ++ 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, d_inode(dentry))); ++ } ++ ++ AuDbg("btop %d, bcpup %d\n", btop, bcpup); ++ err = bcpup; ++ if (bcpup == btop) ++ goto out; /* success */ ++ ++ /* copyup the new parent into the branch we process */ ++ err = au_wr_dir_cpup(dentry, parent, add_entry, bcpup, btop); ++ if (err >= 0) { ++ if (d_really_is_negative(dentry)) { ++ au_set_h_dptr(dentry, btop, NULL); ++ au_set_dbtop(dentry, bcpup); ++ au_set_dbbot(dentry, bcpup); ++ } ++ AuDebugOn(add_entry ++ && !au_ftest_wrdir(args->flags, TMPFILE) ++ && !au_h_dptr(dentry, bcpup)); ++ } ++ ++out: ++ dput(parent); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_pin_hdir_unlock(struct au_pin *p) ++{ ++ if (p->hdir) ++ au_hn_inode_unlock(p->hdir); ++} ++ ++int au_pin_hdir_lock(struct au_pin *p) ++{ ++ int err; ++ ++ err = 0; ++ if (!p->hdir) ++ goto out; ++ ++ /* even if an error happens later, keep this lock */ ++ au_hn_inode_lock_nested(p->hdir, p->lsc_hi); ++ ++ err = -EBUSY; ++ if (unlikely(p->hdir->hi_inode != d_inode(p->h_parent))) ++ goto out; ++ ++ err = 0; ++ if (p->h_dentry) ++ err = au_h_verify(p->h_dentry, p->udba, p->hdir->hi_inode, ++ p->h_parent, p->br); ++ ++out: ++ return err; ++} ++ ++int au_pin_hdir_relock(struct au_pin *p) ++{ ++ int err, i; ++ struct inode *h_i; ++ struct dentry *h_d[] = { ++ p->h_dentry, ++ p->h_parent ++ }; ++ ++ err = au_pin_hdir_lock(p); ++ if (unlikely(err)) ++ goto out; ++ ++ for (i = 0; !err && i < sizeof(h_d)/sizeof(*h_d); i++) { ++ if (!h_d[i]) ++ continue; ++ if (d_is_positive(h_d[i])) { ++ h_i = d_inode(h_d[i]); ++ err = !h_i->i_nlink; ++ } ++ } ++ ++out: ++ return err; ++} ++ ++static void au_pin_hdir_set_owner(struct au_pin *p, struct task_struct *task) ++{ ++ atomic_long_set(&p->hdir->hi_inode->i_rwsem.owner, (long)task); ++} ++ ++void au_pin_hdir_acquire_nest(struct au_pin *p) ++{ ++ if (p->hdir) { ++ rwsem_acquire_nest(&p->hdir->hi_inode->i_rwsem.dep_map, ++ p->lsc_hi, 0, NULL, _RET_IP_); ++ au_pin_hdir_set_owner(p, current); ++ } ++} ++ ++void au_pin_hdir_release(struct au_pin *p) ++{ ++ if (p->hdir) { ++ au_pin_hdir_set_owner(p, p->task); ++ rwsem_release(&p->hdir->hi_inode->i_rwsem.dep_map, 1, _RET_IP_); ++ } ++} ++ ++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->hdir) ++ au_pin_hdir_unlock(p); ++ if (p->h_mnt && au_ftest_pin(p->flags, MNT_WRITE)) ++ vfsub_mnt_drop_write(p->h_mnt); ++ if (!p->hdir) ++ return; ++ ++ 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; ++ /* do not clear p->task */ ++} ++ ++int au_do_pin(struct au_pin *p) ++{ ++ int err; ++ struct super_block *sb; ++ struct inode *h_dir; ++ ++ err = 0; ++ sb = p->dentry->d_sb; ++ p->br = au_sbr(sb, p->bindex); ++ if (IS_ROOT(p->dentry)) { ++ if (au_ftest_pin(p->flags, MNT_WRITE)) { ++ p->h_mnt = au_br_mnt(p->br); ++ err = vfsub_mnt_want_write(p->h_mnt); ++ if (unlikely(err)) { ++ au_fclr_pin(p->flags, MNT_WRITE); ++ goto out_err; ++ } ++ } ++ goto out; ++ } ++ ++ p->h_dentry = NULL; ++ if (p->bindex <= au_dbbot(p->dentry)) ++ p->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; ++ p->h_parent = au_h_dptr(p->parent, p->bindex); ++ p->hdir = au_hi(d_inode(p->parent), 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 || !p->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; ++ } ++ ++ if (au_ftest_pin(p->flags, MNT_WRITE)) { ++ p->h_mnt = au_br_mnt(p->br); ++ err = vfsub_mnt_want_write(p->h_mnt); ++ if (unlikely(err)) { ++ au_fclr_pin(p->flags, MNT_WRITE); ++ 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); ++ err = au_pin_hdir_lock(p); ++ if (!err) ++ goto out; /* success */ ++ ++ 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; ++ ++ p->h_dentry = NULL; ++ p->h_parent = NULL; ++ p->br = NULL; ++ p->task = current; ++} ++ ++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() */ ++int au_reval_for_attr(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ struct dentry *parent; ++ ++ err = 0; ++ 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; ++} ++ ++int au_pin_and_icpup(struct dentry *dentry, struct iattr *ia, ++ struct au_icpup_args *a) ++{ ++ int err; ++ loff_t sz; ++ aufs_bindex_t btop, ibtop; ++ struct dentry *hi_wh, *parent; ++ struct inode *inode; ++ struct au_wr_dir_args wr_dir_args = { ++ .force_btgt = -1, ++ .flags = 0 ++ }; ++ ++ if (d_is_dir(dentry)) ++ au_fset_wrdir(wr_dir_args.flags, ISDIR); ++ /* plink or hi_wh() case */ ++ btop = au_dbtop(dentry); ++ inode = d_inode(dentry); ++ ibtop = au_ibtop(inode); ++ if (btop != ibtop && !au_test_ro(inode->i_sb, ibtop, inode)) ++ wr_dir_args.force_btgt = ibtop; ++ err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args); ++ if (unlikely(err < 0)) ++ goto out; ++ a->btgt = err; ++ if (err != btop) ++ 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; ++ ++ sz = -1; ++ a->h_path.dentry = au_h_dptr(dentry, btop); ++ a->h_inode = d_inode(a->h_path.dentry); ++ if (ia && (ia->ia_valid & ATTR_SIZE)) { ++ inode_lock_shared_nested(a->h_inode, AuLsc_I_CHILD); ++ if (ia->ia_size < i_size_read(a->h_inode)) ++ sz = ia->ia_size; ++ inode_unlock_shared(a->h_inode); ++ } ++ ++ 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) { ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = a->btgt, ++ .bsrc = -1, ++ .len = sz, ++ .pin = &a->pin ++ }; ++ err = au_sio_cpup_wh(&cpg, /*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)) { ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = a->btgt, ++ .bsrc = btop, ++ .len = sz, ++ .pin = &a->pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ err = au_sio_cpup_simple(&cpg); ++ 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: ++ a->h_inode = d_inode(a->h_path.dentry); ++ if (!err) ++ goto out; /* success */ ++ au_unpin(&a->pin); ++out_parent: ++ if (parent) { ++ di_write_unlock(parent); ++ dput(parent); ++ } ++out: ++ if (!err) ++ inode_lock_nested(a->h_inode, AuLsc_I_CHILD); ++ return err; ++} ++ ++static int aufs_setattr(struct dentry *dentry, struct iattr *ia) ++{ ++ int err; ++ struct inode *inode, *delegated; ++ struct super_block *sb; ++ struct file *file; ++ struct au_icpup_args *a; ++ ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ ++ err = setattr_prepare(dentry, ia); ++ if (unlikely(err)) ++ goto out; ++ ++ 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(!d_is_reg(dentry)); ++ file = ia->ia_file; ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1, ++ /*fi_lsc*/0); ++ 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, ia->ia_uid, ia->ia_gid); ++ 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; ++ inode_unlock(a->h_inode); ++ err = vfsub_trunc(&a->h_path, ia->ia_size, ia->ia_valid, f); ++ inode_lock_nested(a->h_inode, AuLsc_I_CHILD); ++ } else { ++ delegated = NULL; ++ while (1) { ++ err = vfsub_notify_change(&a->h_path, ia, &delegated); ++ if (delegated) { ++ err = break_deleg_wait(&delegated); ++ if (!err) ++ continue; ++ } ++ break; ++ } ++ } ++ /* ++ * regardless aufs 'acl' option setting. ++ * why don't all acl-aware fs call this func from their ->setattr()? ++ */ ++ if (!err && (ia->ia_valid & ATTR_MODE)) ++ err = vfsub_acl_chmod(a->h_inode, ia->ia_mode); ++ if (!err) ++ au_cpup_attr_changeable(inode); ++ ++out_unlock: ++ inode_unlock(a->h_inode); ++ au_unpin(&a->pin); ++ if (unlikely(err)) ++ au_update_dbtop(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: ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++#if IS_ENABLED(CONFIG_AUFS_XATTR) || IS_ENABLED(CONFIG_FS_POSIX_ACL) ++static int au_h_path_to_set_attr(struct dentry *dentry, ++ struct au_icpup_args *a, struct path *h_path) ++{ ++ int err; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ a->udba = au_opt_udba(sb); ++ /* 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; ++ } ++ err = au_pin_and_icpup(dentry, /*ia*/NULL, a); ++ if (unlikely(err < 0)) ++ goto out; ++ ++ h_path->dentry = a->h_path.dentry; ++ h_path->mnt = au_sbr_mnt(sb, a->btgt); ++ ++out: ++ return err; ++} ++ ++ssize_t au_sxattr(struct dentry *dentry, struct inode *inode, ++ struct au_sxattr *arg) ++{ ++ int err; ++ struct path h_path; ++ struct super_block *sb; ++ struct au_icpup_args *a; ++ struct inode *h_inode; ++ ++ IMustLock(inode); ++ ++ err = -ENOMEM; ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out_kfree; ++ ++ h_path.dentry = NULL; /* silence gcc */ ++ di_write_lock_child(dentry); ++ err = au_h_path_to_set_attr(dentry, a, &h_path); ++ if (unlikely(err)) ++ goto out_di; ++ ++ inode_unlock(a->h_inode); ++ switch (arg->type) { ++ case AU_XATTR_SET: ++ AuDebugOn(d_is_negative(h_path.dentry)); ++ err = vfsub_setxattr(h_path.dentry, ++ arg->u.set.name, arg->u.set.value, ++ arg->u.set.size, arg->u.set.flags); ++ break; ++ case AU_ACL_SET: ++ err = -EOPNOTSUPP; ++ h_inode = d_inode(h_path.dentry); ++ if (h_inode->i_op->set_acl) ++ /* this will call posix_acl_update_mode */ ++ err = h_inode->i_op->set_acl(h_inode, ++ arg->u.acl_set.acl, ++ arg->u.acl_set.type); ++ break; ++ } ++ if (!err) ++ au_cpup_attr_timesizes(inode); ++ ++ au_unpin(&a->pin); ++ if (unlikely(err)) ++ au_update_dbtop(dentry); ++ ++out_di: ++ di_write_unlock(dentry); ++ si_read_unlock(sb); ++out_kfree: ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++#endif ++ ++static void au_refresh_iattr(struct inode *inode, struct kstat *st, ++ unsigned int nlink) ++{ ++ unsigned int n; ++ ++ inode->i_mode = st->mode; ++ /* don't i_[ug]id_write() here */ ++ inode->i_uid = st->uid; ++ inode->i_gid = 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; ++ smp_mb(); /* for i_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); ++} ++ ++/* ++ * common routine for aufs_getattr() and au_getxattr(). ++ * returns zero or negative (an error). ++ * @dentry will be read-locked in success. ++ */ ++int au_h_path_getattr(struct dentry *dentry, int force, struct path *h_path, ++ int locked) ++{ ++ int err; ++ unsigned int mnt_flags, sigen; ++ unsigned char udba_none; ++ aufs_bindex_t bindex; ++ struct super_block *sb, *h_sb; ++ struct inode *inode; ++ ++ h_path->mnt = NULL; ++ h_path->dentry = NULL; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ mnt_flags = au_mntflags(sb); ++ udba_none = !!au_opt_test(mnt_flags, UDBA_NONE); ++ ++ if (unlikely(locked)) ++ goto body; /* skip locking dinfo */ ++ ++ /* support fstat(2) */ ++ if (!d_unlinked(dentry) && !udba_none) { ++ 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)) { ++ di_read_unlock(dentry, AuLock_IR); ++ goto out; ++ } ++ } else { ++ AuDebugOn(IS_ROOT(dentry)); ++ di_write_lock_child(dentry); ++ err = au_dbrange_test(dentry); ++ if (!err) ++ err = au_reval_for_attr(dentry, sigen); ++ if (!err) ++ di_downgrade_lock(dentry, AuLock_IR); ++ else { ++ di_write_unlock(dentry); ++ goto out; ++ } ++ } ++ } else ++ di_read_lock_child(dentry, AuLock_IR); ++ ++body: ++ inode = d_inode(dentry); ++ bindex = au_ibtop(inode); ++ h_path->mnt = au_sbr_mnt(sb, bindex); ++ h_sb = h_path->mnt->mnt_sb; ++ if (!force ++ && !au_test_fs_bad_iattr(h_sb) ++ && udba_none) ++ goto out; /* success */ ++ ++ if (au_dbtop(dentry) == bindex) ++ h_path->dentry = au_h_dptr(dentry, bindex); ++ else if (au_opt_test(mnt_flags, PLINK) && au_plink_test(inode)) { ++ h_path->dentry = au_plink_lkup(inode, bindex); ++ if (IS_ERR(h_path->dentry)) ++ /* pretending success */ ++ h_path->dentry = NULL; ++ else ++ dput(h_path->dentry); ++ } ++ ++out: ++ return err; ++} ++ ++static int aufs_getattr(const struct path *path, struct kstat *st, ++ u32 request, unsigned int query) ++{ ++ int err; ++ unsigned char positive; ++ struct path h_path; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ dentry = path->dentry; ++ inode = d_inode(dentry); ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out; ++ err = au_h_path_getattr(dentry, /*force*/0, &h_path, /*locked*/0); ++ if (unlikely(err)) ++ goto out_si; ++ if (unlikely(!h_path.dentry)) ++ /* illegally overlapped or something */ ++ goto out_fill; /* pretending success */ ++ ++ positive = d_is_positive(h_path.dentry); ++ if (positive) ++ /* no vfsub version */ ++ err = vfs_getattr(&h_path, st, request, query); ++ if (!err) { ++ if (positive) ++ au_refresh_iattr(inode, st, ++ d_inode(h_path.dentry)->i_nlink); ++ goto out_fill; /* success */ ++ } ++ AuTraceErr(err); ++ goto out_di; ++ ++out_fill: ++ generic_fillattr(inode, st); ++out_di: ++ di_read_unlock(dentry, AuLock_IR); ++out_si: ++ si_read_unlock(sb); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static const char *aufs_get_link(struct dentry *dentry, struct inode *inode, ++ struct delayed_call *done) ++{ ++ const char *ret; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ int err; ++ aufs_bindex_t bindex; ++ ++ ret = NULL; /* suppress a warning */ ++ err = -ECHILD; ++ if (!dentry) ++ goto out; ++ ++ err = aufs_read_lock(dentry, AuLock_IR | AuLock_GEN); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_d_hashed_positive(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ err = -EINVAL; ++ inode = d_inode(dentry); ++ bindex = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, bindex); ++ if (unlikely(!h_inode->i_op->get_link)) ++ goto out_unlock; ++ ++ err = -EBUSY; ++ h_dentry = NULL; ++ if (au_dbtop(dentry) <= bindex) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry) ++ dget(h_dentry); ++ } ++ if (!h_dentry) { ++ h_dentry = d_find_any_alias(h_inode); ++ if (IS_ERR(h_dentry)) { ++ err = PTR_ERR(h_dentry); ++ goto out_unlock; ++ } ++ } ++ if (unlikely(!h_dentry)) ++ goto out_unlock; ++ ++ err = 0; ++ AuDbg("%ps\n", h_inode->i_op->get_link); ++ AuDbgDentry(h_dentry); ++ ret = vfs_get_link(h_dentry, done); ++ dput(h_dentry); ++ if (IS_ERR(ret)) ++ err = PTR_ERR(ret); ++ ++out_unlock: ++ aufs_read_unlock(dentry, AuLock_IR); ++out: ++ if (unlikely(err)) ++ ret = ERR_PTR(err); ++ AuTraceErrPtr(ret); ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_is_special(struct inode *inode) ++{ ++ return (inode->i_mode & (S_IFBLK | S_IFCHR | S_IFIFO | S_IFSOCK)); ++} ++ ++static int aufs_update_time(struct inode *inode, struct timespec64 *ts, ++ int flags) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct super_block *sb; ++ struct inode *h_inode; ++ struct vfsmount *h_mnt; ++ ++ sb = inode->i_sb; ++ WARN_ONCE((flags & S_ATIME) && !IS_NOATIME(inode), ++ "unexpected s_flags 0x%lx", sb->s_flags); ++ ++ /* mmap_sem might be acquired already, cf. aufs_mmap() */ ++ lockdep_off(); ++ si_read_lock(sb, AuLock_FLUSH); ++ ii_write_lock_child(inode); ++ ++ err = 0; ++ bindex = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, bindex); ++ if (!au_test_ro(sb, bindex, inode)) { ++ h_mnt = au_sbr_mnt(sb, bindex); ++ err = vfsub_mnt_want_write(h_mnt); ++ if (!err) { ++ err = vfsub_update_time(h_inode, ts, flags); ++ vfsub_mnt_drop_write(h_mnt); ++ } ++ } else if (au_is_special(h_inode)) { ++ /* ++ * Never copy-up here. ++ * These special files may already be opened and used for ++ * communicating. If we copied it up, then the communication ++ * would be corrupted. ++ */ ++ AuWarn1("timestamps for i%lu are ignored " ++ "since it is on readonly branch (hi%lu).\n", ++ inode->i_ino, h_inode->i_ino); ++ } else if (flags & ~S_ATIME) { ++ err = -EIO; ++ AuIOErr1("unexpected flags 0x%x\n", flags); ++ AuDebugOn(1); ++ } ++ ++ if (!err) ++ au_cpup_attr_timesizes(inode); ++ ii_write_unlock(inode); ++ si_read_unlock(sb); ++ lockdep_on(); ++ ++ if (!err && (flags & S_VERSION)) ++ inode_inc_iversion(inode); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* no getattr version will be set by module.c:aufs_init() */ ++struct inode_operations aufs_iop_nogetattr[AuIop_Last], ++ aufs_iop[] = { ++ [AuIop_SYMLINK] = { ++ .permission = aufs_permission, ++#ifdef CONFIG_FS_POSIX_ACL ++ .get_acl = aufs_get_acl, ++ .set_acl = aufs_set_acl, /* unsupport for symlink? */ ++#endif ++ ++ .setattr = aufs_setattr, ++ .getattr = aufs_getattr, ++ ++#ifdef CONFIG_AUFS_XATTR ++ .listxattr = aufs_listxattr, ++#endif ++ ++ .get_link = aufs_get_link, ++ ++ /* .update_time = aufs_update_time */ ++ }, ++ [AuIop_DIR] = { ++ .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, ++#ifdef CONFIG_FS_POSIX_ACL ++ .get_acl = aufs_get_acl, ++ .set_acl = aufs_set_acl, ++#endif ++ ++ .setattr = aufs_setattr, ++ .getattr = aufs_getattr, ++ ++#ifdef CONFIG_AUFS_XATTR ++ .listxattr = aufs_listxattr, ++#endif ++ ++ .update_time = aufs_update_time, ++ .atomic_open = aufs_atomic_open, ++ .tmpfile = aufs_tmpfile ++ }, ++ [AuIop_OTHER] = { ++ .permission = aufs_permission, ++#ifdef CONFIG_FS_POSIX_ACL ++ .get_acl = aufs_get_acl, ++ .set_acl = aufs_set_acl, ++#endif ++ ++ .setattr = aufs_setattr, ++ .getattr = aufs_getattr, ++ ++#ifdef CONFIG_AUFS_XATTR ++ .listxattr = aufs_listxattr, ++#endif ++ ++ .update_time = aufs_update_time ++ } ++}; +diff -Nurp linux-5.4/fs/aufs/i_op_del.c linux-5.4-aufs/fs/aufs/i_op_del.c +--- linux-5.4/fs/aufs/i_op_del.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/i_op_del.c 2019-11-28 01:25:59.066925618 +0200 +@@ -0,0 +1,500 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode operations (del entry) ++ */ ++ ++#include ++#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 btop; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ btop = au_dbtop(dentry); ++ if (*bcpup < 0) { ++ *bcpup = btop; ++ if (au_test_ro(sb, btop, d_inode(dentry))) { ++ err = AuWbrCopyup(au_sbi(sb), dentry); ++ *bcpup = err; ++ if (unlikely(err < 0)) ++ goto out; ++ } ++ } else ++ AuDebugOn(btop < *bcpup ++ || au_test_ro(sb, *bcpup, d_inode(dentry))); ++ AuDbg("bcpup %d, btop %d\n", *bcpup, btop); ++ ++ if (*bcpup != btop) { ++ 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, btop + 1, ++ /* AuLkup_IGNORE_PERM */ 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); ++ if (d_really_is_positive(dentry)) { ++ err = -ENOENT; ++ if (unlikely(d_is_negative(h_dentry))) ++ goto out; ++ h_inode = d_inode(h_dentry); ++ if (unlikely(!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(d_is_positive(h_dentry))) ++ 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_opt_test(au_mntflags(dentry->d_sb), DIRPERM1) ++ && au_test_h_perm(d_inode(h_parent), ++ MAY_EXEC | MAY_WRITE))) ++ goto out; ++ ++ h_latest = au_sio_lkup_one(&dentry->d_name, h_parent); ++ 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 deciding 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_dbtop(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; ++ struct inode *inode; ++ ++ 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 */ ++ inode = d_inode(dentry); ++ au_hn_free(au_hi(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 %pd, b%d failed, %d. ignored\n", ++ 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 = d_inode(dentry); ++ d_drop(dentry); ++ inode->i_ctime = dir->i_ctime; ++ ++ au_dir_ts(dir, bindex); ++ inode_inc_iversion(dir); ++} ++ ++/* ++ * 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("%pd reverting whiteout failed(%d, %d)\n", dentry, err, rerr); ++ return -EIO; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int aufs_unlink(struct inode *dir, struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t bwh, bindex, btop; ++ struct inode *inode, *h_dir, *delegated; ++ struct dentry *parent, *wh_dentry; ++ /* to reduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct au_pin pin; ++ struct path h_path; ++ } *a; ++ ++ 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_hashed_positive(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ err = -EISDIR; ++ if (unlikely(d_is_dir(dentry))) ++ goto out_unlock; /* possible? */ ++ ++ btop = au_dbtop(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, &a->dt, ++ &a->pin); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ a->h_path.mnt = au_sbr_mnt(dentry->d_sb, btop); ++ a->h_path.dentry = au_h_dptr(dentry, btop); ++ dget(a->h_path.dentry); ++ if (bindex == btop) { ++ h_dir = au_pinned_h_dir(&a->pin); ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, &a->h_path, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ } else { ++ /* dir inode is locked */ ++ h_dir = d_inode(wh_dentry->d_parent); ++ IMustLock(h_dir); ++ err = 0; ++ } ++ ++ if (!err) { ++ vfsub_drop_nlink(inode); ++ epilog(dir, dentry, bindex); ++ ++ /* update target timestamps */ ++ if (bindex == btop) { ++ vfsub_update_h_iattr(&a->h_path, /*did*/NULL); ++ /*ignore*/ ++ inode->i_ctime = d_inode(a->h_path.dentry)->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, ++ &a->dt); ++ if (rerr) ++ err = rerr; ++ } ++ ++out_unpin: ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++ dput(a->h_path.dentry); ++out_parent: ++ di_write_unlock(parent); ++out_unlock: ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ au_kfree_rcu(a); ++out: ++ return err; ++} ++ ++int aufs_rmdir(struct inode *dir, struct dentry *dentry) ++{ ++ int err, rmdir_later; ++ aufs_bindex_t bwh, bindex, btop; ++ struct inode *inode; ++ struct dentry *parent, *wh_dentry, *h_dentry; ++ struct au_whtmp_rmdir *args; ++ /* to reduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct au_pin pin; ++ } *a; ++ ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_free; ++ err = au_alive_dir(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ err = -ENOTDIR; ++ if (unlikely(!d_is_dir(dentry))) ++ 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; ++ ++ btop = au_dbtop(dentry); ++ bwh = au_dbwh(dentry); ++ bindex = -1; ++ wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/1, &bindex, &a->dt, ++ &a->pin); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ h_dentry = au_h_dptr(dentry, btop); ++ dget(h_dentry); ++ rmdir_later = 0; ++ if (bindex == btop) { ++ err = renwh_and_rmdir(dentry, btop, &args->whlist, dir); ++ if (err > 0) { ++ rmdir_later = err; ++ err = 0; ++ } ++ } else { ++ /* stop monitoring */ ++ au_hn_free(au_hi(inode, btop)); ++ ++ /* dir inode is locked */ ++ IMustLock(d_inode(wh_dentry->d_parent)); ++ 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, btop, 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, ++ &a->dt); ++ if (rerr) ++ err = rerr; ++ } ++ ++out_unpin: ++ au_unpin(&a->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_free: ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} +diff -Nurp linux-5.4/fs/aufs/i_op_ren.c linux-5.4-aufs/fs/aufs/i_op_ren.c +--- linux-5.4/fs/aufs/i_op_ren.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/i_op_ren.c 2019-11-28 01:25:59.066925618 +0200 +@@ -0,0 +1,1237 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode operation (rename entry) ++ * todo: this is crazy monster ++ */ ++ ++#include ++#include "aufs.h" ++ ++enum { AuSRC, AuDST, AuSrcDst }; ++enum { AuPARENT, AuCHILD, AuParentChild }; ++ ++#define AuRen_ISDIR_SRC 1 ++#define AuRen_ISDIR_DST (1 << 1) ++#define AuRen_ISSAMEDIR (1 << 2) ++#define AuRen_WHSRC (1 << 3) ++#define AuRen_WHDST (1 << 4) ++#define AuRen_MNT_WRITE (1 << 5) ++#define AuRen_DT_DSTDIR (1 << 6) ++#define AuRen_DIROPQ_SRC (1 << 7) ++#define AuRen_DIROPQ_DST (1 << 8) ++#define AuRen_DIRREN (1 << 9) ++#define AuRen_DROPPED_SRC (1 << 10) ++#define AuRen_DROPPED_DST (1 << 11) ++#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) ++ ++#ifndef CONFIG_AUFS_DIRREN ++#undef AuRen_DIRREN ++#define AuRen_DIRREN 0 ++#endif ++ ++struct au_ren_args { ++ struct { ++ struct dentry *dentry, *h_dentry, *parent, *h_parent, ++ *wh_dentry; ++ struct inode *dir, *inode; ++ struct au_hinode *hdir, *hinode; ++ struct au_dtime dt[AuParentChild]; ++ aufs_bindex_t btop, bdiropq; ++ } 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_hinode sd[AuSRC].hinode ++#define src_h_dir sd[AuSRC].hdir->hi_inode ++#define src_dt sd[AuSRC].dt ++#define src_btop sd[AuSRC].btop ++#define src_bdiropq sd[AuSRC].bdiropq ++ ++#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_hinode sd[AuDST].hinode ++#define dst_h_dir sd[AuDST].hdir->hi_inode ++#define dst_dt sd[AuDST].dt ++#define dst_btop sd[AuDST].btop ++#define dst_bdiropq sd[AuDST].bdiropq ++ ++ struct dentry *h_trap; ++ struct au_branch *br; ++ struct path h_path; ++ struct au_nhash whlist; ++ aufs_bindex_t btgt, src_bwh; ++ ++ struct { ++ unsigned short auren_flags; ++ unsigned char flags; /* syscall parameter */ ++ unsigned char exchange; ++ } __packed; ++ ++ struct au_whtmp_rmdir *thargs; ++ struct dentry *h_dst; ++ struct au_hinode *h_root; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * functions for reverting. ++ * when an error happened in a single rename systemcall, we should revert ++ * everything as if nothing happened. ++ * 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_do_rev_diropq(int err, struct au_ren_args *a, int idx) ++{ ++ int rerr; ++ struct dentry *d; ++#define src_or_dst(member) a->sd[idx].member ++ ++ d = src_or_dst(dentry); /* {src,dst}_dentry */ ++ au_hn_inode_lock_nested(src_or_dst(hinode), AuLsc_I_CHILD); ++ rerr = au_diropq_remove(d, a->btgt); ++ au_hn_inode_unlock(src_or_dst(hinode)); ++ au_set_dbdiropq(d, src_or_dst(bdiropq)); ++ if (rerr) ++ RevertFailure("remove diropq %pd", d); ++ ++#undef src_or_dst_ ++} ++ ++static void au_ren_rev_diropq(int err, struct au_ren_args *a) ++{ ++ if (au_ftest_ren(a->auren_flags, DIROPQ_SRC)) ++ au_ren_do_rev_diropq(err, a, AuSRC); ++ if (au_ftest_ren(a->auren_flags, DIROPQ_DST)) ++ au_ren_do_rev_diropq(err, a, AuDST); ++} ++ ++static void au_ren_rev_rename(int err, struct au_ren_args *a) ++{ ++ int rerr; ++ struct inode *delegated; ++ ++ 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 %pd", a->src_dentry); ++ return; ++ } ++ ++ delegated = NULL; ++ rerr = vfsub_rename(a->dst_h_dir, ++ au_h_dptr(a->src_dentry, a->btgt), ++ a->src_h_dir, &a->h_path, &delegated, a->flags); ++ if (unlikely(rerr == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ 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 %pd", a->src_dentry); ++} ++ ++static void au_ren_rev_whtmp(int err, struct au_ren_args *a) ++{ ++ int rerr; ++ struct inode *delegated; ++ ++ 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 %pd", a->dst_dentry); ++ return; ++ } ++ if (d_is_positive(a->h_path.dentry)) { ++ d_drop(a->h_path.dentry); ++ dput(a->h_path.dentry); ++ return; ++ } ++ ++ delegated = NULL; ++ rerr = vfsub_rename(a->dst_h_dir, a->h_dst, a->dst_h_dir, &a->h_path, ++ &delegated, a->flags); ++ if (unlikely(rerr == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ 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 %pd", 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 %pd", 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; ++ struct inode *delegated; ++ ++ d = a->src_dentry; ++ if (au_dbtop(d) == a->btgt) { ++ a->h_path.dentry = a->dst_h_dentry; ++ AuDebugOn(au_dbtop(d) != a->btgt); ++ delegated = NULL; ++ err = vfsub_rename(a->src_h_dir, au_h_dptr(d, a->btgt), ++ a->dst_h_dir, &a->h_path, &delegated, ++ a->flags); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ } else ++ BUG(); ++ ++ 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 %pd (%d), " ++ "ignored.\n", 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_do_diropq(struct au_ren_args *a, int idx) ++{ ++ int err; ++ struct dentry *d, *diropq; ++#define src_or_dst(member) a->sd[idx].member ++ ++ err = 0; ++ d = src_or_dst(dentry); /* {src,dst}_dentry */ ++ src_or_dst(bdiropq) = au_dbdiropq(d); ++ src_or_dst(hinode) = au_hi(src_or_dst(inode), a->btgt); ++ au_hn_inode_lock_nested(src_or_dst(hinode), AuLsc_I_CHILD); ++ diropq = au_diropq_create(d, a->btgt); ++ au_hn_inode_unlock(src_or_dst(hinode)); ++ if (IS_ERR(diropq)) ++ err = PTR_ERR(diropq); ++ else ++ dput(diropq); ++ ++#undef src_or_dst_ ++ return err; ++} ++ ++static int au_ren_diropq(struct au_ren_args *a) ++{ ++ int err; ++ unsigned char always; ++ struct dentry *d; ++ ++ err = 0; ++ d = a->dst_dentry; /* already renamed on the branch */ ++ always = !!au_opt_test(au_mntflags(d->d_sb), ALWAYS_DIROPQ); ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC) ++ && !au_ftest_ren(a->auren_flags, DIRREN) ++ && a->btgt != au_dbdiropq(a->src_dentry) ++ && (a->dst_wh_dentry ++ || a->btgt <= au_dbdiropq(d) ++ /* hide the lower to keep xino */ ++ /* the lowers may not be a dir, but we hide them anyway */ ++ || a->btgt < au_dbbot(d) ++ || always)) { ++ AuDbg("here\n"); ++ err = au_ren_do_diropq(a, AuSRC); ++ if (unlikely(err)) ++ goto out; ++ au_fset_ren(a->auren_flags, DIROPQ_SRC); ++ } ++ if (!a->exchange) ++ goto out; /* success */ ++ ++ d = a->src_dentry; /* already renamed on the branch */ ++ if (au_ftest_ren(a->auren_flags, ISDIR_DST) ++ && a->btgt != au_dbdiropq(a->dst_dentry) ++ && (a->btgt < au_dbdiropq(d) ++ || a->btgt < au_dbbot(d) ++ || always)) { ++ AuDbgDentry(a->src_dentry); ++ AuDbgDentry(a->dst_dentry); ++ err = au_ren_do_diropq(a, AuDST); ++ if (unlikely(err)) ++ goto out_rev_src; ++ au_fset_ren(a->auren_flags, DIROPQ_DST); ++ } ++ goto out; /* success */ ++ ++out_rev_src: ++ AuDbg("err %d, reverting src\n", err); ++ au_ren_rev_diropq(err, a); ++out: ++ return err; ++} ++ ++static int do_rename(struct au_ren_args *a) ++{ ++ int err; ++ struct dentry *d, *h_d; ++ ++ if (!a->exchange) { ++ /* prepare workqueue args for asynchronous rmdir */ ++ h_d = a->dst_h_dentry; ++ if (au_ftest_ren(a->auren_flags, ISDIR_DST) ++ /* && !au_ftest_ren(a->auren_flags, DIRREN) */ ++ && d_is_positive(h_d)) { ++ 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->auren_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->auren_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 (d_is_negative(h_d)) ++ 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, /*wh*/0); ++ if (unlikely(err)) ++ goto out_whtmp; ++ a->dst_h_dentry = au_h_dptr(d, a->btgt); ++ } ++ } ++ ++ BUG_ON(d_is_positive(a->dst_h_dentry) && a->src_btop != a->btgt); ++#if 0 ++ BUG_ON(!au_ftest_ren(a->auren_flags, DIRREN) ++ && d_is_positive(a->dst_h_dentry) ++ && a->src_btop != a->btgt); ++#endif ++ ++ /* rename by vfs_rename or cpup */ ++ err = au_ren_or_cpup(a); ++ if (unlikely(err)) ++ /* leave the copied-up one */ ++ goto out_whtmp; ++ ++ /* make dir opaque */ ++ err = au_ren_diropq(a); ++ if (unlikely(err)) ++ goto out_rename; ++ ++ /* update target timestamps */ ++ if (a->exchange) { ++ AuDebugOn(au_dbtop(a->dst_dentry) != a->btgt); ++ a->h_path.dentry = au_h_dptr(a->dst_dentry, a->btgt); ++ vfsub_update_h_iattr(&a->h_path, /*did*/NULL); /*ignore*/ ++ a->dst_inode->i_ctime = d_inode(a->h_path.dentry)->i_ctime; ++ } ++ AuDebugOn(au_dbtop(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 = d_inode(a->h_path.dentry)->i_ctime; ++ ++ if (!a->exchange) { ++ /* 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 */ ++ ++ au_fhsm_wrote(a->src_dentry->d_sb, a->btgt, /*force*/0); ++ } ++ err = 0; ++ goto out_success; ++ ++out_diropq: ++ au_ren_rev_diropq(err, a); ++out_rename: ++ au_ren_rev_rename(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 @a->src_dentry dir can be rename source or not. ++ * if it can, return 0. ++ * success means, ++ * - it is a logically empty dir. ++ * - or, it exists on writable branch and has no children including whiteouts ++ * on the lower branch unless DIRREN is on. ++ */ ++static int may_rename_srcdir(struct au_ren_args *a) ++{ ++ int err; ++ unsigned int rdhash; ++ aufs_bindex_t btop, btgt; ++ struct dentry *dentry; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++ dentry = a->src_dentry; ++ sb = dentry->d_sb; ++ sbinfo = au_sbi(sb); ++ if (au_opt_test(sbinfo->si_mntflags, DIRREN)) ++ au_fset_ren(a->auren_flags, DIRREN); ++ ++ btgt = a->btgt; ++ btop = au_dbtop(dentry); ++ if (btop != btgt) { ++ struct au_nhash whlist; ++ ++ SiMustAnyLock(sb); ++ rdhash = sbinfo->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 (btop == au_dbtaildir(dentry)) ++ return 0; /* success */ ++ ++ err = au_test_empty_lower(dentry); ++ ++out: ++ if (err == -ENOTEMPTY) { ++ if (au_ftest_ren(a->auren_flags, DIRREN)) { ++ err = 0; ++ } else { ++ 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->auren_flags, ISDIR_DST) && 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; ++ ++ if (!a->exchange) { ++ au_set_dbtop(d, a->dst_btop); ++ err = may_rename_dstdir(d, &a->whlist); ++ au_set_dbtop(d, a->btgt); ++ } else ++ err = may_rename_srcdir(a); ++ } ++ a->dst_h_dentry = au_h_dptr(d, au_dbtop(d)); ++ if (unlikely(err)) ++ goto out; ++ ++ d = a->src_dentry; ++ a->src_h_dentry = au_h_dptr(d, au_dbtop(d)); ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC)) { ++ err = may_rename_srcdir(a); ++ 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_btop == a->btgt) { ++ err = au_may_del(a->src_dentry, a->btgt, a->src_h_parent, ++ au_ftest_ren(a->auren_flags, ISDIR_SRC)); ++ if (unlikely(err)) ++ goto out; ++ err = -EINVAL; ++ if (unlikely(a->src_h_dentry == a->h_trap)) ++ goto out; ++ } ++ ++ err = 0; ++ if (a->dst_btop != a->btgt) ++ goto out; ++ ++ err = -ENOTEMPTY; ++ if (unlikely(a->dst_h_dentry == a->h_trap)) ++ goto out; ++ ++ err = -EIO; ++ isdir = !!au_ftest_ren(a->auren_flags, ISDIR_DST); ++ if (d_really_is_negative(a->dst_dentry)) { ++ if (d_is_negative(a->dst_h_dentry)) ++ err = au_may_add(a->dst_dentry, a->btgt, ++ a->dst_h_parent, isdir); ++ } else { ++ if (unlikely(d_is_negative(a->dst_h_dentry))) ++ goto out; ++ h_inode = d_inode(a->dst_h_dentry); ++ if (h_inode->i_nlink) ++ err = au_may_del(a->dst_dentry, a->btgt, ++ a->dst_h_parent, isdir); ++ } ++ ++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 exists ++ * (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) ++{ ++ vfsub_unlock_rename(a->src_h_parent, a->src_hdir, ++ a->dst_h_parent, a->dst_hdir); ++ if (au_ftest_ren(a->auren_flags, DIRREN) ++ && a->h_root) ++ au_hn_inode_unlock(a->h_root); ++ if (au_ftest_ren(a->auren_flags, MNT_WRITE)) ++ vfsub_mnt_drop_write(au_br_mnt(a->br)); ++} ++ ++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); ++ ++ err = vfsub_mnt_want_write(au_br_mnt(a->br)); ++ if (unlikely(err)) ++ goto out; ++ au_fset_ren(a->auren_flags, MNT_WRITE); ++ if (au_ftest_ren(a->auren_flags, DIRREN)) { ++ struct dentry *root; ++ struct inode *dir; ++ ++ /* ++ * sbinfo is already locked, so this ii_read_lock is ++ * unnecessary. but our debugging feature checks it. ++ */ ++ root = a->src_inode->i_sb->s_root; ++ if (root != a->src_parent && root != a->dst_parent) { ++ dir = d_inode(root); ++ ii_read_lock_parent3(dir); ++ a->h_root = au_hi(dir, a->btgt); ++ ii_read_unlock(dir); ++ au_hn_inode_lock_nested(a->h_root, AuLsc_I_PARENT3); ++ } ++ } ++ 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 != d_inode(a->src_h_parent) ++ || a->dst_hdir->hi_inode != d_inode(a->dst_h_parent))) ++ err = au_busy_or_stale(); ++ if (!err && au_dbtop(a->src_dentry) == a->btgt) ++ err = au_h_verify(a->src_h_dentry, udba, ++ d_inode(a->src_h_parent), a->src_h_parent, ++ a->br); ++ if (!err && au_dbtop(a->dst_dentry) == a->btgt) ++ err = au_h_verify(a->dst_h_dentry, udba, ++ d_inode(a->dst_h_parent), a->dst_h_parent, ++ a->br); ++ if (!err) ++ goto out; /* success */ ++ ++ err = au_busy_or_stale(); ++ 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; ++ inode_inc_iversion(dir); ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC)) { ++ /* is this updating defined in POSIX? */ ++ au_cpup_attr_timesizes(a->src_inode); ++ au_cpup_attr_nlink(dir, /*force*/1); ++ } ++ au_dir_ts(dir, a->btgt); ++ ++ if (a->exchange) { ++ dir = a->src_dir; ++ inode_inc_iversion(dir); ++ if (au_ftest_ren(a->auren_flags, ISDIR_DST)) { ++ /* is this updating defined in POSIX? */ ++ au_cpup_attr_timesizes(a->dst_inode); ++ au_cpup_attr_nlink(dir, /*force*/1); ++ } ++ au_dir_ts(dir, a->btgt); ++ } ++ ++ if (au_ftest_ren(a->auren_flags, ISSAMEDIR)) ++ return; ++ ++ dir = a->src_dir; ++ inode_inc_iversion(dir); ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC)) ++ au_cpup_attr_nlink(dir, /*force*/1); ++ au_dir_ts(dir, a->btgt); ++} ++ ++static void au_ren_refresh(struct au_ren_args *a) ++{ ++ aufs_bindex_t bbot, 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 (!a->exchange) { ++ if (!au_ftest_ren(a->auren_flags, ISDIR_DST)) ++ vfsub_drop_nlink(i); ++ else { ++ vfsub_dead_dir(i); ++ au_cpup_attr_timesizes(i); ++ } ++ au_update_dbrange(d, /*do_put_zero*/1); ++ } else ++ au_cpup_attr_nlink(i, /*force*/1); ++ } else { ++ bbot = a->btgt; ++ for (bindex = au_dbtop(d); bindex < bbot; bindex++) ++ au_set_h_dptr(d, bindex, NULL); ++ bbot = au_dbbot(d); ++ for (bindex = a->btgt + 1; bindex <= bbot; bindex++) ++ au_set_h_dptr(d, bindex, NULL); ++ au_update_dbrange(d, /*do_put_zero*/0); ++ } ++ ++ if (a->exchange ++ || au_ftest_ren(a->auren_flags, DIRREN)) { ++ d_drop(a->src_dentry); ++ if (au_ftest_ren(a->auren_flags, DIRREN)) ++ au_set_dbwh(a->src_dentry, -1); ++ return; ++ } ++ ++ d = a->src_dentry; ++ au_set_dbwh(d, -1); ++ bbot = au_dbbot(d); ++ for (bindex = a->btgt + 1; bindex <= bbot; bindex++) { ++ h_d = au_h_dptr(d, bindex); ++ if (h_d) ++ au_set_h_dptr(d, bindex, NULL); ++ } ++ au_set_dbbot(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 */ ++ ++ bbot = au_ibbot(i); ++ for (bindex = a->btgt + 1; bindex <= bbot; 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_ibbot(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(d_inode(parent)); /* 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_btop, dst_btop 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_btop = au_dbtop(a->src_dentry); ++ a->dst_btop = au_dbtop(a->dst_dentry); ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC) ++ || au_ftest_ren(a->auren_flags, ISDIR_DST)) ++ au_fset_wrdir(wr_dir_args.flags, ISDIR); ++ wr_dir_args.force_btgt = a->src_btop; ++ if (a->dst_inode && a->dst_btop < a->src_btop) ++ wr_dir_args.force_btgt = a->dst_btop; ++ 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; ++ if (a->exchange) ++ au_update_dbtop(a->dst_dentry); ++ ++ 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->auren_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->auren_flags, DT_DSTDIR); ++ if (!au_ftest_ren(a->auren_flags, ISDIR_SRC) ++ && !a->exchange) ++ return; ++ ++ a->h_path.dentry = a->src_h_dentry; ++ au_dtime_store(a->src_dt + AuCHILD, a->src_dentry, &a->h_path); ++ if (d_is_positive(a->dst_h_dentry)) { ++ au_fset_ren(a->auren_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 inode *h_inode; ++ ++ au_dtime_revert(a->src_dt + AuPARENT); ++ if (!au_ftest_ren(a->auren_flags, ISSAMEDIR)) ++ au_dtime_revert(a->dst_dt + AuPARENT); ++ ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC) && err != -EIO) { ++ h_d = a->src_dt[AuCHILD].dt_h_path.dentry; ++ h_inode = d_inode(h_d); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ au_dtime_revert(a->src_dt + AuCHILD); ++ inode_unlock(h_inode); ++ ++ if (au_ftest_ren(a->auren_flags, DT_DSTDIR)) { ++ h_d = a->dst_dt[AuCHILD].dt_h_path.dentry; ++ h_inode = d_inode(h_d); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ au_dtime_revert(a->dst_dt + AuCHILD); ++ inode_unlock(h_inode); ++ } ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int aufs_rename(struct inode *_src_dir, struct dentry *_src_dentry, ++ struct inode *_dst_dir, struct dentry *_dst_dentry, ++ unsigned int _flags) ++{ ++ int err, lock_flags; ++ void *rev; ++ /* reduce stack space */ ++ struct au_ren_args *a; ++ struct au_pin pin; ++ ++ AuDbg("%pd, %pd, 0x%x\n", _src_dentry, _dst_dentry, _flags); ++ IMustLock(_src_dir); ++ IMustLock(_dst_dir); ++ ++ err = -EINVAL; ++ if (unlikely(_flags & RENAME_WHITEOUT)) ++ goto out; ++ ++ err = -ENOMEM; ++ BUILD_BUG_ON(sizeof(*a) > PAGE_SIZE); ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ a->flags = _flags; ++ BUILD_BUG_ON(sizeof(a->exchange) == sizeof(u8) ++ && RENAME_EXCHANGE > U8_MAX); ++ a->exchange = _flags & RENAME_EXCHANGE; ++ a->src_dir = _src_dir; ++ a->src_dentry = _src_dentry; ++ a->src_inode = NULL; ++ if (d_really_is_positive(a->src_dentry)) ++ a->src_inode = d_inode(a->src_dentry); ++ 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 = NULL; ++ if (d_really_is_positive(a->dst_dentry)) ++ a->dst_inode = d_inode(a->dst_dentry); ++ a->dst_parent = a->dst_dentry->d_parent; /* dir inode is locked */ ++ if (a->dst_inode) { ++ /* ++ * if EXCHANGE && src is non-dir && dst is dir, ++ * dst is not locked. ++ */ ++ /* IMustLock(a->dst_inode); */ ++ au_igrab(a->dst_inode); ++ } ++ ++ err = -ENOTDIR; ++ lock_flags = AuLock_FLUSH | AuLock_NOPLM | AuLock_GEN; ++ if (d_is_dir(a->src_dentry)) { ++ au_fset_ren(a->auren_flags, ISDIR_SRC); ++ if (unlikely(!a->exchange ++ && d_really_is_positive(a->dst_dentry) ++ && !d_is_dir(a->dst_dentry))) ++ goto out_free; ++ lock_flags |= AuLock_DIRS; ++ } ++ if (a->dst_inode && d_is_dir(a->dst_dentry)) { ++ au_fset_ren(a->auren_flags, ISDIR_DST); ++ if (unlikely(!a->exchange ++ && d_really_is_positive(a->src_dentry) ++ && !d_is_dir(a->src_dentry))) ++ goto out_free; ++ lock_flags |= AuLock_DIRS; ++ } ++ err = aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry, ++ lock_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 it before this ++ * function. It means we cannot rely upon d_unhashed(). ++ */ ++ if (unlikely(!a->dst_inode->i_nlink)) ++ goto out_unlock; ++ if (!au_ftest_ren(a->auren_flags, ISDIR_DST)) { ++ err = au_d_hashed_positive(a->dst_dentry); ++ if (unlikely(err && !a->exchange)) ++ 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 happened (in linux-3.3-rcN) but I don't know why. ++ * there may exist a problem somewhere else. ++ */ ++ err = -EINVAL; ++ if (unlikely(d_inode(a->dst_parent) == d_inode(a->src_dentry))) ++ goto out_unlock; ++ ++ au_fset_ren(a->auren_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 = au_br_mnt(a->br); ++ ++ /* 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_btop == a->btgt) { ++ au_fset_ren(a->auren_flags, WHDST); ++ } else { ++ err = au_cpup_dirs(a->dst_dentry, a->btgt); ++ if (unlikely(err)) ++ goto out_children; ++ } ++ ++ err = 0; ++ if (!a->exchange) { ++ 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->auren_flags, ++ ISDIR_SRC), ++ &a->btgt); ++ di_write_unlock(a->src_parent); ++ di_write_lock2_parent(a->src_parent, a->dst_parent, ++ /*isdir*/1); ++ au_fclr_ren(a->auren_flags, ISSAMEDIR); ++ } else ++ err = au_wr_dir_need_wh(a->src_dentry, ++ au_ftest_ren(a->auren_flags, ++ ISDIR_SRC), ++ &a->btgt); ++ } ++ if (unlikely(err < 0)) ++ goto out_children; ++ if (err) ++ au_fset_ren(a->auren_flags, WHSRC); ++ ++ /* cpup src */ ++ if (a->src_btop != a->btgt) { ++ err = au_pin(&pin, a->src_dentry, a->btgt, ++ au_opt_udba(a->src_dentry->d_sb), ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (!err) { ++ struct au_cp_generic cpg = { ++ .dentry = a->src_dentry, ++ .bdst = a->btgt, ++ .bsrc = a->src_btop, ++ .len = -1, ++ .pin = &pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ AuDebugOn(au_dbtop(a->src_dentry) != a->src_btop); ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&pin); ++ } ++ if (unlikely(err)) ++ goto out_children; ++ a->src_btop = a->btgt; ++ a->src_h_dentry = au_h_dptr(a->src_dentry, a->btgt); ++ if (!a->exchange) ++ au_fset_ren(a->auren_flags, WHSRC); ++ } ++ ++ /* cpup dst */ ++ if (a->exchange && a->dst_inode ++ && a->dst_btop != a->btgt) { ++ err = au_pin(&pin, a->dst_dentry, a->btgt, ++ au_opt_udba(a->dst_dentry->d_sb), ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (!err) { ++ struct au_cp_generic cpg = { ++ .dentry = a->dst_dentry, ++ .bdst = a->btgt, ++ .bsrc = a->dst_btop, ++ .len = -1, ++ .pin = &pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&pin); ++ } ++ if (unlikely(err)) ++ goto out_children; ++ a->dst_btop = a->btgt; ++ a->dst_h_dentry = au_h_dptr(a->dst_dentry, a->btgt); ++ } ++ ++ /* lock them all */ ++ err = au_ren_lock(a); ++ if (unlikely(err)) ++ /* leave the copied-up one */ ++ goto out_children; ++ ++ if (!a->exchange) { ++ 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); ++ ++ /* store dirren info */ ++ if (au_ftest_ren(a->auren_flags, DIRREN)) { ++ err = au_dr_rename(a->src_dentry, a->btgt, ++ &a->dst_dentry->d_name, &rev); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out_dt; ++ } ++ ++ /* here we go */ ++ err = do_rename(a); ++ if (unlikely(err)) ++ goto out_dirren; ++ ++ if (au_ftest_ren(a->auren_flags, DIRREN)) ++ au_dr_rename_fin(a->src_dentry, a->btgt, rev); ++ ++ /* update dir attributes */ ++ au_ren_refresh_dir(a); ++ ++ /* dput/iput all lower dentries */ ++ au_ren_refresh(a); ++ ++ goto out_hdir; /* success */ ++ ++out_dirren: ++ if (au_ftest_ren(a->auren_flags, DIRREN)) ++ au_dr_rename_rev(a->src_dentry, a->btgt, rev); ++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_btop != a->btgt) { ++ AuDbg("btop %d, btgt %d\n", a->dst_btop, a->btgt); ++ au_set_h_dptr(a->dst_dentry, a->btgt, NULL); ++ au_set_dbtop(a->dst_dentry, a->dst_btop); ++ } ++out_parent: ++ if (!err) { ++ if (d_unhashed(a->src_dentry)) ++ au_fset_ren(a->auren_flags, DROPPED_SRC); ++ if (d_unhashed(a->dst_dentry)) ++ au_fset_ren(a->auren_flags, DROPPED_DST); ++ if (!a->exchange) ++ d_move(a->src_dentry, a->dst_dentry); ++ else { ++ d_exchange(a->src_dentry, a->dst_dentry); ++ if (au_ftest_ren(a->auren_flags, DROPPED_DST)) ++ d_drop(a->dst_dentry); ++ } ++ if (au_ftest_ren(a->auren_flags, DROPPED_SRC)) ++ d_drop(a->src_dentry); ++ } else { ++ au_update_dbtop(a->dst_dentry); ++ if (!a->dst_inode) ++ d_drop(a->dst_dentry); ++ } ++ if (au_ftest_ren(a->auren_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); ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} +diff -Nurp linux-5.4/fs/aufs/Kconfig linux-5.4-aufs/fs/aufs/Kconfig +--- linux-5.4/fs/aufs/Kconfig 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/Kconfig 2019-11-28 01:25:59.062925618 +0200 +@@ -0,0 +1,199 @@ ++# SPDX-License-Identifier: GPL-2.0 ++config AUFS_FS ++ bool "Aufs (Advanced multi layered unification filesystem) support" ++ 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 = y ++ 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_XATTR ++ bool "support for XATTR/EA (including Security Labels)" ++ help ++ If your branch fs supports XATTR/EA and you want to make them ++ available in aufs too, then enable this opsion and specify the ++ branch attributes for EA. ++ See detail in aufs.5. ++ ++config AUFS_FHSM ++ bool "File-based Hierarchical Storage Management" ++ help ++ Hierarchical Storage Management (or HSM) is a well-known feature ++ in the storage world. Aufs provides this feature as file-based. ++ with multiple branches. ++ These multiple branches are prioritized, ie. the topmost one ++ should be the fastest drive and be used heavily. ++ ++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_DIRREN ++ bool "Workaround for rename(2)-ing a directory" ++ help ++ By default, aufs returns EXDEV error in renameing a dir who has ++ his child on the lower branch, since it is a bad idea to issue ++ rename(2) internally for every lower branch. But user may not ++ accept this behaviour. So here is a workaround to allow such ++ rename(2) and store some extra infromation on the writable ++ branch. Obviously this costs high (and I don't like it). ++ To use this feature, you need to enable this configuration AND ++ to specify the mount option `dirren.' ++ See details in aufs.5 and the design documents. ++ ++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 -Nurp linux-5.4/fs/aufs/lcnt.h linux-5.4-aufs/fs/aufs/lcnt.h +--- linux-5.4/fs/aufs/lcnt.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/lcnt.h 2019-11-28 01:25:59.066925618 +0200 +@@ -0,0 +1,173 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2018-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * simple long counter wrapper ++ */ ++ ++#ifndef __AUFS_LCNT_H__ ++#define __AUFS_LCNT_H__ ++ ++#ifdef __KERNEL__ ++ ++#include "debug.h" ++ ++#define AuLCntATOMIC 1 ++#define AuLCntPCPUCNT 2 ++/* ++ * why does percpu_refcount require extra synchronize_rcu()s in ++ * au_br_do_free() ++ */ ++#define AuLCntPCPUREF 3 ++ ++/* #define AuLCntChosen AuLCntATOMIC */ ++#define AuLCntChosen AuLCntPCPUCNT ++/* #define AuLCntChosen AuLCntPCPUREF */ ++ ++#if AuLCntChosen == AuLCntATOMIC ++#include ++ ++typedef atomic_long_t au_lcnt_t; ++ ++static inline int au_lcnt_init(au_lcnt_t *cnt, void *release __maybe_unused) ++{ ++ atomic_long_set(cnt, 0); ++ return 0; ++} ++ ++static inline void au_lcnt_wait_for_fin(au_lcnt_t *cnt __maybe_unused) ++{ ++ /* empty */ ++} ++ ++static inline void au_lcnt_fin(au_lcnt_t *cnt __maybe_unused, ++ int do_sync __maybe_unused) ++{ ++ /* empty */ ++} ++ ++static inline void au_lcnt_inc(au_lcnt_t *cnt) ++{ ++ atomic_long_inc(cnt); ++} ++ ++static inline void au_lcnt_dec(au_lcnt_t *cnt) ++{ ++ atomic_long_dec(cnt); ++} ++ ++static inline long au_lcnt_read(au_lcnt_t *cnt, int do_rev __maybe_unused) ++{ ++ return atomic_long_read(cnt); ++} ++#endif ++ ++#if AuLCntChosen == AuLCntPCPUCNT ++#include ++ ++typedef struct percpu_counter au_lcnt_t; ++ ++static inline int au_lcnt_init(au_lcnt_t *cnt, void *release __maybe_unused) ++{ ++ return percpu_counter_init(cnt, 0, GFP_NOFS); ++} ++ ++static inline void au_lcnt_wait_for_fin(au_lcnt_t *cnt __maybe_unused) ++{ ++ /* empty */ ++} ++ ++static inline void au_lcnt_fin(au_lcnt_t *cnt, int do_sync __maybe_unused) ++{ ++ percpu_counter_destroy(cnt); ++} ++ ++static inline void au_lcnt_inc(au_lcnt_t *cnt) ++{ ++ percpu_counter_inc(cnt); ++} ++ ++static inline void au_lcnt_dec(au_lcnt_t *cnt) ++{ ++ percpu_counter_dec(cnt); ++} ++ ++static inline long au_lcnt_read(au_lcnt_t *cnt, int do_rev __maybe_unused) ++{ ++ s64 n; ++ ++ n = percpu_counter_sum(cnt); ++ BUG_ON(n < 0); ++ if (LONG_MAX != LLONG_MAX ++ && n > LONG_MAX) ++ AuWarn1("%s\n", "wrap-around"); ++ ++ return n; ++} ++#endif ++ ++#if AuLCntChosen == AuLCntPCPUREF ++#include ++ ++typedef struct percpu_ref au_lcnt_t; ++ ++static inline int au_lcnt_init(au_lcnt_t *cnt, percpu_ref_func_t *release) ++{ ++ if (!release) ++ release = percpu_ref_exit; ++ return percpu_ref_init(cnt, release, /*percpu mode*/0, GFP_NOFS); ++} ++ ++static inline void au_lcnt_wait_for_fin(au_lcnt_t *cnt __maybe_unused) ++{ ++ synchronize_rcu(); ++} ++ ++static inline void au_lcnt_fin(au_lcnt_t *cnt, int do_sync) ++{ ++ percpu_ref_kill(cnt); ++ if (do_sync) ++ au_lcnt_wait_for_fin(cnt); ++} ++ ++static inline void au_lcnt_inc(au_lcnt_t *cnt) ++{ ++ percpu_ref_get(cnt); ++} ++ ++static inline void au_lcnt_dec(au_lcnt_t *cnt) ++{ ++ percpu_ref_put(cnt); ++} ++ ++/* ++ * avoid calling this func as possible. ++ */ ++static inline long au_lcnt_read(au_lcnt_t *cnt, int do_rev) ++{ ++ long l; ++ ++ percpu_ref_switch_to_atomic_sync(cnt); ++ l = atomic_long_read(&cnt->count); ++ if (do_rev) ++ percpu_ref_switch_to_percpu(cnt); ++ ++ /* percpu_ref is initialized by 1 instead of 0 */ ++ return l - 1; ++} ++#endif ++ ++#ifdef CONFIG_AUFS_DEBUG ++#define AuLCntZero(val) do { \ ++ long l = val; \ ++ if (l) \ ++ AuDbg("%s = %ld\n", #val, l); \ ++} while (0) ++#else ++#define AuLCntZero(val) do {} while (0) ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_LCNT_H__ */ +diff -Nurp linux-5.4/fs/aufs/loop.c linux-5.4-aufs/fs/aufs/loop.c +--- linux-5.4/fs/aufs/loop.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/loop.c 2019-11-28 01:25:59.066925618 +0200 +@@ -0,0 +1,135 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * support for loopback block device as a branch ++ */ ++ ++#include "aufs.h" ++ ++/* added into drivers/block/loop.c */ ++static struct file *(*backing_file_func)(struct super_block *sb); ++ ++/* ++ * 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 file *backing_file; ++ ++ if (unlikely(!backing_file_func)) { ++ /* don't load "loop" module here */ ++ backing_file_func = symbol_get(loop_backing_file); ++ if (unlikely(!backing_file_func)) ++ /* "loop" module is not loaded */ ++ return 0; ++ } ++ ++ h_sb = h_adding->d_sb; ++ backing_file = backing_file_func(h_sb); ++ if (!backing_file) ++ return 0; ++ ++ h_adding = backing_file->f_path.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, ++ /*may_shrink*/0); ++ 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; ++ ++ BUILD_BUG_ON(sizeof(sb->s_magic) != sizeof(*au_warn_loopback_array)); ++ ++ 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) ++{ ++ if (backing_file_func) ++ symbol_put(loop_backing_file); ++ au_kfree_try_rcu(au_warn_loopback_array); ++} +diff -Nurp linux-5.4/fs/aufs/loop.h linux-5.4-aufs/fs/aufs/loop.h +--- linux-5.4/fs/aufs/loop.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/loop.h 2019-11-28 01:25:59.066925618 +0200 +@@ -0,0 +1,42 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * 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 ++/* drivers/block/loop.c */ ++struct file *loop_backing_file(struct super_block *sb); ++ ++/* 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 ++AuStub(struct file *, loop_backing_file, return NULL, struct super_block *sb) ++ ++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 -Nurp linux-5.4/fs/aufs/magic.mk linux-5.4-aufs/fs/aufs/magic.mk +--- linux-5.4/fs/aufs/magic.mk 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/magic.mk 2019-11-28 01:25:59.066925618 +0200 +@@ -0,0 +1,31 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++# defined in ${srctree}/fs/fuse/inode.c ++# tristate ++ifdef CONFIG_FUSE_FS ++ccflags-y += -DFUSE_SUPER_MAGIC=0x65735546 ++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/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 -Nurp linux-5.4/fs/aufs/Makefile linux-5.4-aufs/fs/aufs/Makefile +--- linux-5.4/fs/aufs/Makefile 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/Makefile 2019-11-28 01:25:59.062925618 +0200 +@@ -0,0 +1,39 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++include ${srctree}/${src}/magic.mk ++-include ${srctree}/${src}/priv_def.mk ++ ++# cf. include/linux/kernel.h ++# enable pr_debug ++ccflags-y += -DDEBUG ++# sparse requires the full pathname ++ccflags-y += -include ${srctree}/include/uapi/linux/aufs_type.h ++ ++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 \ ++ mvdown.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_XATTR) += xattr.o ++aufs-$(CONFIG_FS_POSIX_ACL) += posix_acl.o ++aufs-$(CONFIG_AUFS_DIRREN) += dirren.o ++aufs-$(CONFIG_AUFS_FHSM) += fhsm.o ++aufs-$(CONFIG_AUFS_POLL) += poll.o ++aufs-$(CONFIG_AUFS_RDU) += rdu.o ++aufs-$(CONFIG_AUFS_BR_HFSPLUS) += hfsplus.o ++aufs-$(CONFIG_AUFS_DEBUG) += debug.o ++aufs-$(CONFIG_AUFS_MAGIC_SYSRQ) += sysrq.o +diff -Nurp linux-5.4/fs/aufs/module.c linux-5.4-aufs/fs/aufs/module.c +--- linux-5.4/fs/aufs/module.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/module.c 2019-11-28 01:25:59.066925618 +0200 +@@ -0,0 +1,259 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * module global variables and operations ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++/* shrinkable realloc */ ++void *au_krealloc(void *p, unsigned int new_sz, gfp_t gfp, int may_shrink) ++{ ++ size_t sz; ++ int diff; ++ ++ sz = 0; ++ diff = -1; ++ if (p) { ++#if 0 /* unused */ ++ if (!new_sz) { ++ au_kfree_rcu(p); ++ p = NULL; ++ goto out; ++ } ++#else ++ AuDebugOn(!new_sz); ++#endif ++ sz = ksize(p); ++ diff = au_kmidx_sub(sz, new_sz); ++ } ++ if (sz && !diff) ++ goto out; ++ ++ if (sz < new_sz) ++ /* expand or SLOB */ ++ p = krealloc(p, new_sz, gfp); ++ else if (new_sz < sz && may_shrink) { ++ /* shrink */ ++ void *q; ++ ++ q = kmalloc(new_sz, gfp); ++ if (q) { ++ if (p) { ++ memcpy(q, p, new_sz); ++ au_kfree_try_rcu(p); ++ } ++ p = q; ++ } else ++ p = NULL; ++ } ++ ++out: ++ return p; ++} ++ ++void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp, ++ int may_shrink) ++{ ++ p = au_krealloc(p, new_sz, gfp, may_shrink); ++ if (p && new_sz > nused) ++ memset(p + nused, 0, new_sz - nused); ++ return p; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * aufs caches ++ */ ++struct kmem_cache *au_cache[AuCache_Last]; ++ ++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++) { ++ kmem_cache_destroy(au_cache[i]); ++ au_cache[i] = NULL; ++ } ++} ++ ++static int __init au_cache_init(void) ++{ ++ au_cache[AuCache_DINFO] = AuCacheCtor(au_dinfo, au_di_init_once); ++ if (au_cache[AuCache_DINFO]) ++ /* SLAB_DESTROY_BY_RCU */ ++ au_cache[AuCache_ICNTNR] = AuCacheCtor(au_icntnr, ++ au_icntnr_init_once); ++ if (au_cache[AuCache_ICNTNR]) ++ au_cache[AuCache_FINFO] = AuCacheCtor(au_finfo, ++ au_fi_init_once); ++ if (au_cache[AuCache_FINFO]) ++ au_cache[AuCache_VDIR] = AuCache(au_vdir); ++ if (au_cache[AuCache_VDIR]) ++ au_cache[AuCache_DEHSTR] = AuCache(au_vdir_dehstr); ++ if (au_cache[AuCache_DEHSTR]) ++ return 0; ++ ++ au_cache_fin(); ++ return -ENOMEM; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_dir_roflags; ++ ++#ifdef CONFIG_AUFS_SBILIST ++/* ++ * iterate_supers_type() doesn't protect us from ++ * remounting (branch management) ++ */ ++struct hlist_bl_head au_sbilist; ++#endif ++ ++/* ++ * 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, 0444); ++ ++/* this module parameter has no meaning when USER_NS is disabled */ ++bool au_userns; ++MODULE_PARM_DESC(allow_userns, "allow unprivileged to mount under userns"); ++module_param_named(allow_userns, au_userns, bool, 0444); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static char au_esc_chars[0x20 + 3]; /* 0x01-0x20, backslash, del, and NULL */ ++ ++int au_seq_path(struct seq_file *seq, struct path *path) ++{ ++ int err; ++ ++ err = seq_path(seq, path, au_esc_chars); ++ if (err >= 0) ++ err = 0; ++ else ++ err = -ENOMEM; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++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); ++ ++ memcpy(aufs_iop_nogetattr, aufs_iop, sizeof(aufs_iop)); ++ for (i = 0; i < AuIop_Last; i++) ++ aufs_iop_nogetattr[i].getattr = NULL; ++ ++ memset(au_cache, 0, sizeof(au_cache)); /* including hnotify */ ++ ++ au_sbilist_init(); ++ sysaufs_brs_init(); ++ au_debug_init(); ++ au_dy_init(); ++ err = sysaufs_init(); ++ if (unlikely(err)) ++ goto out; ++ err = dbgaufs_init(); ++ if (unlikely(err)) ++ goto out_sysaufs; ++ err = au_procfs_init(); ++ if (unlikely(err)) ++ goto out_dbgaufs; ++ 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; ++ ++ aufs_fs_type.fs_flags |= au_userns ? FS_USERNS_MOUNT : 0; ++ 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_dbgaufs: ++ dbgaufs_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(); ++ dbgaufs_fin(); ++ sysaufs_fin(); ++ au_dy_fin(); ++} ++ ++module_init(aufs_init); ++module_exit(aufs_exit); +diff -Nurp linux-5.4/fs/aufs/module.h linux-5.4-aufs/fs/aufs/module.h +--- linux-5.4/fs/aufs/module.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/module.h 2019-11-28 01:25:59.066925618 +0200 +@@ -0,0 +1,153 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * module initialization and module-global ++ */ ++ ++#ifndef __AUFS_MODULE_H__ ++#define __AUFS_MODULE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "debug.h" ++#include "dentry.h" ++#include "dir.h" ++#include "file.h" ++#include "inode.h" ++ ++struct path; ++struct seq_file; ++ ++/* module parameters */ ++extern int sysaufs_brs; ++extern bool au_userns; ++ ++/* ---------------------------------------------------------------------- */ ++ ++extern int au_dir_roflags; ++ ++void *au_krealloc(void *p, unsigned int new_sz, gfp_t gfp, int may_shrink); ++void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp, ++ int may_shrink); ++ ++/* ++ * Comparing the size of the object with sizeof(struct rcu_head) ++ * case 1: object is always larger ++ * --> au_kfree_rcu() or au_kfree_do_rcu() ++ * case 2: object is always smaller ++ * --> au_kfree_small() ++ * case 3: object can be any size ++ * --> au_kfree_try_rcu() ++ */ ++ ++static inline void au_kfree_do_rcu(const void *p) ++{ ++ struct { ++ struct rcu_head rcu; ++ } *a = (void *)p; ++ ++ kfree_rcu(a, rcu); ++} ++ ++#define au_kfree_rcu(_p) do { \ ++ typeof(_p) p = (_p); \ ++ BUILD_BUG_ON(sizeof(*p) < sizeof(struct rcu_head)); \ ++ if (p) \ ++ au_kfree_do_rcu(p); \ ++ } while (0) ++ ++#define au_kfree_do_sz_test(sz) (sz >= sizeof(struct rcu_head)) ++#define au_kfree_sz_test(p) (p && au_kfree_do_sz_test(ksize(p))) ++ ++static inline void au_kfree_try_rcu(const void *p) ++{ ++ if (!p) ++ return; ++ if (au_kfree_sz_test(p)) ++ au_kfree_do_rcu(p); ++ else ++ kfree(p); ++} ++ ++static inline void au_kfree_small(const void *p) ++{ ++ if (!p) ++ return; ++ AuDebugOn(au_kfree_sz_test(p)); ++ kfree(p); ++} ++ ++static inline int au_kmidx_sub(size_t sz, size_t new_sz) ++{ ++#ifndef CONFIG_SLOB ++ return kmalloc_index(sz) - kmalloc_index(new_sz); ++#else ++ return -1; /* SLOB is untested */ ++#endif ++} ++ ++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 ++}; ++ ++extern struct kmem_cache *au_cache[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) ++ ++#define AuCacheFuncs(name, index) \ ++ static inline struct au_##name *au_cache_alloc_##name(void) \ ++ { return kmem_cache_alloc(au_cache[AuCache_##index], GFP_NOFS); } \ ++ static inline void au_cache_free_##name##_norcu(struct au_##name *p) \ ++ { kmem_cache_free(au_cache[AuCache_##index], p); } \ ++ \ ++ static inline void au_cache_free_##name##_rcu_cb(struct rcu_head *rcu) \ ++ { void *p = rcu; \ ++ p -= offsetof(struct au_##name, rcu); \ ++ kmem_cache_free(au_cache[AuCache_##index], p); } \ ++ static inline void au_cache_free_##name##_rcu(struct au_##name *p) \ ++ { BUILD_BUG_ON(sizeof(struct au_##name) < sizeof(struct rcu_head)); \ ++ call_rcu(&p->rcu, au_cache_free_##name##_rcu_cb); } \ ++ \ ++ static inline void au_cache_free_##name(struct au_##name *p) \ ++ { /* au_cache_free_##name##_norcu(p); */ \ ++ au_cache_free_##name##_rcu(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 -Nurp linux-5.4/fs/aufs/mvdown.c linux-5.4-aufs/fs/aufs/mvdown.c +--- linux-5.4/fs/aufs/mvdown.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/mvdown.c 2019-11-28 01:25:59.067925618 +0200 +@@ -0,0 +1,693 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2011-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * move-down, opposite of copy-up ++ */ ++ ++#include "aufs.h" ++ ++struct au_mvd_args { ++ struct { ++ struct super_block *h_sb; ++ struct dentry *h_parent; ++ struct au_hinode *hdir; ++ struct inode *h_dir, *h_inode; ++ struct au_pin pin; ++ } info[AUFS_MVDOWN_NARRAY]; ++ ++ struct aufs_mvdown mvdown; ++ struct dentry *dentry, *parent; ++ struct inode *inode, *dir; ++ struct super_block *sb; ++ aufs_bindex_t bopq, bwh, bfound; ++ unsigned char rename_lock; ++}; ++ ++#define mvd_errno mvdown.au_errno ++#define mvd_bsrc mvdown.stbr[AUFS_MVDOWN_UPPER].bindex ++#define mvd_src_brid mvdown.stbr[AUFS_MVDOWN_UPPER].brid ++#define mvd_bdst mvdown.stbr[AUFS_MVDOWN_LOWER].bindex ++#define mvd_dst_brid mvdown.stbr[AUFS_MVDOWN_LOWER].brid ++ ++#define mvd_h_src_sb info[AUFS_MVDOWN_UPPER].h_sb ++#define mvd_h_src_parent info[AUFS_MVDOWN_UPPER].h_parent ++#define mvd_hdir_src info[AUFS_MVDOWN_UPPER].hdir ++#define mvd_h_src_dir info[AUFS_MVDOWN_UPPER].h_dir ++#define mvd_h_src_inode info[AUFS_MVDOWN_UPPER].h_inode ++#define mvd_pin_src info[AUFS_MVDOWN_UPPER].pin ++ ++#define mvd_h_dst_sb info[AUFS_MVDOWN_LOWER].h_sb ++#define mvd_h_dst_parent info[AUFS_MVDOWN_LOWER].h_parent ++#define mvd_hdir_dst info[AUFS_MVDOWN_LOWER].hdir ++#define mvd_h_dst_dir info[AUFS_MVDOWN_LOWER].h_dir ++#define mvd_h_dst_inode info[AUFS_MVDOWN_LOWER].h_inode ++#define mvd_pin_dst info[AUFS_MVDOWN_LOWER].pin ++ ++#define AU_MVD_PR(flag, ...) do { \ ++ if (flag) \ ++ pr_err(__VA_ARGS__); \ ++ } while (0) ++ ++static int find_lower_writable(struct au_mvd_args *a) ++{ ++ struct super_block *sb; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ sb = a->sb; ++ bindex = a->mvd_bsrc; ++ bbot = au_sbbot(sb); ++ if (a->mvdown.flags & AUFS_MVDOWN_FHSM_LOWER) ++ for (bindex++; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm) ++ && !sb_rdonly(au_br_sb(br))) ++ return bindex; ++ } ++ else if (!(a->mvdown.flags & AUFS_MVDOWN_ROLOWER)) ++ for (bindex++; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!au_br_rdonly(br)) ++ return bindex; ++ } ++ else ++ for (bindex++; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!sb_rdonly(au_br_sb(br))) { ++ if (au_br_rdonly(br)) ++ a->mvdown.flags ++ |= AUFS_MVDOWN_ROLOWER_R; ++ return bindex; ++ } ++ } ++ ++ return -1; ++} ++ ++/* make the parent dir on bdst */ ++static int au_do_mkdir(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ ++ err = 0; ++ a->mvd_hdir_src = au_hi(a->dir, a->mvd_bsrc); ++ a->mvd_hdir_dst = au_hi(a->dir, a->mvd_bdst); ++ a->mvd_h_src_parent = au_h_dptr(a->parent, a->mvd_bsrc); ++ a->mvd_h_dst_parent = NULL; ++ if (au_dbbot(a->parent) >= a->mvd_bdst) ++ a->mvd_h_dst_parent = au_h_dptr(a->parent, a->mvd_bdst); ++ if (!a->mvd_h_dst_parent) { ++ err = au_cpdown_dirs(a->dentry, a->mvd_bdst); ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "cpdown_dirs failed\n"); ++ goto out; ++ } ++ a->mvd_h_dst_parent = au_h_dptr(a->parent, a->mvd_bdst); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* lock them all */ ++static int au_do_lock(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct dentry *h_trap; ++ ++ a->mvd_h_src_sb = au_sbr_sb(a->sb, a->mvd_bsrc); ++ a->mvd_h_dst_sb = au_sbr_sb(a->sb, a->mvd_bdst); ++ err = au_pin(&a->mvd_pin_dst, a->dentry, a->mvd_bdst, ++ au_opt_udba(a->sb), ++ AuPin_MNT_WRITE | AuPin_DI_LOCKED); ++ AuTraceErr(err); ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "pin_dst failed\n"); ++ goto out; ++ } ++ ++ if (a->mvd_h_src_sb != a->mvd_h_dst_sb) { ++ a->rename_lock = 0; ++ au_pin_init(&a->mvd_pin_src, a->dentry, a->mvd_bsrc, ++ AuLsc_DI_PARENT, AuLsc_I_PARENT3, ++ au_opt_udba(a->sb), ++ AuPin_MNT_WRITE | AuPin_DI_LOCKED); ++ err = au_do_pin(&a->mvd_pin_src); ++ AuTraceErr(err); ++ a->mvd_h_src_dir = d_inode(a->mvd_h_src_parent); ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "pin_src failed\n"); ++ goto out_dst; ++ } ++ goto out; /* success */ ++ } ++ ++ a->rename_lock = 1; ++ au_pin_hdir_unlock(&a->mvd_pin_dst); ++ err = au_pin(&a->mvd_pin_src, a->dentry, a->mvd_bsrc, ++ au_opt_udba(a->sb), ++ AuPin_MNT_WRITE | AuPin_DI_LOCKED); ++ AuTraceErr(err); ++ a->mvd_h_src_dir = d_inode(a->mvd_h_src_parent); ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "pin_src failed\n"); ++ au_pin_hdir_lock(&a->mvd_pin_dst); ++ goto out_dst; ++ } ++ au_pin_hdir_unlock(&a->mvd_pin_src); ++ h_trap = vfsub_lock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, ++ a->mvd_h_dst_parent, a->mvd_hdir_dst); ++ if (h_trap) { ++ err = (h_trap != a->mvd_h_src_parent); ++ if (err) ++ err = (h_trap != a->mvd_h_dst_parent); ++ } ++ BUG_ON(err); /* it should never happen */ ++ if (unlikely(a->mvd_h_src_dir != au_pinned_h_dir(&a->mvd_pin_src))) { ++ err = -EBUSY; ++ AuTraceErr(err); ++ vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, ++ a->mvd_h_dst_parent, a->mvd_hdir_dst); ++ au_pin_hdir_lock(&a->mvd_pin_src); ++ au_unpin(&a->mvd_pin_src); ++ au_pin_hdir_lock(&a->mvd_pin_dst); ++ goto out_dst; ++ } ++ goto out; /* success */ ++ ++out_dst: ++ au_unpin(&a->mvd_pin_dst); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static void au_do_unlock(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ if (!a->rename_lock) ++ au_unpin(&a->mvd_pin_src); ++ else { ++ vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, ++ a->mvd_h_dst_parent, a->mvd_hdir_dst); ++ au_pin_hdir_lock(&a->mvd_pin_src); ++ au_unpin(&a->mvd_pin_src); ++ au_pin_hdir_lock(&a->mvd_pin_dst); ++ } ++ au_unpin(&a->mvd_pin_dst); ++} ++ ++/* copy-down the file */ ++static int au_do_cpdown(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct au_cp_generic cpg = { ++ .dentry = a->dentry, ++ .bdst = a->mvd_bdst, ++ .bsrc = a->mvd_bsrc, ++ .len = -1, ++ .pin = &a->mvd_pin_dst, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ ++ AuDbg("b%d, b%d\n", cpg.bsrc, cpg.bdst); ++ if (a->mvdown.flags & AUFS_MVDOWN_OWLOWER) ++ au_fset_cpup(cpg.flags, OVERWRITE); ++ if (a->mvdown.flags & AUFS_MVDOWN_ROLOWER) ++ au_fset_cpup(cpg.flags, RWDST); ++ err = au_sio_cpdown_simple(&cpg); ++ if (unlikely(err)) ++ AU_MVD_PR(dmsg, "cpdown failed\n"); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * unlink the whiteout on bdst if exist which may be created by UDBA while we ++ * were sleeping ++ */ ++static int au_do_unlink_wh(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct path h_path; ++ struct au_branch *br; ++ struct inode *delegated; ++ ++ br = au_sbr(a->sb, a->mvd_bdst); ++ h_path.dentry = au_wh_lkup(a->mvd_h_dst_parent, &a->dentry->d_name, br); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) { ++ AU_MVD_PR(dmsg, "wh_lkup failed\n"); ++ goto out; ++ } ++ ++ err = 0; ++ if (d_is_positive(h_path.dentry)) { ++ h_path.mnt = au_br_mnt(br); ++ delegated = NULL; ++ err = vfsub_unlink(d_inode(a->mvd_h_dst_parent), &h_path, ++ &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) ++ AU_MVD_PR(dmsg, "wh_unlink failed\n"); ++ } ++ dput(h_path.dentry); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * unlink the topmost h_dentry ++ */ ++static int au_do_unlink(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct path h_path; ++ struct inode *delegated; ++ ++ h_path.mnt = au_sbr_mnt(a->sb, a->mvd_bsrc); ++ h_path.dentry = au_h_dptr(a->dentry, a->mvd_bsrc); ++ delegated = NULL; ++ err = vfsub_unlink(a->mvd_h_src_dir, &h_path, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) ++ AU_MVD_PR(dmsg, "unlink failed\n"); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* Since mvdown succeeded, we ignore an error of this function */ ++static void au_do_stfs(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct au_branch *br; ++ ++ a->mvdown.flags |= AUFS_MVDOWN_STFS_FAILED; ++ br = au_sbr(a->sb, a->mvd_bsrc); ++ err = au_br_stfs(br, &a->mvdown.stbr[AUFS_MVDOWN_UPPER].stfs); ++ if (!err) { ++ br = au_sbr(a->sb, a->mvd_bdst); ++ a->mvdown.stbr[AUFS_MVDOWN_LOWER].brid = br->br_id; ++ err = au_br_stfs(br, &a->mvdown.stbr[AUFS_MVDOWN_LOWER].stfs); ++ } ++ if (!err) ++ a->mvdown.flags &= ~AUFS_MVDOWN_STFS_FAILED; ++ else ++ AU_MVD_PR(dmsg, "statfs failed (%d), ignored\n", err); ++} ++ ++/* ++ * copy-down the file and unlink the bsrc file. ++ * - unlink the bdst whout if exist ++ * - copy-down the file (with whtmp name and rename) ++ * - unlink the bsrc file ++ */ ++static int au_do_mvdown(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ ++ err = au_do_mkdir(dmsg, a); ++ if (!err) ++ err = au_do_lock(dmsg, a); ++ if (unlikely(err)) ++ goto out; ++ ++ /* ++ * do not revert the activities we made on bdst since they should be ++ * harmless in aufs. ++ */ ++ ++ err = au_do_cpdown(dmsg, a); ++ if (!err) ++ err = au_do_unlink_wh(dmsg, a); ++ if (!err && !(a->mvdown.flags & AUFS_MVDOWN_KUPPER)) ++ err = au_do_unlink(dmsg, a); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ AuDbg("%pd2, 0x%x, %d --> %d\n", ++ a->dentry, a->mvdown.flags, a->mvd_bsrc, a->mvd_bdst); ++ if (find_lower_writable(a) < 0) ++ a->mvdown.flags |= AUFS_MVDOWN_BOTTOM; ++ ++ if (a->mvdown.flags & AUFS_MVDOWN_STFS) ++ au_do_stfs(dmsg, a); ++ ++ /* maintain internal array */ ++ if (!(a->mvdown.flags & AUFS_MVDOWN_KUPPER)) { ++ au_set_h_dptr(a->dentry, a->mvd_bsrc, NULL); ++ au_set_dbtop(a->dentry, a->mvd_bdst); ++ au_set_h_iptr(a->inode, a->mvd_bsrc, NULL, /*flags*/0); ++ au_set_ibtop(a->inode, a->mvd_bdst); ++ } else { ++ /* hide the lower */ ++ au_set_h_dptr(a->dentry, a->mvd_bdst, NULL); ++ au_set_dbbot(a->dentry, a->mvd_bsrc); ++ au_set_h_iptr(a->inode, a->mvd_bdst, NULL, /*flags*/0); ++ au_set_ibbot(a->inode, a->mvd_bsrc); ++ } ++ if (au_dbbot(a->dentry) < a->mvd_bdst) ++ au_set_dbbot(a->dentry, a->mvd_bdst); ++ if (au_ibbot(a->inode) < a->mvd_bdst) ++ au_set_ibbot(a->inode, a->mvd_bdst); ++ ++out_unlock: ++ au_do_unlock(dmsg, a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* make sure the file is idle */ ++static int au_mvd_args_busy(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err, plinked; ++ ++ err = 0; ++ plinked = !!au_opt_test(au_mntflags(a->sb), PLINK); ++ if (au_dbtop(a->dentry) == a->mvd_bsrc ++ && au_dcount(a->dentry) == 1 ++ && atomic_read(&a->inode->i_count) == 1 ++ /* && a->mvd_h_src_inode->i_nlink == 1 */ ++ && (!plinked || !au_plink_test(a->inode)) ++ && a->inode->i_nlink == 1) ++ goto out; ++ ++ err = -EBUSY; ++ AU_MVD_PR(dmsg, ++ "b%d, d{b%d, c%d?}, i{c%d?, l%u}, hi{l%u}, p{%d, %d}\n", ++ a->mvd_bsrc, au_dbtop(a->dentry), au_dcount(a->dentry), ++ atomic_read(&a->inode->i_count), a->inode->i_nlink, ++ a->mvd_h_src_inode->i_nlink, ++ plinked, plinked ? au_plink_test(a->inode) : 0); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* make sure the parent dir is fine */ ++static int au_mvd_args_parent(const unsigned char dmsg, ++ struct au_mvd_args *a) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ ++ err = 0; ++ if (unlikely(au_alive_dir(a->parent))) { ++ err = -ENOENT; ++ AU_MVD_PR(dmsg, "parent dir is dead\n"); ++ goto out; ++ } ++ ++ a->bopq = au_dbdiropq(a->parent); ++ bindex = au_wbr_nonopq(a->dentry, a->mvd_bdst); ++ AuDbg("b%d\n", bindex); ++ if (unlikely((bindex >= 0 && bindex < a->mvd_bdst) ++ || (a->bopq != -1 && a->bopq < a->mvd_bdst))) { ++ err = -EINVAL; ++ a->mvd_errno = EAU_MVDOWN_OPAQUE; ++ AU_MVD_PR(dmsg, "ancestor is opaque b%d, b%d\n", ++ a->bopq, a->mvd_bdst); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_mvd_args_intermediate(const unsigned char dmsg, ++ struct au_mvd_args *a) ++{ ++ int err; ++ struct au_dinfo *dinfo, *tmp; ++ ++ /* lookup the next lower positive entry */ ++ err = -ENOMEM; ++ tmp = au_di_alloc(a->sb, AuLsc_DI_TMP); ++ if (unlikely(!tmp)) ++ goto out; ++ ++ a->bfound = -1; ++ a->bwh = -1; ++ dinfo = au_di(a->dentry); ++ au_di_cp(tmp, dinfo); ++ au_di_swap(tmp, dinfo); ++ ++ /* returns the number of positive dentries */ ++ err = au_lkup_dentry(a->dentry, a->mvd_bsrc + 1, ++ /* AuLkup_IGNORE_PERM */ 0); ++ if (!err) ++ a->bwh = au_dbwh(a->dentry); ++ else if (err > 0) ++ a->bfound = au_dbtop(a->dentry); ++ ++ au_di_swap(tmp, dinfo); ++ au_rw_write_unlock(&tmp->di_rwsem); ++ au_di_free(tmp); ++ if (unlikely(err < 0)) ++ AU_MVD_PR(dmsg, "failed look-up lower\n"); ++ ++ /* ++ * here, we have these cases. ++ * bfound == -1 ++ * no positive dentry under bsrc. there are more sub-cases. ++ * bwh < 0 ++ * there no whiteout, we can safely move-down. ++ * bwh <= bsrc ++ * impossible ++ * bsrc < bwh && bwh < bdst ++ * there is a whiteout on RO branch. cannot proceed. ++ * bwh == bdst ++ * there is a whiteout on the RW target branch. it should ++ * be removed. ++ * bdst < bwh ++ * there is a whiteout somewhere unrelated branch. ++ * -1 < bfound && bfound <= bsrc ++ * impossible. ++ * bfound < bdst ++ * found, but it is on RO branch between bsrc and bdst. cannot ++ * proceed. ++ * bfound == bdst ++ * found, replace it if AUFS_MVDOWN_FORCE is set. otherwise return ++ * error. ++ * bdst < bfound ++ * found, after we create the file on bdst, it will be hidden. ++ */ ++ ++ AuDebugOn(a->bfound == -1 ++ && a->bwh != -1 ++ && a->bwh <= a->mvd_bsrc); ++ AuDebugOn(-1 < a->bfound ++ && a->bfound <= a->mvd_bsrc); ++ ++ err = -EINVAL; ++ if (a->bfound == -1 ++ && a->mvd_bsrc < a->bwh ++ && a->bwh != -1 ++ && a->bwh < a->mvd_bdst) { ++ a->mvd_errno = EAU_MVDOWN_WHITEOUT; ++ AU_MVD_PR(dmsg, "bsrc %d, bdst %d, bfound %d, bwh %d\n", ++ a->mvd_bsrc, a->mvd_bdst, a->bfound, a->bwh); ++ goto out; ++ } else if (a->bfound != -1 && a->bfound < a->mvd_bdst) { ++ a->mvd_errno = EAU_MVDOWN_UPPER; ++ AU_MVD_PR(dmsg, "bdst %d, bfound %d\n", ++ a->mvd_bdst, a->bfound); ++ goto out; ++ } ++ ++ err = 0; /* success */ ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_mvd_args_exist(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ ++ err = 0; ++ if (!(a->mvdown.flags & AUFS_MVDOWN_OWLOWER) ++ && a->bfound == a->mvd_bdst) ++ err = -EEXIST; ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_mvd_args(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct au_branch *br; ++ ++ err = -EISDIR; ++ if (unlikely(S_ISDIR(a->inode->i_mode))) ++ goto out; ++ ++ err = -EINVAL; ++ if (!(a->mvdown.flags & AUFS_MVDOWN_BRID_UPPER)) ++ a->mvd_bsrc = au_ibtop(a->inode); ++ else { ++ a->mvd_bsrc = au_br_index(a->sb, a->mvd_src_brid); ++ if (unlikely(a->mvd_bsrc < 0 ++ || (a->mvd_bsrc < au_dbtop(a->dentry) ++ || au_dbbot(a->dentry) < a->mvd_bsrc ++ || !au_h_dptr(a->dentry, a->mvd_bsrc)) ++ || (a->mvd_bsrc < au_ibtop(a->inode) ++ || au_ibbot(a->inode) < a->mvd_bsrc ++ || !au_h_iptr(a->inode, a->mvd_bsrc)))) { ++ a->mvd_errno = EAU_MVDOWN_NOUPPER; ++ AU_MVD_PR(dmsg, "no upper\n"); ++ goto out; ++ } ++ } ++ if (unlikely(a->mvd_bsrc == au_sbbot(a->sb))) { ++ a->mvd_errno = EAU_MVDOWN_BOTTOM; ++ AU_MVD_PR(dmsg, "on the bottom\n"); ++ goto out; ++ } ++ a->mvd_h_src_inode = au_h_iptr(a->inode, a->mvd_bsrc); ++ br = au_sbr(a->sb, a->mvd_bsrc); ++ err = au_br_rdonly(br); ++ if (!(a->mvdown.flags & AUFS_MVDOWN_ROUPPER)) { ++ if (unlikely(err)) ++ goto out; ++ } else if (!(vfsub_native_ro(a->mvd_h_src_inode) ++ || IS_APPEND(a->mvd_h_src_inode))) { ++ if (err) ++ a->mvdown.flags |= AUFS_MVDOWN_ROUPPER_R; ++ /* go on */ ++ } else ++ goto out; ++ ++ err = -EINVAL; ++ if (!(a->mvdown.flags & AUFS_MVDOWN_BRID_LOWER)) { ++ a->mvd_bdst = find_lower_writable(a); ++ if (unlikely(a->mvd_bdst < 0)) { ++ a->mvd_errno = EAU_MVDOWN_BOTTOM; ++ AU_MVD_PR(dmsg, "no writable lower branch\n"); ++ goto out; ++ } ++ } else { ++ a->mvd_bdst = au_br_index(a->sb, a->mvd_dst_brid); ++ if (unlikely(a->mvd_bdst < 0 ++ || au_sbbot(a->sb) < a->mvd_bdst)) { ++ a->mvd_errno = EAU_MVDOWN_NOLOWERBR; ++ AU_MVD_PR(dmsg, "no lower brid\n"); ++ goto out; ++ } ++ } ++ ++ err = au_mvd_args_busy(dmsg, a); ++ if (!err) ++ err = au_mvd_args_parent(dmsg, a); ++ if (!err) ++ err = au_mvd_args_intermediate(dmsg, a); ++ if (!err) ++ err = au_mvd_args_exist(dmsg, a); ++ if (!err) ++ AuDbg("b%d, b%d\n", a->mvd_bsrc, a->mvd_bdst); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *uarg) ++{ ++ int err, e; ++ unsigned char dmsg; ++ struct au_mvd_args *args; ++ struct inode *inode; ++ ++ inode = d_inode(dentry); ++ err = -EPERM; ++ if (unlikely(!capable(CAP_SYS_ADMIN))) ++ goto out; ++ ++ err = -ENOMEM; ++ args = kmalloc(sizeof(*args), GFP_NOFS); ++ if (unlikely(!args)) ++ goto out; ++ ++ err = copy_from_user(&args->mvdown, uarg, sizeof(args->mvdown)); ++ if (!err) ++ /* VERIFY_WRITE */ ++ err = !access_ok(uarg, sizeof(*uarg)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out_free; ++ } ++ AuDbg("flags 0x%x\n", args->mvdown.flags); ++ args->mvdown.flags &= ~(AUFS_MVDOWN_ROLOWER_R | AUFS_MVDOWN_ROUPPER_R); ++ args->mvdown.au_errno = 0; ++ args->dentry = dentry; ++ args->inode = inode; ++ args->sb = dentry->d_sb; ++ ++ err = -ENOENT; ++ dmsg = !!(args->mvdown.flags & AUFS_MVDOWN_DMSG); ++ args->parent = dget_parent(dentry); ++ args->dir = d_inode(args->parent); ++ inode_lock_nested(args->dir, I_MUTEX_PARENT); ++ dput(args->parent); ++ if (unlikely(args->parent != dentry->d_parent)) { ++ AU_MVD_PR(dmsg, "parent dir is moved\n"); ++ goto out_dir; ++ } ++ ++ inode_lock_nested(inode, I_MUTEX_CHILD); ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_NOPLMW); ++ if (unlikely(err)) ++ goto out_inode; ++ ++ di_write_lock_parent(args->parent); ++ err = au_mvd_args(dmsg, args); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ err = au_do_mvdown(dmsg, args); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ au_cpup_attr_timesizes(args->dir); ++ au_cpup_attr_timesizes(inode); ++ if (!(args->mvdown.flags & AUFS_MVDOWN_KUPPER)) ++ au_cpup_igen(inode, au_h_iptr(inode, args->mvd_bdst)); ++ /* au_digen_dec(dentry); */ ++ ++out_parent: ++ di_write_unlock(args->parent); ++ aufs_read_unlock(dentry, AuLock_DW); ++out_inode: ++ inode_unlock(inode); ++out_dir: ++ inode_unlock(args->dir); ++out_free: ++ e = copy_to_user(uarg, &args->mvdown, sizeof(args->mvdown)); ++ if (unlikely(e)) ++ err = -EFAULT; ++ au_kfree_rcu(args); ++out: ++ AuTraceErr(err); ++ return err; ++} +diff -Nurp linux-5.4/fs/aufs/opts.c linux-5.4-aufs/fs/aufs/opts.c +--- linux-5.4/fs/aufs/opts.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/opts.c 2019-11-28 01:25:59.067925618 +0200 +@@ -0,0 +1,1867 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * mount options/flags ++ */ ++ ++#include ++#include /* a distribution requires */ ++#include ++#include "aufs.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++enum { ++ Opt_br, ++ Opt_add, Opt_del, Opt_mod, Opt_append, Opt_prepend, ++ Opt_idel, Opt_imod, ++ Opt_dirwh, Opt_rdcache, Opt_rdblk, Opt_rdhash, ++ Opt_rdblk_def, Opt_rdhash_def, ++ Opt_xino, 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_diropq_a, Opt_diropq_w, ++ Opt_warn_perm, Opt_nowarn_perm, ++ Opt_wbr_copyup, Opt_wbr_create, ++ Opt_fhsm_sec, ++ Opt_verbose, Opt_noverbose, ++ Opt_sum, Opt_nosum, Opt_wsum, ++ Opt_dirperm1, Opt_nodirperm1, ++ Opt_dirren, Opt_nodirren, ++ Opt_acl, Opt_noacl, ++ 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"}, ++ ++#ifdef CONFIG_AUFS_DIRREN ++ {Opt_dirren, "dirren"}, ++ {Opt_nodirren, "nodirren"}, ++#else ++ {Opt_ignore, "dirren"}, ++ {Opt_ignore_silent, "nodirren"}, ++#endif ++ ++#ifdef CONFIG_AUFS_FHSM ++ {Opt_fhsm_sec, "fhsm_sec=%d"}, ++#else ++ {Opt_ignore, "fhsm_sec=%d"}, ++#endif ++ ++ {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, "nodlgt"}, ++ {Opt_ignore, "clean_plink"}, ++ ++#ifdef CONFIG_AUFS_SHWH ++ {Opt_shwh, "shwh"}, ++#endif ++ {Opt_noshwh, "noshwh"}, ++ ++ {Opt_dirperm1, "dirperm1"}, ++ {Opt_nodirperm1, "nodirperm1"}, ++ ++ {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"}, ++ ++ /* generic VFS flag */ ++#ifdef CONFIG_FS_POSIX_ACL ++ {Opt_acl, "acl"}, ++ {Opt_noacl, "noacl"}, ++#else ++ {Opt_ignore, "acl"}, ++ {Opt_ignore_silent, "noacl"}, ++#endif ++ ++ /* 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, match_table_t tbl) ++{ ++ struct match_token *p; ++ ++ p = tbl; ++ while (p->pattern) { ++ if (p->token == val) ++ return p->pattern; ++ p++; ++ } ++ BUG(); ++ return "??"; ++} ++ ++static const char *au_optstr(int *val, match_table_t tbl) ++{ ++ struct match_token *p; ++ int v; ++ ++ v = *val; ++ if (!v) ++ goto out; ++ p = tbl; ++ while (p->pattern) { ++ if (p->token ++ && (v & p->token) == p->token) { ++ *val &= ~p->token; ++ return p->pattern; ++ } ++ p++; ++ } ++ ++out: ++ return NULL; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++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 brattr = { ++ /* general */ ++ {AuBrAttr_COO_REG, AUFS_BRATTR_COO_REG}, ++ {AuBrAttr_COO_ALL, AUFS_BRATTR_COO_ALL}, ++ /* 'unpin' attrib is meaningless since linux-3.18-rc1 */ ++ {AuBrAttr_UNPIN, AUFS_BRATTR_UNPIN}, ++#ifdef CONFIG_AUFS_FHSM ++ {AuBrAttr_FHSM, AUFS_BRATTR_FHSM}, ++#endif ++#ifdef CONFIG_AUFS_XATTR ++ {AuBrAttr_ICEX, AUFS_BRATTR_ICEX}, ++ {AuBrAttr_ICEX_SEC, AUFS_BRATTR_ICEX_SEC}, ++ {AuBrAttr_ICEX_SYS, AUFS_BRATTR_ICEX_SYS}, ++ {AuBrAttr_ICEX_TR, AUFS_BRATTR_ICEX_TR}, ++ {AuBrAttr_ICEX_USR, AUFS_BRATTR_ICEX_USR}, ++ {AuBrAttr_ICEX_OTH, AUFS_BRATTR_ICEX_OTH}, ++#endif ++ ++ /* ro/rr branch */ ++ {AuBrRAttr_WH, AUFS_BRRATTR_WH}, ++ ++ /* rw branch */ ++ {AuBrWAttr_MOO, AUFS_BRWATTR_MOO}, ++ {AuBrWAttr_NoLinkWH, AUFS_BRWATTR_NLWH}, ++ ++ {0, NULL} ++}; ++ ++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) { ++ if (v & AuBrAttr_CMOO_Mask) ++ attr &= ~AuBrAttr_CMOO_Mask; ++ 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 au_do_optstr_br_attr(au_br_perm_str_t *str, int perm) ++{ ++ int sz; ++ const char *p; ++ char *q; ++ ++ q = str->a; ++ *q = 0; ++ p = au_optstr(&perm, brattr); ++ if (p) { ++ sz = strlen(p); ++ memcpy(q, p, sz + 1); ++ q += sz; ++ } else ++ goto out; ++ ++ do { ++ p = au_optstr(&perm, brattr); ++ if (p) { ++ *q++ = '+'; ++ sz = strlen(p); ++ memcpy(q, p, sz + 1); ++ q += sz; ++ } ++ } while (p); ++ ++out: ++ return q - str->a; ++} ++ ++static int noinline_for_stack br_perm_val(char *perm) ++{ ++ int val, bad, sz; ++ char *p; ++ substring_t args[MAX_OPT_ARGS]; ++ au_br_perm_str_t attr; ++ ++ 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; ++ ++ val |= br_attr_val(p + 1, brattr, args); ++ ++ bad = 0; ++ switch (val & AuBrPerm_Mask) { ++ case AuBrPerm_RO: ++ case AuBrPerm_RR: ++ bad = val & AuBrWAttr_Mask; ++ val &= ~AuBrWAttr_Mask; ++ break; ++ case AuBrPerm_RW: ++ bad = val & AuBrRAttr_Mask; ++ val &= ~AuBrRAttr_Mask; ++ break; ++ } ++ ++ /* ++ * 'unpin' attrib becomes meaningless since linux-3.18-rc1, but aufs ++ * does not treat it as an error, just warning. ++ * this is a tiny guard for the user operation. ++ */ ++ if (val & AuBrAttr_UNPIN) { ++ bad |= AuBrAttr_UNPIN; ++ val &= ~AuBrAttr_UNPIN; ++ } ++ ++ if (unlikely(bad)) { ++ sz = au_do_optstr_br_attr(&attr, bad); ++ AuDebugOn(!sz); ++ pr_warn("ignored branch attribute %s\n", attr.a); ++ } ++ ++out: ++ return val; ++} ++ ++void au_optstr_br_perm(au_br_perm_str_t *str, int perm) ++{ ++ au_br_perm_str_t attr; ++ const char *p; ++ char *q; ++ int sz; ++ ++ q = str->a; ++ p = au_optstr(&perm, brperm); ++ AuDebugOn(!p || !*p); ++ sz = strlen(p); ++ memcpy(q, p, sz + 1); ++ q += sz; ++ ++ sz = au_do_optstr_br_attr(&attr, perm); ++ if (sz) { ++ *q++ = '+'; ++ memcpy(q, attr.a, sz + 1); ++ } ++ ++ AuDebugOn(strlen(str->a) >= sizeof(str->a)); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++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, 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"}, ++ ++ /* top-down regardless the parent, and then mfs */ ++ {AuWbrCreate_TDMFS, "tdmfs:%d"}, ++ {AuWbrCreate_TDMFSV, "tdmfs:%d:%d"}, ++ ++ {AuWbrCreate_MFSRR, "mfsrr:%d"}, ++ {AuWbrCreate_MFSRRV, "mfsrr:%d:%d"}, ++ {AuWbrCreate_PMFS, "pmfs"}, ++ {AuWbrCreate_PMFSV, "pmfs:%d"}, ++ {AuWbrCreate_PMFSRR, "pmfsrr:%d"}, ++ {AuWbrCreate_PMFSRRV, "pmfsrr:%d:%d"}, ++ ++ {-1, NULL} ++}; ++ ++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 (!match_u64(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: ++ case AuWbrCreate_TDMFSV: ++ case AuWbrCreate_PMFSRRV: ++ 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: ++ case AuWbrCreate_TDMFS: ++ case AuWbrCreate_PMFSRR: ++ 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, 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, 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 %pD}\n", u.xino->path, u.xino->file); ++ 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_dirperm1: ++ AuLabel(dirperm1); ++ break; ++ case Opt_nodirperm1: ++ AuLabel(nodirperm1); ++ 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_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: ++ case AuWbrCreate_TDMFS: ++ AuDbg("%llu watermark\n", ++ u.create->mfsrr_watermark); ++ break; ++ case AuWbrCreate_MFSRRV: ++ case AuWbrCreate_TDMFSV: ++ case AuWbrCreate_PMFSRRV: ++ 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; ++ case Opt_fhsm_sec: ++ AuDbg("fhsm_sec %u\n", opt->fhsm_second); ++ break; ++ case Opt_dirren: ++ AuLabel(dirren); ++ break; ++ case Opt_nodirren: ++ AuLabel(nodirren); ++ break; ++ case Opt_acl: ++ AuLabel(acl); ++ break; ++ case Opt_noacl: ++ AuLabel(noacl); ++ 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 & SB_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_sbbot(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 permission %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_sbbot(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, /*wbrtop*/0); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ ++ err = -EINVAL; ++ if (unlikely(file->f_path.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 bbot, 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); ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; 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_sbbot(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_dirperm1: ++ case Opt_nodirperm1: ++ 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_verbose: ++ case Opt_noverbose: ++ case Opt_sum: ++ case Opt_nosum: ++ case Opt_wsum: ++ case Opt_rdblk_def: ++ case Opt_rdhash_def: ++ case Opt_dirren: ++ case Opt_nodirren: ++ case Opt_acl: ++ case Opt_noacl: ++ 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_fhsm_sec: ++ if (unlikely(match_int(&a->args[0], &n) ++ || n < 0)) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ if (sysaufs_brs) { ++ opt->fhsm_second = n; ++ opt->type = token; ++ } else ++ pr_warn("ignored %s\n", opt_str); ++ err = 0; ++ 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; ++ } ++ } ++ ++ au_kfree_rcu(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: ++ case AuWbrCreate_TDMFS: ++ case AuWbrCreate_TDMFSV: ++ case AuWbrCreate_PMFSRR: ++ case AuWbrCreate_PMFSRRV: ++ 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_fhsm_sec: ++ au_fhsm_set(sbinfo, opt->fhsm_second); ++ 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_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); ++ break; ++ 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_dirperm1: ++ au_opt_set(sbinfo->si_mntflags, DIRPERM1); ++ break; ++ case Opt_nodirperm1: ++ au_opt_clr(sbinfo->si_mntflags, DIRPERM1); ++ 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, ++ /*idx_begin*/0); ++ 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; ++ ++ case Opt_dirren: ++ err = 1; ++ if (!au_opt_test(sbinfo->si_mntflags, DIRREN)) { ++ err = au_dr_opt_set(sb); ++ if (!err) ++ err = 1; ++ } ++ if (err == 1) ++ au_opt_set(sbinfo->si_mntflags, DIRREN); ++ break; ++ case Opt_nodirren: ++ err = 1; ++ if (au_opt_test(sbinfo->si_mntflags, DIRREN)) { ++ err = au_dr_opt_clr(sb, au_ftest_opts(opts->flags, ++ DR_FLUSHED)); ++ if (!err) ++ err = 1; ++ } ++ if (err == 1) ++ au_opt_clr(sbinfo->si_mntflags, DIRREN); ++ break; ++ ++ case Opt_acl: ++ sb->s_flags |= SB_POSIXACL; ++ break; ++ case Opt_noacl: ++ sb->s_flags &= ~SB_POSIXACL; ++ 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_sbbot(sb) + 1; ++ if (opt->add.bindex < 0) ++ opt->add.bindex = 0; ++ goto add; ++ /* Always goto add, not fallthrough */ ++ case Opt_prepend: ++ opt->add.bindex = 0; ++ /* fallthrough */ ++ add: /* indented label */ ++ 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; ++ ++ 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; ++ break; ++ ++ case Opt_noxino: ++ au_xino_clr(sb); ++ *opt_xino = (void *)-1; ++ break; ++ } ++ ++ return err; ++} ++ ++int au_opts_verify(struct super_block *sb, unsigned long sb_flags, ++ unsigned int pending) ++{ ++ int err, fhsm; ++ aufs_bindex_t bindex, bbot; ++ unsigned char do_plink, skip, do_free, can_no_dreval; ++ struct au_branch *br; ++ struct au_wbr *wbr; ++ struct dentry *root, *dentry; ++ 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 & SB_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_once("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_once("udba=*notify requires xino\n"); ++ ++ if (au_opt_test(sbinfo->si_mntflags, DIRPERM1)) ++ pr_warn_once("dirperm1 breaks the protection" ++ " by the permission bits on the lower branch\n"); ++ ++ err = 0; ++ fhsm = 0; ++ root = sb->s_root; ++ dir = d_inode(root); ++ do_plink = !!au_opt_test(sbinfo->si_mntflags, PLINK); ++ can_no_dreval = !!au_opt_test((sbinfo->si_mntflags | pending), ++ UDBA_NONE); ++ bbot = au_sbbot(sb); ++ for (bindex = 0; !err && bindex <= bbot; bindex++) { ++ skip = 0; ++ h_dir = au_h_iptr(dir, bindex); ++ br = au_sbr(sb, bindex); ++ ++ if ((br->br_perm & AuBrAttr_ICEX) ++ && !h_dir->i_op->listxattr) ++ br->br_perm &= ~AuBrAttr_ICEX; ++#if 0 ++ if ((br->br_perm & AuBrAttr_ICEX_SEC) ++ && (au_br_sb(br)->s_flags & SB_NOSEC)) ++ br->br_perm &= ~AuBrAttr_ICEX_SEC; ++#endif ++ ++ 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 (can_no_dreval) { ++ dentry = br->br_path.dentry; ++ spin_lock(&dentry->d_lock); ++ if (dentry->d_flags & ++ (DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE)) ++ can_no_dreval = 0; ++ spin_unlock(&dentry->d_lock); ++ } ++ ++ if (au_br_fhsm(br->br_perm)) { ++ fhsm++; ++ AuDebugOn(!br->br_fhsm); ++ } ++ ++ if (skip) ++ continue; ++ ++ hdir = au_hi(dir, bindex); ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ if (wbr) ++ wbr_wh_write_lock(wbr); ++ err = au_wh_init(br, sb); ++ if (wbr) ++ wbr_wh_write_unlock(wbr); ++ au_hn_inode_unlock(hdir); ++ ++ if (!err && do_free) { ++ au_kfree_rcu(wbr); ++ br->br_wbr = NULL; ++ } ++ } ++ ++ if (can_no_dreval) ++ au_fset_si(sbinfo, NO_DREVAL); ++ else ++ au_fclr_si(sbinfo, NO_DREVAL); ++ ++ if (fhsm >= 2) { ++ au_fset_si(sbinfo, FHSM); ++ for (bindex = bbot; bindex >= 0; bindex--) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm)) { ++ au_fhsm_set_bottom(sb, bindex); ++ break; ++ } ++ } ++ } else { ++ au_fclr_si(sbinfo, FHSM); ++ au_fhsm_set_bottom(sb, -1); ++ } ++ ++ return err; ++} ++ ++int au_opts_mount(struct super_block *sb, struct au_opts *opts) ++{ ++ int err; ++ unsigned int tmp; ++ aufs_bindex_t bindex, bbot; ++ struct au_opt *opt; ++ struct au_opt_xino *opt_xino, xino; ++ struct au_sbinfo *sbinfo; ++ struct au_branch *br; ++ struct inode *dir; ++ ++ 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; ++ ++ bbot = au_sbbot(sb); ++ if (unlikely(bbot < 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; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; 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)) { ++ dir = d_inode(sb->s_root); ++ 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; ++ unsigned char no_dreval; ++ struct inode *dir; ++ struct au_opt_xino *opt_xino; ++ struct au_opt *opt; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ err = au_dr_opt_flush(sb); ++ if (unlikely(err)) ++ goto out; ++ au_fset_opts(opts->flags, DR_FLUSHED); ++ ++ dir = d_inode(sb->s_root); ++ sbinfo = au_sbi(sb); ++ 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 */ ++ ++ no_dreval = !!au_ftest_si(sbinfo, NO_DREVAL); ++ rerr = au_opts_verify(sb, opts->sb_flags, /*pending*/0); ++ if (unlikely(rerr && !err)) ++ err = rerr; ++ ++ if (no_dreval != !!au_ftest_si(sbinfo, NO_DREVAL)) ++ au_fset_opts(opts->flags, REFRESH_IDOP); ++ ++ 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_ftest_opts(opts->flags, REFRESH_IDOP) ++ )) ++ au_fset_opts(opts->flags, REFRESH); ++ ++ AuDbg("status 0x%x\n", opts->flags); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++unsigned int au_opt_udba(struct super_block *sb) ++{ ++ return au_mntflags(sb) & AuOptMask_UDBA; ++} +diff -Nurp linux-5.4/fs/aufs/opts.h linux-5.4-aufs/fs/aufs/opts.h +--- linux-5.4/fs/aufs/opts.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/opts.h 2019-11-28 01:25:59.067925618 +0200 +@@ -0,0 +1,212 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * mount options/flags ++ */ ++ ++#ifndef __AUFS_OPTS_H__ ++#define __AUFS_OPTS_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++struct file; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* 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) /* ignore the lower dir's perm ++ bits */ ++#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) /* print the cause of error */ ++#define AuOpt_DIO (1 << 14) /* direct io */ ++#define AuOpt_DIRREN (1 << 15) /* directory rename */ ++ ++#ifndef CONFIG_AUFS_HNOTIFY ++#undef AuOpt_UDBA_HNOTIFY ++#define AuOpt_UDBA_HNOTIFY 0 ++#endif ++#ifndef CONFIG_AUFS_DIRREN ++#undef AuOpt_DIRREN ++#define AuOpt_DIRREN 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_TDMFS, /* top down regardless parent and mfs */ ++ AuWbrCreate_TDMFSV, /* top down regardless parent and mfs */ ++ AuWbrCreate_PMFS, /* parent and mfs */ ++ AuWbrCreate_PMFSV, /* parent and mfs with seconds */ ++ AuWbrCreate_PMFSRR, /* parent, mfs and round-robin */ ++ AuWbrCreate_PMFSRRV, /* plus 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; ++ unsigned int fhsm_second; ++ }; ++}; ++ ++/* opts flags */ ++#define AuOpts_REMOUNT 1 ++#define AuOpts_REFRESH (1 << 1) ++#define AuOpts_TRUNC_XIB (1 << 2) ++#define AuOpts_REFRESH_DYAOP (1 << 3) ++#define AuOpts_REFRESH_IDOP (1 << 4) ++#define AuOpts_DR_FLUSHED (1 << 5) ++#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) ++ ++#ifndef CONFIG_AUFS_DIRREN ++#undef AuOpts_DR_FLUSHED ++#define AuOpts_DR_FLUSHED 0 ++#endif ++ ++struct au_opts { ++ struct au_opt *opt; ++ int max_opt; ++ ++ unsigned int given_udba; ++ unsigned int flags; ++ unsigned long sb_flags; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* opts.c */ ++void au_optstr_br_perm(au_br_perm_str_t *str, int perm); ++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); ++struct super_block; ++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 -Nurp linux-5.4/fs/aufs/plink.c linux-5.4-aufs/fs/aufs/plink.c +--- linux-5.4/fs/aufs/plink.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/plink.c 2019-11-28 01:25:59.067925618 +0200 +@@ -0,0 +1,503 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * 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 task_struct *parent, *prev; ++ 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 */ ++ prev = NULL; ++ parent = current; ++ ppid = 0; ++ rcu_read_lock(); ++ while (1) { ++ parent = rcu_dereference(parent->real_parent); ++ if (parent == prev) ++ break; ++ ppid = task_pid_vnr(parent); ++ if (pid == ppid) { ++ rcu_read_unlock(); ++ goto out; ++ } ++ prev = parent; ++ } ++ rcu_read_unlock(); ++ ++ 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; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_DEBUG ++void au_plink_list(struct super_block *sb) ++{ ++ int i; ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_icntnr *icntnr; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); ++ ++ for (i = 0; i < AuPlink_NHASH; i++) { ++ hbl = sbinfo->si_plink + i; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(icntnr, pos, hbl, plink) ++ AuDbg("%lu\n", icntnr->vfs_inode.i_ino); ++ hlist_bl_unlock(hbl); ++ } ++} ++#endif ++ ++/* is the inode pseudo-linked? */ ++int au_plink_test(struct inode *inode) ++{ ++ int found, i; ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_icntnr *icntnr; ++ ++ 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; ++ i = au_plink_hash(inode->i_ino); ++ hbl = sbinfo->si_plink + i; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(icntnr, pos, hbl, plink) ++ if (&icntnr->vfs_inode == inode) { ++ found = 1; ++ break; ++ } ++ hlist_bl_unlock(hbl); ++ 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 inode *h_inode; ++ ++ h_inode = d_inode(h_parent); ++ inode_lock_shared_nested(h_inode, AuLsc_I_CHILD2); ++ h_dentry = vfsub_lkup_one(tgtname, h_parent); ++ inode_unlock_shared(h_inode); ++ 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; ++ 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; ++ 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 = au_br_mnt(br) ++ }; ++ struct inode *h_dir, *delegated; ++ ++ h_dir = d_inode(h_parent); ++ inode_lock_nested(h_dir, 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 (d_is_positive(h_path.dentry) ++ && d_inode(h_path.dentry) != d_inode(h_dentry)) { ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, &h_path, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ dput(h_path.dentry); ++ h_path.dentry = NULL; ++ if (!err) ++ goto again; ++ } ++ if (!err && d_is_negative(h_path.dentry)) { ++ delegated = NULL; ++ err = vfsub_link(h_dentry, h_dir, &h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ } ++ dput(h_path.dentry); ++ ++out: ++ inode_unlock(h_dir); ++ 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; ++ 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; ++ 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; ++} ++ ++/* ++ * 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 hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_icntnr *icntnr; ++ int found, err, cnt, i; ++ ++ sb = inode->i_sb; ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); ++ ++ found = au_plink_test(inode); ++ if (found) ++ return; ++ ++ i = au_plink_hash(inode->i_ino); ++ hbl = sbinfo->si_plink + i; ++ au_igrab(inode); ++ ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(icntnr, pos, hbl, plink) { ++ if (&icntnr->vfs_inode == inode) { ++ found = 1; ++ break; ++ } ++ } ++ if (!found) { ++ icntnr = container_of(inode, struct au_icntnr, vfs_inode); ++ hlist_bl_add_head(&icntnr->plink, hbl); ++ } ++ hlist_bl_unlock(hbl); ++ if (!found) { ++ cnt = au_hbl_count(hbl); ++#define msg "unexpectedly unbalanced or too many pseudo-links" ++ if (cnt > AUFS_PLINK_WARN) ++ AuWarn1(msg ", %d\n", cnt); ++#undef msg ++ err = whplink(h_dentry, inode, bindex, au_sbr(sb, bindex)); ++ if (unlikely(err)) { ++ pr_warn("err %d, damaged pseudo link.\n", err); ++ au_hbl_del(&icntnr->plink, hbl); ++ iput(&icntnr->vfs_inode); ++ } ++ } else ++ iput(&icntnr->vfs_inode); ++} ++ ++/* free all plinks */ ++void au_plink_put(struct super_block *sb, int verbose) ++{ ++ int i, warned; ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos, *tmp; ++ struct au_icntnr *icntnr; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); ++ ++ /* no spin_lock since sbinfo is write-locked */ ++ warned = 0; ++ for (i = 0; i < AuPlink_NHASH; i++) { ++ hbl = sbinfo->si_plink + i; ++ if (!warned && verbose && !hlist_bl_empty(hbl)) { ++ pr_warn("pseudo-link is not flushed"); ++ warned = 1; ++ } ++ hlist_bl_for_each_entry_safe(icntnr, pos, tmp, hbl, plink) ++ iput(&icntnr->vfs_inode); ++ INIT_HLIST_BL_HEAD(hbl); ++ } ++} ++ ++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); ++} ++ ++static int au_plink_do_half_refresh(struct inode *inode, aufs_bindex_t br_id) ++{ ++ int do_put; ++ aufs_bindex_t btop, bbot, bindex; ++ ++ do_put = 0; ++ btop = au_ibtop(inode); ++ bbot = au_ibbot(inode); ++ if (btop >= 0) { ++ for (bindex = btop; bindex <= bbot; 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; ++ } ++ if (do_put) ++ for (bindex = btop; bindex <= bbot; bindex++) ++ if (au_h_iptr(inode, bindex)) { ++ do_put = 0; ++ break; ++ } ++ } else ++ do_put = 1; ++ ++ return do_put; ++} ++ ++/* 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 hlist_bl_head *hbl; ++ struct hlist_bl_node *pos, *tmp; ++ struct au_icntnr *icntnr; ++ struct inode *inode; ++ int i, do_put; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); ++ ++ /* no bit_lock since sbinfo is write-locked */ ++ for (i = 0; i < AuPlink_NHASH; i++) { ++ hbl = sbinfo->si_plink + i; ++ hlist_bl_for_each_entry_safe(icntnr, pos, tmp, hbl, plink) { ++ inode = au_igrab(&icntnr->vfs_inode); ++ ii_write_lock_child(inode); ++ do_put = au_plink_do_half_refresh(inode, br_id); ++ if (do_put) { ++ hlist_bl_del(&icntnr->plink); ++ iput(inode); ++ } ++ ii_write_unlock(inode); ++ iput(inode); ++ } ++ } ++} +diff -Nurp linux-5.4/fs/aufs/poll.c linux-5.4-aufs/fs/aufs/poll.c +--- linux-5.4/fs/aufs/poll.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/poll.c 2019-11-28 01:25:59.067925618 +0200 +@@ -0,0 +1,38 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * poll operation ++ * There is only one filesystem which implements ->poll operation, currently. ++ */ ++ ++#include "aufs.h" ++ ++__poll_t aufs_poll(struct file *file, struct poll_table_struct *pt) ++{ ++ __poll_t mask; ++ struct file *h_file; ++ struct super_block *sb; ++ ++ /* We should pretend an error happened. */ ++ mask = EPOLLERR /* | EPOLLIN | EPOLLOUT */; ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/0, /*lsc*/0); ++ if (IS_ERR(h_file)) { ++ AuDbg("h_file %ld\n", PTR_ERR(h_file)); ++ goto out; ++ } ++ ++ mask = vfs_poll(h_file, pt); ++ fput(h_file); /* instead of au_read_post() */ ++ ++out: ++ si_read_unlock(sb); ++ if (mask & EPOLLERR) ++ AuDbg("mask 0x%x\n", mask); ++ return mask; ++} +diff -Nurp linux-5.4/fs/aufs/posix_acl.c linux-5.4-aufs/fs/aufs/posix_acl.c +--- linux-5.4/fs/aufs/posix_acl.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/posix_acl.c 2019-11-28 01:25:59.067925618 +0200 +@@ -0,0 +1,92 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2014-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * posix acl operations ++ */ ++ ++#include ++#include "aufs.h" ++ ++struct posix_acl *aufs_get_acl(struct inode *inode, int type) ++{ ++ struct posix_acl *acl; ++ int err; ++ aufs_bindex_t bindex; ++ struct inode *h_inode; ++ struct super_block *sb; ++ ++ acl = NULL; ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ ii_read_lock_child(inode); ++ if (!(sb->s_flags & SB_POSIXACL)) ++ goto out; ++ ++ bindex = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, bindex); ++ if (unlikely(!h_inode ++ || ((h_inode->i_mode & S_IFMT) ++ != (inode->i_mode & S_IFMT)))) { ++ err = au_busy_or_stale(); ++ acl = ERR_PTR(err); ++ goto out; ++ } ++ ++ /* always topmost only */ ++ acl = get_acl(h_inode, type); ++ if (IS_ERR(acl)) ++ forget_cached_acl(inode, type); ++ else ++ set_cached_acl(inode, type, acl); ++ ++out: ++ ii_read_unlock(inode); ++ si_read_unlock(sb); ++ ++ AuTraceErrPtr(acl); ++ return acl; ++} ++ ++int aufs_set_acl(struct inode *inode, struct posix_acl *acl, int type) ++{ ++ int err; ++ ssize_t ssz; ++ struct dentry *dentry; ++ struct au_sxattr arg = { ++ .type = AU_ACL_SET, ++ .u.acl_set = { ++ .acl = acl, ++ .type = type ++ }, ++ }; ++ ++ IMustLock(inode); ++ ++ if (inode->i_ino == AUFS_ROOT_INO) ++ dentry = dget(inode->i_sb->s_root); ++ else { ++ dentry = d_find_alias(inode); ++ if (!dentry) ++ dentry = d_find_any_alias(inode); ++ if (!dentry) { ++ pr_warn("cannot handle this inode, " ++ "please report to aufs-users ML\n"); ++ err = -ENOENT; ++ goto out; ++ } ++ } ++ ++ ssz = au_sxattr(dentry, inode, &arg); ++ /* forget even it if succeeds since the branch might set differently */ ++ forget_cached_acl(inode, type); ++ dput(dentry); ++ err = ssz; ++ if (ssz >= 0) ++ err = 0; ++ ++out: ++ return err; ++} +diff -Nurp linux-5.4/fs/aufs/procfs.c linux-5.4-aufs/fs/aufs/procfs.c +--- linux-5.4/fs/aufs/procfs.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/procfs.c 2019-11-28 01:25:59.067925618 +0200 +@@ -0,0 +1,158 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2010-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * 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; ++ struct hlist_bl_node *pos; ++ ++ err = -EBUSY; ++ if (unlikely(file->private_data)) ++ goto out; ++ ++ sb = NULL; ++ /* don't use au_sbilist_lock() here */ ++ hlist_bl_lock(&au_sbilist); ++ hlist_bl_for_each_entry(sbinfo, pos, &au_sbilist, si_list) ++ if (id == sysaufs_si_id(sbinfo)) { ++ if (kobject_get_unless_zero(&sbinfo->si_kobj)) ++ sb = sbinfo->si_sb; ++ break; ++ } ++ hlist_bl_unlock(&au_sbilist); ++ ++ 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 | 0200, ++ 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 -Nurp linux-5.4/fs/aufs/rdu.c linux-5.4-aufs/fs/aufs/rdu.c +--- linux-5.4/fs/aufs/rdu.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/rdu.c 2019-11-28 01:25:59.067925618 +0200 +@@ -0,0 +1,371 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * 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 dir_context ctx; ++ struct aufs_rdu *rdu; ++ union au_rdu_ent_ul ent; ++ unsigned long end; ++ ++ struct super_block *sb; ++ int err; ++}; ++ ++static int au_rdu_fill(struct dir_context *ctx, const char *name, int nlen, ++ loff_t offset, u64 h_ino, unsigned int d_type) ++{ ++ int err, len; ++ struct au_rdu_arg *arg = container_of(ctx, struct au_rdu_arg, ctx); ++ 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_iterate_dir(h_file, &arg->ctx); ++ 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 bbot; ++ struct au_rdu_arg arg = { ++ .ctx = { ++ .actor = au_rdu_fill ++ } ++ }; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct file *h_file; ++ struct au_rdu_cookie *cookie = &rdu->cookie; ++ ++ /* VERIFY_WRITE */ ++ err = !access_ok(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->iterate && !file->f_op->iterate_shared)) ++ goto out; ++ ++ err = security_file_permission(file, MAY_READ); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out; ++ ++ dentry = file->f_path.dentry; ++ inode = d_inode(dentry); ++ inode_lock_shared(inode); ++ ++ 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); ++ } ++ bbot = au_fbtop(file); ++ if (cookie->bindex < bbot) ++ cookie->bindex = bbot; ++ bbot = au_fbbot_dir(file); ++ /* AuDbg("b%d, b%d\n", cookie->bindex, bbot); */ ++ for (; !err && cookie->bindex <= bbot; ++ 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_ibtop(inode))); ++ ii_read_unlock(inode); ++ ++out_unlock: ++ fi_read_unlock(file); ++out_si: ++ si_read_unlock(arg.sb); ++out_mtx: ++ inode_unlock_shared(inode); ++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_path.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) ++ /* VERIFY_WRITE */ ++ err = !access_ok(&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 -Nurp linux-5.4/fs/aufs/rwsem.h linux-5.4-aufs/fs/aufs/rwsem.h +--- linux-5.4/fs/aufs/rwsem.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/rwsem.h 2019-11-28 01:25:59.067925618 +0200 +@@ -0,0 +1,60 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * simple read-write semaphore wrappers ++ */ ++ ++#ifndef __AUFS_RWSEM_H__ ++#define __AUFS_RWSEM_H__ ++ ++#ifdef __KERNEL__ ++ ++#include "debug.h" ++ ++/* in the future, the name 'au_rwsem' will be totally gone */ ++#define au_rwsem rw_semaphore ++ ++/* to debug easier, do not make them inlined functions */ ++#define AuRwMustNoWaiters(rw) AuDebugOn(rwsem_is_contended(rw)) ++/* rwsem_is_locked() is unusable */ ++#define AuRwMustReadLock(rw) AuDebugOn(!lockdep_recursing(current) \ ++ && debug_locks \ ++ && !lockdep_is_held_type(rw, 1)) ++#define AuRwMustWriteLock(rw) AuDebugOn(!lockdep_recursing(current) \ ++ && debug_locks \ ++ && !lockdep_is_held_type(rw, 0)) ++#define AuRwMustAnyLock(rw) AuDebugOn(!lockdep_recursing(current) \ ++ && debug_locks \ ++ && !lockdep_is_held(rw)) ++#define AuRwDestroy(rw) AuDebugOn(!lockdep_recursing(current) \ ++ && debug_locks \ ++ && lockdep_is_held(rw)) ++ ++#define au_rw_init(rw) init_rwsem(rw) ++ ++#define au_rw_init_wlock(rw) do { \ ++ au_rw_init(rw); \ ++ down_write(rw); \ ++ } while (0) ++ ++#define au_rw_init_wlock_nested(rw, lsc) do { \ ++ au_rw_init(rw); \ ++ down_write_nested(rw, lsc); \ ++ } while (0) ++ ++#define au_rw_read_lock(rw) down_read(rw) ++#define au_rw_read_lock_nested(rw, lsc) down_read_nested(rw, lsc) ++#define au_rw_read_unlock(rw) up_read(rw) ++#define au_rw_dgrade_lock(rw) downgrade_write(rw) ++#define au_rw_write_lock(rw) down_write(rw) ++#define au_rw_write_lock_nested(rw, lsc) down_write_nested(rw, lsc) ++#define au_rw_write_unlock(rw) up_write(rw) ++/* why is not _nested version defined? */ ++#define au_rw_read_trylock(rw) down_read_trylock(rw) ++#define au_rw_write_trylock(rw) down_write_trylock(rw) ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_RWSEM_H__ */ +diff -Nurp linux-5.4/fs/aufs/sbinfo.c linux-5.4-aufs/fs/aufs/sbinfo.c +--- linux-5.4/fs/aufs/sbinfo.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/sbinfo.c 2019-11-28 01:25:59.067925618 +0200 +@@ -0,0 +1,301 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * superblock private data ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* ++ * they are necessary regardless sysfs is disabled. ++ */ ++void au_si_free(struct kobject *kobj) ++{ ++ int i; ++ struct au_sbinfo *sbinfo; ++ char *locked __maybe_unused; /* debug only */ ++ ++ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); ++ for (i = 0; i < AuPlink_NHASH; i++) ++ AuDebugOn(!hlist_bl_empty(sbinfo->si_plink + i)); ++ AuDebugOn(atomic_read(&sbinfo->si_nowait.nw_len)); ++ ++ AuLCntZero(au_lcnt_read(&sbinfo->si_ninodes, /*do_rev*/0)); ++ au_lcnt_fin(&sbinfo->si_ninodes, /*do_sync*/0); ++ AuLCntZero(au_lcnt_read(&sbinfo->si_nfiles, /*do_rev*/0)); ++ au_lcnt_fin(&sbinfo->si_nfiles, /*do_sync*/0); ++ ++ dbgaufs_si_fin(sbinfo); ++ au_rw_write_lock(&sbinfo->si_rwsem); ++ au_br_free(sbinfo); ++ au_rw_write_unlock(&sbinfo->si_rwsem); ++ ++ au_kfree_try_rcu(sbinfo->si_branch); ++ mutex_destroy(&sbinfo->si_xib_mtx); ++ AuRwDestroy(&sbinfo->si_rwsem); ++ ++ au_lcnt_wait_for_fin(&sbinfo->si_ninodes); ++ /* si_nfiles is waited too */ ++ au_kfree_rcu(sbinfo); ++} ++ ++int au_si_alloc(struct super_block *sb) ++{ ++ int err, i; ++ struct au_sbinfo *sbinfo; ++ ++ err = -ENOMEM; ++ sbinfo = kzalloc(sizeof(*sbinfo), GFP_NOFS); ++ if (unlikely(!sbinfo)) ++ goto out; ++ ++ /* will be reallocated separately */ ++ sbinfo->si_branch = kzalloc(sizeof(*sbinfo->si_branch), GFP_NOFS); ++ if (unlikely(!sbinfo->si_branch)) ++ goto out_sbinfo; ++ ++ err = sysaufs_si_init(sbinfo); ++ if (!err) { ++ dbgaufs_si_null(sbinfo); ++ err = dbgaufs_si_init(sbinfo); ++ if (unlikely(err)) ++ kobject_put(&sbinfo->si_kobj); ++ } ++ if (unlikely(err)) ++ goto out_br; ++ ++ au_nwt_init(&sbinfo->si_nowait); ++ au_rw_init_wlock(&sbinfo->si_rwsem); ++ ++ au_lcnt_init(&sbinfo->si_ninodes, /*release*/NULL); ++ au_lcnt_init(&sbinfo->si_nfiles, /*release*/NULL); ++ ++ sbinfo->si_bbot = -1; ++ sbinfo->si_last_br_id = AUFS_BRANCH_MAX / 2; ++ ++ 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; ++ ++ au_fhsm_init(sbinfo); ++ ++ sbinfo->si_mntflags = au_opts_plink(AuOpt_Def); ++ ++ sbinfo->si_xino_jiffy = jiffies; ++ sbinfo->si_xino_expire ++ = msecs_to_jiffies(AUFS_XINO_DEF_SEC * MSEC_PER_SEC); ++ mutex_init(&sbinfo->si_xib_mtx); ++ /* leave si_xib_last_pindex and si_xib_next_bit */ ++ ++ INIT_HLIST_BL_HEAD(&sbinfo->si_aopen); ++ ++ 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; ++ ++ for (i = 0; i < AuPlink_NHASH; i++) ++ INIT_HLIST_BL_HEAD(sbinfo->si_plink + i); ++ init_waitqueue_head(&sbinfo->si_plink_wq); ++ spin_lock_init(&sbinfo->si_plink_maint_lock); ++ ++ INIT_HLIST_BL_HEAD(&sbinfo->si_files); ++ ++ /* with getattr by default */ ++ sbinfo->si_iop_array = aufs_iop; ++ ++ /* leave other members for sysaufs and si_mnt. */ ++ sbinfo->si_sb = sb; ++ sb->s_fs_info = sbinfo; ++ si_pid_set(sb); ++ return 0; /* success */ ++ ++out_br: ++ au_kfree_try_rcu(sbinfo->si_branch); ++out_sbinfo: ++ au_kfree_rcu(sbinfo); ++out: ++ return err; ++} ++ ++int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr, int may_shrink) ++{ ++ int err, sz; ++ struct au_branch **brp; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ err = -ENOMEM; ++ sz = sizeof(*brp) * (sbinfo->si_bbot + 1); ++ if (unlikely(!sz)) ++ sz = sizeof(*brp); ++ brp = au_kzrealloc(sbinfo->si_branch, sz, sizeof(*brp) * nbr, GFP_NOFS, ++ may_shrink); ++ if (brp) { ++ sbinfo->si_branch = brp; ++ err = 0; ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++unsigned int au_sigen_inc(struct super_block *sb) ++{ ++ unsigned int gen; ++ struct inode *inode; ++ ++ SiMustWriteLock(sb); ++ ++ gen = ++au_sbi(sb)->si_generation; ++ au_update_digen(sb->s_root); ++ inode = d_inode(sb->s_root); ++ au_update_iigen(inode, /*half*/0); ++ inode_inc_iversion(inode); ++ 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)); ++ if (!au_opt_test(au_mntflags(sb), UDBA_NONE)) ++ AuDebugOn(!err && au_dbrange_test(dentry)); ++ else if (!err) ++ 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, DIRS)); ++ ++ 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); ++} +diff -Nurp linux-5.4/fs/aufs/super.c linux-5.4-aufs/fs/aufs/super.c +--- linux-5.4/fs/aufs/super.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/super.c 2019-11-28 01:25:59.067925618 +0200 +@@ -0,0 +1,1034 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * mount and super_block operations ++ */ ++ ++#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); ++ inode_set_iversion(&c->vfs_inode, 1); /* sigen(sb); */ ++ c->iinfo.ii_hinode = NULL; ++ return &c->vfs_inode; ++ } ++ return NULL; ++} ++ ++static void aufs_destroy_inode(struct inode *inode) ++{ ++ if (!au_is_bad_inode(inode)) ++ au_iinfo_fin(inode); ++} ++ ++static void aufs_free_inode(struct inode *inode) ++{ ++ au_cache_free_icntnr(container_of(inode, struct au_icntnr, vfs_inode)); ++} ++ ++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_inc_iversion(inode); ++ 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, bbot; ++ struct path path; ++ struct au_hdentry *hdp; ++ struct au_branch *br; ++ au_br_perm_str_t perm; ++ ++ err = 0; ++ bbot = au_sbbot(sb); ++ bindex = 0; ++ hdp = au_hdentry(au_di(sb->s_root), bindex); ++ for (; !err && bindex <= bbot; bindex++, hdp++) { ++ br = au_sbr(sb, bindex); ++ path.mnt = au_br_mnt(br); ++ path.dentry = hdp->hd_dentry; ++ err = au_seq_path(seq, &path); ++ if (!err) { ++ au_optstr_br_perm(&perm, br->br_perm); ++ seq_printf(seq, "=%s", perm.a); ++ if (bindex != bbot) ++ seq_putc(seq, ':'); ++ } ++ } ++ if (unlikely(err || seq_has_overflowed(seq))) ++ err = -E2BIG; ++ ++ return err; ++} ++ ++static void au_gen_fmt(char *fmt, int len __maybe_unused, const char *pat, ++ const char *append) ++{ ++ char *p; ++ ++ p = fmt; ++ while (*pat != ':') ++ *p++ = *pat++; ++ *p++ = *pat++; ++ strcpy(p, append); ++ AuDebugOn(strlen(fmt) >= len); ++} ++ ++static void au_show_wbr_create(struct seq_file *m, int v, ++ struct au_sbinfo *sbinfo) ++{ ++ const char *pat; ++ char fmt[32]; ++ struct au_wbr_mfs *mfs; ++ ++ AuRwMustAnyLock(&sbinfo->si_rwsem); ++ ++ seq_puts(m, ",create="); ++ pat = au_optstr_wbr_create(v); ++ mfs = &sbinfo->si_wbr_mfs; ++ switch (v) { ++ case AuWbrCreate_TDP: ++ case AuWbrCreate_RR: ++ case AuWbrCreate_MFS: ++ case AuWbrCreate_PMFS: ++ seq_puts(m, pat); ++ break; ++ case AuWbrCreate_MFSRR: ++ case AuWbrCreate_TDMFS: ++ case AuWbrCreate_PMFSRR: ++ au_gen_fmt(fmt, sizeof(fmt), pat, "%llu"); ++ seq_printf(m, fmt, mfs->mfsrr_watermark); ++ break; ++ case AuWbrCreate_MFSV: ++ case AuWbrCreate_PMFSV: ++ au_gen_fmt(fmt, sizeof(fmt), pat, "%lu"); ++ seq_printf(m, fmt, ++ jiffies_to_msecs(mfs->mfs_expire) ++ / MSEC_PER_SEC); ++ break; ++ case AuWbrCreate_MFSRRV: ++ case AuWbrCreate_TDMFSV: ++ case AuWbrCreate_PMFSRRV: ++ au_gen_fmt(fmt, sizeof(fmt), pat, "%llu:%lu"); ++ seq_printf(m, fmt, mfs->mfsrr_watermark, ++ jiffies_to_msecs(mfs->mfs_expire) / MSEC_PER_SEC); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++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_branch *br; ++ ++ 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; ++ bindex = au_xi_root(sb, f->f_path.dentry); ++ if (bindex >= 0) { ++ br = au_sbr_sb(sb, bindex); ++ h_root = au_br_dentry(br); ++ } ++ ++ d = f->f_path.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) ++ ++ sb = dentry->d_sb; ++ if (sb->s_flags & SB_POSIXACL) ++ seq_puts(m, ",acl"); ++#if 0 ++ if (sb->s_flags & SB_I_VERSION) ++ seq_puts(m, ",i_version"); ++#endif ++ ++ /* lock free root dinfo */ ++ 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); ++ ++ 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); ++ ++ au_fhsm_show(m, sbinfo); ++ ++ AuBool(DIRREN, dirren); ++ 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 bbot, 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; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; 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 bbot, bindex; ++ struct au_branch *br; ++ struct super_block *h_sb; ++ ++ err = 0; ++ si_noflush_read_lock(sb); ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!au_br_writable(br->br_perm)) ++ continue; ++ ++ h_sb = au_sbr_sb(sb, bindex); ++ e = vfsub_sync_filesystem(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) ++ kobject_put(&sbinfo->si_kobj); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, ++ struct super_block *sb, void *arg) ++{ ++ void *array; ++ unsigned long long n, sz; ++ ++ 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; ++ } ++ ++ sz = sizeof(array) * *hint; ++ array = kzalloc(sz, GFP_NOFS); ++ if (unlikely(!array)) ++ array = vzalloc(sz); ++ if (unlikely(!array)) { ++ array = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ ++ n = cb(sb, array, *hint, arg); ++ AuDebugOn(n > *hint); ++ ++out: ++ *hint = n; ++ return array; ++} ++ ++static unsigned long long au_iarray_cb(struct super_block *sb, 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(&sb->s_inode_list_lock); ++ list_for_each_entry(inode, head, i_sb_list) { ++ if (!au_is_bad_inode(inode) ++ && au_ii(inode)->ii_btop >= 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(&sb->s_inode_list_lock); ++ ++ return n; ++} ++ ++struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max) ++{ ++ struct au_sbinfo *sbi; ++ ++ sbi = au_sbi(sb); ++ *max = au_lcnt_read(&sbi->si_ninodes, /*do_rev*/1); ++ return au_array_alloc(max, au_iarray_cb, sb, &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]); ++ kvfree(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(d_inode(dentry), 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, unsigned int do_idop) ++{ ++ int err; ++ struct dentry *parent; ++ ++ err = 0; ++ parent = dget_parent(dentry); ++ if (!au_digen_test(parent, sigen) && au_digen_test(dentry, sigen)) { ++ if (d_really_is_positive(dentry)) { ++ if (!d_is_dir(dentry)) ++ 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); ++ ++ if (!err) { ++ if (do_idop) ++ au_refresh_dop(dentry, /*force_reval*/0); ++ } else ++ au_refresh_dop(dentry, /*force_reval*/1); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_refresh_d(struct super_block *sb, unsigned int do_idop) ++{ ++ 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(d_inode(root), /*isdir*/1); ++ ++ if (do_idop) ++ au_refresh_dop(root, /*force_reval*/0); ++ ++ 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, ++ do_idop); ++ 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, unsigned int do_idop) ++{ ++ 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 (unlikely(!inode)) ++ break; ++ ++ e = 0; ++ ii_write_lock_child(inode); ++ if (au_iigen(inode, NULL) != sigen) { ++ e = au_refresh_hinode_self(inode); ++ if (unlikely(e)) { ++ au_refresh_iop(inode, /*force_getattr*/1); ++ pr_err("error %d, i%lu\n", e, inode->i_ino); ++ if (!err) ++ err = e; ++ /* go on even if err */ ++ } ++ } ++ if (!e && do_idop) ++ au_refresh_iop(inode, /*force_getattr*/0); ++ ii_write_unlock(inode); ++ } ++ ++ au_iarray_free(array, max); ++ ++out: ++ return err; ++} ++ ++static void au_remount_refresh(struct super_block *sb, unsigned int do_idop) ++{ ++ int err, e; ++ unsigned int udba; ++ aufs_bindex_t bindex, bbot; ++ struct dentry *root; ++ struct inode *inode; ++ struct au_branch *br; ++ struct au_sbinfo *sbi; ++ ++ au_sigen_inc(sb); ++ sbi = au_sbi(sb); ++ au_fclr_si(sbi, FAILED_REFRESH_DIR); ++ ++ root = sb->s_root; ++ DiMustNoWaiters(root); ++ inode = d_inode(root); ++ IiMustNoWaiters(inode); ++ ++ udba = au_opt_udba(sb); ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; 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)); ++ ++ if (do_idop) { ++ if (au_ftest_si(sbi, NO_DREVAL)) { ++ AuDebugOn(sb->s_d_op == &aufs_dop_noreval); ++ sb->s_d_op = &aufs_dop_noreval; ++ AuDebugOn(sbi->si_iop_array == aufs_iop_nogetattr); ++ sbi->si_iop_array = aufs_iop_nogetattr; ++ } else { ++ AuDebugOn(sb->s_d_op == &aufs_dop); ++ sb->s_d_op = &aufs_dop; ++ AuDebugOn(sbi->si_iop_array == aufs_iop); ++ sbi->si_iop_array = aufs_iop; ++ } ++ pr_info("reset to %ps and %ps\n", ++ sb->s_d_op, sbi->si_iop_array); ++ } ++ ++ di_write_unlock(root); ++ err = au_refresh_d(sb, do_idop); ++ e = au_refresh_i(sb, do_idop); ++ 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 = { ++ .opt = NULL ++ }; ++ 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; ++ 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 = d_inode(root); ++ inode_lock(inode); ++ 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, au_ftest_opts(opts.flags, REFRESH_IDOP)); ++ ++ if (au_ftest_opts(opts.flags, REFRESH_DYAOP)) { ++ mntflags = au_mntflags(sb); ++ do_dx = !!au_opt_test(mntflags, DIO); ++ au_dy_arefresh(do_dx); ++ } ++ ++ au_fhsm_wrote_all(sb, /*force*/1); /* ?? */ ++ aufs_write_unlock(root); ++ ++out_mtx: ++ inode_unlock(inode); ++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, ++ .free_inode = aufs_free_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_iop + AuIop_DIR; /* with getattr by default */ ++ 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 = { ++ .opt = NULL ++ }; ++ struct au_sbinfo *sbinfo; ++ 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; ++ 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; ++ sbinfo = au_sbi(sb); ++ ++ /* all timestamps always follow the ones on the branch */ ++ sb->s_flags |= SB_NOATIME | SB_NODIRATIME; ++ sb->s_flags |= SB_I_VERSION; /* do we really need this? */ ++ sb->s_op = &aufs_sop; ++ sb->s_d_op = &aufs_dop; ++ sb->s_magic = AUFS_SUPER_MAGIC; ++ sb->s_maxbytes = 0; ++ sb->s_stack_depth = 1; ++ au_export_init(sb); ++ au_xattr_init(sb); ++ ++ err = alloc_root(sb); ++ if (unlikely(err)) { ++ si_write_unlock(sb); ++ goto out_info; ++ } ++ root = sb->s_root; ++ inode = d_inode(root); ++ ++ /* ++ * 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. */ ++ inode_lock(inode); ++ aufs_write_lock(root); ++ err = au_opts_mount(sb, &opts); ++ au_opts_free(&opts); ++ if (!err && au_ftest_si(sbinfo, NO_DREVAL)) { ++ sb->s_d_op = &aufs_dop_noreval; ++ pr_info("%ps\n", sb->s_d_op); ++ au_refresh_dop(root, /*force_reval*/0); ++ sbinfo->si_iop_array = aufs_iop_nogetattr; ++ au_refresh_iop(inode, /*force_getattr*/0); ++ } ++ aufs_write_unlock(root); ++ inode_unlock(inode); ++ if (!err) ++ goto out_opts; /* success */ ++ ++out_root: ++ dput(root); ++ sb->s_root = NULL; ++out_info: ++ kobject_put(&sbinfo->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; ++ ++ /* 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; ++ ++ au_sbilist_add(root->d_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); ++ au_fhsm_fin(sb); ++ 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, /*do_idop*/0); ++ } ++ if (au_opt_test(sbinfo->si_mntflags, PLINK)) ++ au_plink_put(sb, /*verbose*/1); ++ au_xino_clr(sb); ++ au_dr_opt_flush(sb); ++ sbinfo->si_sb = NULL; ++ aufs_write_unlock(sb->s_root); ++ au_nwt_flush(&sbinfo->si_nowait); ++ } ++ kill_anon_super(sb); ++} ++ ++struct file_system_type aufs_fs_type = { ++ .name = AUFS_FSTYPE, ++ /* a race between rename and others */ ++ .fs_flags = FS_RENAME_DOES_D_MOVE, ++ .mount = aufs_mount, ++ .kill_sb = aufs_kill_sb, ++ /* no need to __module_get() and module_put(). */ ++ .owner = THIS_MODULE, ++}; +diff -Nurp linux-5.4/fs/aufs/super.h linux-5.4-aufs/fs/aufs/super.h +--- linux-5.4/fs/aufs/super.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/super.h 2019-11-28 01:25:59.068925618 +0200 +@@ -0,0 +1,576 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * super_block operations ++ */ ++ ++#ifndef __AUFS_SUPER_H__ ++#define __AUFS_SUPER_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include "hbl.h" ++#include "lcnt.h" ++#include "rwsem.h" ++#include "wkq.h" ++ ++/* policies to select one among multiple writable branches */ ++struct au_wbr_copyup_operations { ++ int (*copyup)(struct dentry *dentry); ++}; ++ ++#define AuWbr_DIR 1 /* target is a dir */ ++#define AuWbr_PARENT (1 << 1) /* always require a parent */ ++ ++#define au_ftest_wbr(flags, name) ((flags) & AuWbr_##name) ++#define au_fset_wbr(flags, name) { (flags) |= AuWbr_##name; } ++#define au_fclr_wbr(flags, name) { (flags) &= ~AuWbr_##name; } ++ ++struct au_wbr_create_operations { ++ int (*create)(struct dentry *dentry, unsigned int flags); ++ 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; ++}; ++ ++#define AuPlink_NHASH 100 ++static inline int au_plink_hash(ino_t ino) ++{ ++ return ino % AuPlink_NHASH; ++} ++ ++/* File-based Hierarchical Storage Management */ ++struct au_fhsm { ++#ifdef CONFIG_AUFS_FHSM ++ /* allow only one process who can receive the notification */ ++ spinlock_t fhsm_spin; ++ pid_t fhsm_pid; ++ wait_queue_head_t fhsm_wqh; ++ atomic_t fhsm_readable; ++ ++ /* these are protected by si_rwsem */ ++ unsigned long fhsm_expire; ++ aufs_bindex_t fhsm_bottom; ++#endif ++}; ++ ++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 dependency between i_mutex. ++ * rwsem for au_sbinfo is necessary. ++ */ ++ struct au_rwsem si_rwsem; ++ ++ /* ++ * dirty approach to protect sb->sb_inodes and ->s_files (gone) from ++ * remount. ++ */ ++ au_lcnt_t si_ninodes, si_nfiles; ++ ++ /* branch management */ ++ unsigned int si_generation; ++ ++ /* see AuSi_ flags */ ++ unsigned char au_si_status; ++ ++ aufs_bindex_t si_bbot; ++ ++ /* 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; ++ ++ /* File-based Hierarchical Storage Management */ ++ struct au_fhsm si_fhsm; ++ ++ /* mount flags */ ++ /* include/asm-ia64/siginfo.h defines a macro named si_flags */ ++ unsigned int si_mntflags; ++ ++ /* external inode number (bitmap and translation table) */ ++ vfs_readf_t si_xread; ++ vfs_writef_t si_xwrite; ++ loff_t si_ximaxent; /* max entries in a xino */ ++ ++ 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; ++ ++ unsigned long si_xino_jiffy; ++ unsigned long si_xino_expire; ++ /* reserved for future use */ ++ /* unsigned long long si_xib_limit; */ /* Max xib file size */ ++ ++#ifdef CONFIG_AUFS_EXPORT ++ /* i_generation */ ++ /* todo: make xigen file an array to support many inode numbers */ ++ struct file *si_xigen; ++ atomic_t si_xigen_next; ++#endif ++ ++ /* dirty trick to support atomic_open */ ++ struct hlist_bl_head si_aopen; ++ ++ /* 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; ++ ++ /* pseudo_link list */ ++ struct hlist_bl_head si_plink[AuPlink_NHASH]; ++ wait_queue_head_t si_plink_wq; ++ spinlock_t si_plink_maint_lock; ++ pid_t si_plink_maint_pid; ++ ++ /* file list */ ++ struct hlist_bl_head si_files; ++ ++ /* with/without getattr, brother of sb->s_d_op */ ++ struct inode_operations *si_iop_array; ++ ++ /* ++ * sysfs and lifetime management. ++ * this is not a small structure and it may be a waste of memory in case ++ * of sysfs is disabled, particularly when many aufs-es are mounted. ++ * but using sysfs is majority. ++ */ ++ struct kobject si_kobj; ++#ifdef CONFIG_DEBUG_FS ++ struct dentry *si_dbgaufs; ++ struct dentry *si_dbgaufs_plink; ++ struct dentry *si_dbgaufs_xib; ++#ifdef CONFIG_AUFS_EXPORT ++ struct dentry *si_dbgaufs_xigen; ++#endif ++#endif ++ ++#ifdef CONFIG_AUFS_SBILIST ++ struct hlist_bl_node 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 unnecessary ++ */ ++#define AuSi_FAILED_REFRESH_DIR 1 ++#define AuSi_FHSM (1 << 1) /* fhsm is active now */ ++#define AuSi_NO_DREVAL (1 << 2) /* disable all d_revalidate */ ++ ++#ifndef CONFIG_AUFS_FHSM ++#undef AuSi_FHSM ++#define AuSi_FHSM 0 ++#endif ++ ++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_DIRS (1 << 4) /* target is a pair of dirs */ ++ /* except RENAME_EXCHANGE */ ++#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)(struct super_block *sb, void *array, ++ unsigned long long max, void *arg); ++void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, ++ struct super_block *sb, 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, int may_shrink); ++ ++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); ++ ++/* 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); ++int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex); ++int au_wbr_do_copyup_bu(struct dentry *dentry, aufs_bindex_t btop); ++ ++/* mvdown.c */ ++int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *arg); ++ ++#ifdef CONFIG_AUFS_FHSM ++/* fhsm.c */ ++ ++static inline pid_t au_fhsm_pid(struct au_fhsm *fhsm) ++{ ++ pid_t pid; ++ ++ spin_lock(&fhsm->fhsm_spin); ++ pid = fhsm->fhsm_pid; ++ spin_unlock(&fhsm->fhsm_spin); ++ ++ return pid; ++} ++ ++void au_fhsm_wrote(struct super_block *sb, aufs_bindex_t bindex, int force); ++void au_fhsm_wrote_all(struct super_block *sb, int force); ++int au_fhsm_fd(struct super_block *sb, int oflags); ++int au_fhsm_br_alloc(struct au_branch *br); ++void au_fhsm_set_bottom(struct super_block *sb, aufs_bindex_t bindex); ++void au_fhsm_fin(struct super_block *sb); ++void au_fhsm_init(struct au_sbinfo *sbinfo); ++void au_fhsm_set(struct au_sbinfo *sbinfo, unsigned int sec); ++void au_fhsm_show(struct seq_file *seq, struct au_sbinfo *sbinfo); ++#else ++AuStubVoid(au_fhsm_wrote, struct super_block *sb, aufs_bindex_t bindex, ++ int force) ++AuStubVoid(au_fhsm_wrote_all, struct super_block *sb, int force) ++AuStub(int, au_fhsm_fd, return -EOPNOTSUPP, struct super_block *sb, int oflags) ++AuStub(pid_t, au_fhsm_pid, return 0, struct au_fhsm *fhsm) ++AuStubInt0(au_fhsm_br_alloc, struct au_branch *br) ++AuStubVoid(au_fhsm_set_bottom, struct super_block *sb, aufs_bindex_t bindex) ++AuStubVoid(au_fhsm_fin, struct super_block *sb) ++AuStubVoid(au_fhsm_init, struct au_sbinfo *sbinfo) ++AuStubVoid(au_fhsm_set, struct au_sbinfo *sbinfo, unsigned int sec) ++AuStubVoid(au_fhsm_show, struct seq_file *seq, struct au_sbinfo *sbinfo) ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++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 path *path); ++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 path *path) ++AuStubVoid(au_xigen_clr, struct super_block *sb) ++AuStub(int, au_busy_or_stale, return -EBUSY, void) ++#endif /* CONFIG_AUFS_EXPORT */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_SBILIST ++/* module.c */ ++extern struct hlist_bl_head au_sbilist; ++ ++static inline void au_sbilist_init(void) ++{ ++ INIT_HLIST_BL_HEAD(&au_sbilist); ++} ++ ++static inline void au_sbilist_add(struct super_block *sb) ++{ ++ au_hbl_add(&au_sbi(sb)->si_list, &au_sbilist); ++} ++ ++static inline void au_sbilist_del(struct super_block *sb) ++{ ++ au_hbl_del(&au_sbi(sb)->si_list, &au_sbilist); ++} ++ ++#ifdef CONFIG_AUFS_MAGIC_SYSRQ ++static inline void au_sbilist_lock(void) ++{ ++ hlist_bl_lock(&au_sbilist); ++} ++ ++static inline void au_sbilist_unlock(void) ++{ ++ hlist_bl_unlock(&au_sbilist); ++} ++#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 *sb) ++AuStubVoid(au_sbilist_del, struct super_block *sb) ++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' function 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_plink = NULL; ++ sbinfo->si_dbgaufs_xib = NULL; ++#ifdef CONFIG_AUFS_EXPORT ++ sbinfo->si_dbgaufs_xigen = NULL; ++#endif ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* current->atomic_flags */ ++/* this value should never corrupt the ones defined in linux/sched.h */ ++#define PFA_AUFS 0x10 ++ ++TASK_PFA_TEST(AUFS, test_aufs) /* task_test_aufs */ ++TASK_PFA_SET(AUFS, aufs) /* task_set_aufs */ ++TASK_PFA_CLEAR(AUFS, aufs) /* task_clear_aufs */ ++ ++static inline int si_pid_test(struct super_block *sb) ++{ ++ return !!task_test_aufs(current); ++} ++ ++static inline void si_pid_clr(struct super_block *sb) ++{ ++ AuDebugOn(!task_test_aufs(current)); ++ task_clear_aufs(current); ++} ++ ++static inline void si_pid_set(struct super_block *sb) ++{ ++ AuDebugOn(task_test_aufs(current)); ++ task_set_aufs(current); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock superblock. mainly for entry point functions */ ++#define __si_read_lock(sb) au_rw_read_lock(&au_sbi(sb)->si_rwsem) ++#define __si_write_lock(sb) au_rw_write_lock(&au_sbi(sb)->si_rwsem) ++#define __si_read_trylock(sb) au_rw_read_trylock(&au_sbi(sb)->si_rwsem) ++#define __si_write_trylock(sb) au_rw_write_trylock(&au_sbi(sb)->si_rwsem) ++/* ++#define __si_read_trylock_nested(sb) \ ++ au_rw_read_trylock_nested(&au_sbi(sb)->si_rwsem) ++#define __si_write_trylock_nested(sb) \ ++ au_rw_write_trylock_nested(&au_sbi(sb)->si_rwsem) ++*/ ++ ++#define __si_read_unlock(sb) au_rw_read_unlock(&au_sbi(sb)->si_rwsem) ++#define __si_write_unlock(sb) au_rw_write_unlock(&au_sbi(sb)->si_rwsem) ++#define __si_downgrade_lock(sb) au_rw_dgrade_lock(&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; ++ ++ 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; ++ ++ locked = __si_write_trylock(sb); ++ if (locked) ++ si_pid_set(sb); ++ return locked; ++} ++ ++#if 0 /* reserved */ ++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 /* reserved */ ++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 /* reserved */ ++static inline void si_downgrade_lock(struct super_block *sb) ++{ ++ __si_downgrade_lock(sb); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline aufs_bindex_t au_sbbot(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_bbot; ++} ++ ++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 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 loff_t au_xi_maxent(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_ximaxent; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_SUPER_H__ */ +diff -Nurp linux-5.4/fs/aufs/sysaufs.c linux-5.4-aufs/fs/aufs/sysaufs.c +--- linux-5.4/fs/aufs/sysaufs.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/sysaufs.c 2019-11-28 01:25:59.068925618 +0200 +@@ -0,0 +1,80 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * 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)); ++ ++ return err; ++} ++ ++void sysaufs_fin(void) ++{ ++ 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); ++ ++out: ++ return err; ++} +diff -Nurp linux-5.4/fs/aufs/sysaufs.h linux-5.4-aufs/fs/aufs/sysaufs.h +--- linux-5.4/fs/aufs/sysaufs.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/sysaufs.h 2019-11-28 01:25:59.068925618 +0200 +@@ -0,0 +1,89 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * 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); ++long au_brinfo_ioctl(struct file *file, unsigned long arg); ++#ifdef CONFIG_COMPAT ++long au_brinfo_compat_ioctl(struct file *file, unsigned long arg); ++#endif ++ ++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) ++AuStub(ssize_t, sysaufs_si_show, return 0, struct kobject *kobj, ++ struct attribute *attr, char *buf) ++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 -Nurp linux-5.4/fs/aufs/sysfs.c linux-5.4-aufs/fs/aufs/sysfs.c +--- linux-5.4/fs/aufs/sysfs.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/sysfs.c 2019-11-28 01:25:59.068925618 +0200 +@@ -0,0 +1,338 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * sysfs interface ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++static struct attribute *au_attr[] = { ++ 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 idx) ++{ ++ int err; ++ struct path path; ++ struct dentry *root; ++ struct au_branch *br; ++ au_br_perm_str_t perm; ++ ++ AuDbg("b%d\n", bindex); ++ ++ err = 0; ++ root = sb->s_root; ++ di_read_lock_parent(root, !AuLock_IR); ++ br = au_sbr(sb, bindex); ++ ++ switch (idx) { ++ case AuBrSysfs_BR: ++ path.mnt = au_br_mnt(br); ++ path.dentry = au_h_dptr(root, bindex); ++ err = au_seq_path(seq, &path); ++ if (!err) { ++ au_optstr_br_perm(&perm, br->br_perm); ++ seq_printf(seq, "=%s\n", perm.a); ++ } ++ break; ++ case AuBrSysfs_BRID: ++ seq_printf(seq, "%d\n", br->br_id); ++ break; ++ } ++ di_read_unlock(root, !AuLock_IR); ++ if (unlikely(err || seq_has_overflowed(seq))) ++ err = -E2BIG; ++ ++ 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" ++#define SysaufsBrid_PREFIX "brid" ++ ++/* todo: file size may exceed PAGE_SIZE */ ++ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, ++ char *buf) ++{ ++ ssize_t err; ++ int idx; ++ long l; ++ aufs_bindex_t bbot; ++ 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++; ++ } ++ ++ if (!strncmp(name, SysaufsBrid_PREFIX, ++ sizeof(SysaufsBrid_PREFIX) - 1)) { ++ idx = AuBrSysfs_BRID; ++ name += sizeof(SysaufsBrid_PREFIX) - 1; ++ } else if (!strncmp(name, SysaufsBr_PREFIX, ++ sizeof(SysaufsBr_PREFIX) - 1)) { ++ idx = AuBrSysfs_BR; ++ name += sizeof(SysaufsBr_PREFIX) - 1; ++ } else ++ BUG(); ++ ++ err = kstrtol(name, 10, &l); ++ if (!err) { ++ bbot = au_sbbot(sb); ++ if (l <= bbot) ++ err = sysaufs_si_br(seq, sb, (aufs_bindex_t)l, idx); ++ else ++ err = -ENOENT; ++ } ++ ++out_seq: ++ if (!err) { ++ err = seq->count; ++ /* sysfs limit */ ++ if (unlikely(err == PAGE_SIZE)) ++ err = -EFBIG; ++ } ++ au_kfree_rcu(seq); ++out_unlock: ++ si_read_unlock(sb); ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_brinfo(struct super_block *sb, union aufs_brinfo __user *arg) ++{ ++ int err; ++ int16_t brid; ++ aufs_bindex_t bindex, bbot; ++ size_t sz; ++ char *buf; ++ struct seq_file *seq; ++ struct au_branch *br; ++ ++ si_read_lock(sb, AuLock_FLUSH); ++ bbot = au_sbbot(sb); ++ err = bbot + 1; ++ if (!arg) ++ goto out; ++ ++ err = -ENOMEM; ++ buf = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!buf)) ++ goto out; ++ ++ seq = au_seq(buf, PAGE_SIZE); ++ err = PTR_ERR(seq); ++ if (IS_ERR(seq)) ++ goto out_buf; ++ ++ sz = sizeof(*arg) - offsetof(union aufs_brinfo, path); ++ for (bindex = 0; bindex <= bbot; bindex++, arg++) { ++ /* VERIFY_WRITE */ ++ err = !access_ok(arg, sizeof(*arg)); ++ if (unlikely(err)) ++ break; ++ ++ br = au_sbr(sb, bindex); ++ brid = br->br_id; ++ BUILD_BUG_ON(sizeof(brid) != sizeof(arg->id)); ++ err = __put_user(brid, &arg->id); ++ if (unlikely(err)) ++ break; ++ ++ BUILD_BUG_ON(sizeof(br->br_perm) != sizeof(arg->perm)); ++ err = __put_user(br->br_perm, &arg->perm); ++ if (unlikely(err)) ++ break; ++ ++ err = au_seq_path(seq, &br->br_path); ++ if (unlikely(err)) ++ break; ++ seq_putc(seq, '\0'); ++ if (!seq_has_overflowed(seq)) { ++ err = copy_to_user(arg->path, seq->buf, seq->count); ++ seq->count = 0; ++ if (unlikely(err)) ++ break; ++ } else { ++ err = -E2BIG; ++ goto out_seq; ++ } ++ } ++ if (unlikely(err)) ++ err = -EFAULT; ++ ++out_seq: ++ au_kfree_rcu(seq); ++out_buf: ++ free_page((unsigned long)buf); ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++long au_brinfo_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_brinfo(file->f_path.dentry->d_sb, (void __user *)arg); ++} ++ ++#ifdef CONFIG_COMPAT ++long au_brinfo_compat_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_brinfo(file->f_path.dentry->d_sb, compat_ptr(arg)); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++void sysaufs_br_init(struct au_branch *br) ++{ ++ int i; ++ struct au_brsysfs *br_sysfs; ++ struct attribute *attr; ++ ++ br_sysfs = br->br_sysfs; ++ for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) { ++ attr = &br_sysfs->attr; ++ sysfs_attr_init(attr); ++ attr->name = br_sysfs->name; ++ attr->mode = 0444; ++ br_sysfs++; ++ } ++} ++ ++void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ struct au_branch *br; ++ struct kobject *kobj; ++ struct au_brsysfs *br_sysfs; ++ int i; ++ aufs_bindex_t bbot; ++ ++ if (!sysaufs_brs) ++ return; ++ ++ kobj = &au_sbi(sb)->si_kobj; ++ bbot = au_sbbot(sb); ++ for (; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ br_sysfs = br->br_sysfs; ++ for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) { ++ sysfs_remove_file(kobj, &br_sysfs->attr); ++ br_sysfs++; ++ } ++ } ++} ++ ++void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ int err, i; ++ aufs_bindex_t bbot; ++ struct kobject *kobj; ++ struct au_branch *br; ++ struct au_brsysfs *br_sysfs; ++ ++ if (!sysaufs_brs) ++ return; ++ ++ kobj = &au_sbi(sb)->si_kobj; ++ bbot = au_sbbot(sb); ++ for (; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ br_sysfs = br->br_sysfs; ++ snprintf(br_sysfs[AuBrSysfs_BR].name, sizeof(br_sysfs->name), ++ SysaufsBr_PREFIX "%d", bindex); ++ snprintf(br_sysfs[AuBrSysfs_BRID].name, sizeof(br_sysfs->name), ++ SysaufsBrid_PREFIX "%d", bindex); ++ for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) { ++ err = sysfs_create_file(kobj, &br_sysfs->attr); ++ if (unlikely(err)) ++ pr_warn("failed %s under sysfs(%d)\n", ++ br_sysfs->name, err); ++ br_sysfs++; ++ } ++ } ++} +diff -Nurp linux-5.4/fs/aufs/sysrq.c linux-5.4-aufs/fs/aufs/sysrq.c +--- linux-5.4/fs/aufs/sysrq.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/sysrq.c 2019-11-28 01:25:59.068925618 +0200 +@@ -0,0 +1,147 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * magic sysrq handler ++ */ ++ ++/* #include */ ++#include ++#include "aufs.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void sysrq_sb(struct super_block *sb) ++{ ++ char *plevel; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ struct hlist_bl_head *files; ++ struct hlist_bl_node *pos; ++ struct au_finfo *finfo; ++ ++ 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(d_inode(sb->s_root)); ++#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(&sb->s_inode_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(&sb->s_inode_list_lock); ++ } ++#endif ++ pr("files\n"); ++ files = &au_sbi(sb)->si_files; ++ hlist_bl_lock(files); ++ hlist_bl_for_each_entry(finfo, pos, files, fi_hlist) { ++ umode_t mode; ++ ++ file = finfo->fi_file; ++ mode = file_inode(file)->i_mode; ++ if (!special_file(mode)) ++ au_dpri_file(file); ++ } ++ hlist_bl_unlock(files); ++ pr("done\n"); ++ ++#undef pr ++ au_plevel = plevel; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* module parameter */ ++static char *aufs_sysrq_key = "a"; ++module_param_named(sysrq, aufs_sysrq_key, charp, 0444); ++MODULE_PARM_DESC(sysrq, "MagicSysRq key for " AUFS_NAME); ++ ++static void au_sysrq(int key __maybe_unused) ++{ ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_node *pos; ++ ++ lockdep_off(); ++ au_sbilist_lock(); ++ hlist_bl_for_each_entry(sbinfo, pos, &au_sbilist, 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 -Nurp linux-5.4/fs/aufs/wbr_policy.c linux-5.4-aufs/fs/aufs/wbr_policy.c +--- linux-5.4/fs/aufs/wbr_policy.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/wbr_policy.c 2019-11-28 01:25:59.068925618 +0200 +@@ -0,0 +1,817 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * 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 = d_inode(h_src); ++ 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(d_inode(h_path->dentry), h_isrc->i_flags); ++ /* no delegation since it is just created */ ++ err = vfsub_sio_notify_change(h_path, &ia, /*delegated*/NULL); ++ ++ /* 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, /*delegated*/NULL); ++ } ++ ++ 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) ++ ++static int au_cpdown_dir_opq(struct dentry *dentry, aufs_bindex_t bdst, ++ unsigned int *flags) ++{ ++ 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(*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 (d_is_positive(h_path.dentry)) { ++ h_path.mnt = au_br_mnt(br); ++ 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 au_pin *pin, ++ struct dentry *h_parent, void *arg) ++{ ++ int err, rerr; ++ aufs_bindex_t bopq, btop; ++ struct path h_path; ++ struct dentry *parent; ++ struct inode *h_dir, *h_inode, *inode, *dir; ++ unsigned int *flags = arg; ++ ++ btop = au_dbtop(dentry); ++ /* dentry is di-locked */ ++ parent = dget_parent(dentry); ++ dir = d_inode(parent); ++ h_dir = d_inode(h_parent); ++ AuDebugOn(h_dir != au_h_iptr(dir, bdst)); ++ IMustLock(h_dir); ++ ++ err = au_lkup_neg(dentry, bdst, /*wh*/0); ++ 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, 0755); ++ if (unlikely(err)) ++ goto out_put; ++ au_fset_cpdown(*flags, MADE_DIR); ++ ++ bopq = au_dbdiropq(dentry); ++ au_fclr_cpdown(*flags, WHED); ++ au_fclr_cpdown(*flags, DIROPQ); ++ if (au_dbwh(dentry) == bdst) ++ au_fset_cpdown(*flags, WHED); ++ if (!au_ftest_cpdown(*flags, PARENT_OPQ) && bopq <= bdst) ++ au_fset_cpdown(*flags, PARENT_OPQ); ++ h_inode = d_inode(h_path.dentry); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ if (au_ftest_cpdown(*flags, WHED)) { ++ err = au_cpdown_dir_opq(dentry, bdst, flags); ++ if (unlikely(err)) { ++ inode_unlock(h_inode); ++ goto out_dir; ++ } ++ } ++ ++ err = au_cpdown_attr(&h_path, au_h_dptr(dentry, btop)); ++ inode_unlock(h_inode); ++ if (unlikely(err)) ++ goto out_opq; ++ ++ if (au_ftest_cpdown(*flags, WHED)) { ++ err = au_cpdown_dir_wh(dentry, h_parent, dir, bdst); ++ if (unlikely(err)) ++ goto out_opq; ++ } ++ ++ inode = d_inode(dentry); ++ if (au_ibbot(inode) < bdst) ++ au_set_ibbot(inode, bdst); ++ au_set_h_iptr(inode, bdst, au_igrab(h_inode), ++ au_hi_flags(inode, /*isdir*/1)); ++ au_fhsm_wrote(dentry->d_sb, bdst, /*force*/0); ++ goto out; /* success */ ++ ++ /* revert */ ++out_opq: ++ if (au_ftest_cpdown(*flags, DIROPQ)) { ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ rerr = au_diropq_remove(dentry, bdst); ++ inode_unlock(h_inode); ++ if (unlikely(rerr)) { ++ AuIOErr("failed removing diropq for %pd b%d (%d)\n", ++ dentry, bdst, rerr); ++ err = -EIO; ++ goto out; ++ } ++ } ++out_dir: ++ if (au_ftest_cpdown(*flags, MADE_DIR)) { ++ rerr = vfsub_sio_rmdir(au_h_iptr(dir, bdst), &h_path); ++ if (unlikely(rerr)) { ++ AuIOErr("failed removing %pd b%d (%d)\n", ++ dentry, bdst, rerr); ++ err = -EIO; ++ } ++ } ++out_put: ++ au_set_h_dptr(dentry, bdst, NULL); ++ if (au_dbbot(dentry) == bdst) ++ au_update_dbbot(dentry); ++out: ++ dput(parent); ++ return err; ++} ++ ++int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst) ++{ ++ int err; ++ unsigned int flags; ++ ++ flags = 0; ++ err = au_cp_dirs(dentry, bdst, au_cpdown_dir, &flags); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policies for create */ ++ ++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, ++ unsigned int flags __maybe_unused) ++{ ++ int err; ++ aufs_bindex_t btop, bindex; ++ struct super_block *sb; ++ struct dentry *parent, *h_parent; ++ ++ sb = dentry->d_sb; ++ btop = au_dbtop(dentry); ++ err = btop; ++ if (!au_br_rdonly(au_sbr(sb, btop))) ++ goto out; ++ ++ err = -EROFS; ++ parent = dget_parent(dentry); ++ for (bindex = au_dbtop(parent); bindex < btop; bindex++) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || d_is_negative(h_parent)) ++ 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, btop - 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_sbbot(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, unsigned int flags) ++{ ++ int err, nbr; ++ unsigned int u; ++ aufs_bindex_t bindex, bbot; ++ 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; ++ bbot = au_sbbot(sb); ++ nbr = bbot + 1; ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ if (!au_ftest_wbr(flags, DIR)) { ++ 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 dentry *parent) ++{ ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_wbr_mfs *mfs; ++ struct dentry *h_parent; ++ aufs_bindex_t bindex, bbot; ++ 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; ++ if (!parent) { ++ bindex = 0; ++ bbot = au_sbbot(sb); ++ } else { ++ bindex = au_dbtop(parent); ++ bbot = au_dbtaildir(parent); ++ } ++ ++ for (; bindex <= bbot; bindex++) { ++ if (parent) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || d_is_negative(h_parent)) ++ continue; ++ } ++ br = au_sbr(sb, bindex); ++ if (au_br_rdonly(br)) ++ continue; ++ ++ /* sb->s_root for NFS is unreliable */ ++ h_path.mnt = au_br_mnt(br); ++ 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); ++ au_kfree_rcu(st); ++} ++ ++static int au_wbr_create_mfs(struct dentry *dentry, unsigned int flags) ++{ ++ int err; ++ struct dentry *parent; ++ struct super_block *sb; ++ struct au_wbr_mfs *mfs; ++ ++ err = au_wbr_create_exp(dentry); ++ if (err >= 0) ++ goto out; ++ ++ sb = dentry->d_sb; ++ parent = NULL; ++ if (au_ftest_wbr(flags, PARENT)) ++ parent = dget_parent(dentry); ++ 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, parent); ++ mutex_unlock(&mfs->mfs_lock); ++ err = mfs->mfs_bindex; ++ dput(parent); ++ ++ 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; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* top down regardless parent, and then mfs */ ++static int au_wbr_create_tdmfs(struct dentry *dentry, ++ unsigned int flags __maybe_unused) ++{ ++ int err; ++ aufs_bindex_t bwh, btail, bindex, bfound, bmfs; ++ unsigned long long watermark; ++ struct super_block *sb; ++ struct au_wbr_mfs *mfs; ++ struct au_branch *br; ++ struct dentry *parent; ++ ++ 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_mfs(dentry, /*parent*/NULL); ++ watermark = mfs->mfsrr_watermark; ++ bmfs = mfs->mfs_bindex; ++ mutex_unlock(&mfs->mfs_lock); ++ ++ /* another style of au_wbr_create_exp() */ ++ bwh = au_dbwh(dentry); ++ parent = dget_parent(dentry); ++ btail = au_dbtaildir(parent); ++ if (bwh >= 0 && bwh < btail) ++ btail = bwh; ++ ++ err = au_wbr_nonopq(dentry, btail); ++ if (unlikely(err < 0)) ++ goto out; ++ btail = err; ++ bfound = -1; ++ for (bindex = 0; bindex <= btail; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_rdonly(br)) ++ continue; ++ if (br->br_wbr->wbr_bytes > watermark) { ++ bfound = bindex; ++ break; ++ } ++ } ++ err = bfound; ++ if (err < 0) ++ err = bmfs; ++ ++out: ++ dput(parent); ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* most free space and then round robin */ ++static int au_wbr_create_mfsrr(struct dentry *dentry, unsigned int flags) ++{ ++ int err; ++ struct au_wbr_mfs *mfs; ++ ++ err = au_wbr_create_mfs(dentry, flags); ++ 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, flags); ++ 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, unsigned int flags) ++{ ++ int err, e2; ++ unsigned long long b; ++ aufs_bindex_t bindex, btop, bbot; ++ struct super_block *sb; ++ struct dentry *parent, *h_parent; ++ struct au_branch *br; ++ ++ err = au_wbr_create_tdp(dentry, flags); ++ if (unlikely(err < 0)) ++ goto out; ++ parent = dget_parent(dentry); ++ btop = au_dbtop(parent); ++ bbot = au_dbtaildir(parent); ++ if (btop == bbot) ++ goto out_parent; /* success */ ++ ++ e2 = au_wbr_create_mfs(dentry, flags); ++ 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 = btop; bindex <= bbot; bindex++) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || d_is_negative(h_parent)) ++ 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; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * - top down parent ++ * - most free space with parent ++ * - most free space round-robin regardless parent ++ */ ++static int au_wbr_create_pmfsrr(struct dentry *dentry, unsigned int flags) ++{ ++ int err; ++ unsigned long long watermark; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_wbr_mfs *mfs; ++ ++ err = au_wbr_create_pmfs(dentry, flags | AuWbr_PARENT); ++ if (unlikely(err < 0)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, err); ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ mutex_lock(&mfs->mfs_lock); ++ watermark = mfs->mfsrr_watermark; ++ mutex_unlock(&mfs->mfs_lock); ++ if (br->br_wbr->wbr_bytes < watermark) ++ /* regardless the parent dir */ ++ err = au_wbr_create_mfsrr(dentry, flags); ++ ++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, /*flags, anything is ok*/0); ++} ++ ++/* bottom up parent */ ++static int au_wbr_copyup_bup(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t bindex, btop; ++ struct dentry *parent, *h_parent; ++ struct super_block *sb; ++ ++ err = -EROFS; ++ sb = dentry->d_sb; ++ parent = dget_parent(dentry); ++ btop = au_dbtop(parent); ++ for (bindex = au_dbtop(dentry); bindex >= btop; bindex--) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || d_is_negative(h_parent)) ++ 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, btop - 1); ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* bottom up */ ++int au_wbr_do_copyup_bu(struct dentry *dentry, aufs_bindex_t btop) ++{ ++ int err; ++ ++ err = au_wbr_bu(dentry->d_sb, btop); ++ AuDbg("b%d\n", err); ++ if (err > btop) ++ err = au_wbr_nonopq(dentry, err); ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_copyup_bu(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t btop; ++ ++ btop = au_dbtop(dentry); ++ err = au_wbr_do_copyup_bu(dentry, btop); ++ 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_TDMFS] = { ++ .create = au_wbr_create_tdmfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_TDMFSV] = { ++ .create = au_wbr_create_tdmfs, ++ .init = au_wbr_create_init_mfs, ++ .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 ++ }, ++ [AuWbrCreate_PMFSRR] = { ++ .create = au_wbr_create_pmfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFSRRV] = { ++ .create = au_wbr_create_pmfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ } ++}; +diff -Nurp linux-5.4/fs/aufs/vdir.c linux-5.4-aufs/fs/aufs/vdir.c +--- linux-5.4/fs/aufs/vdir.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/vdir.c 2019-11-28 01:25:59.068925618 +0200 +@@ -0,0 +1,883 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * virtual or vertical directory ++ */ ++ ++#include ++#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 appropriate 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; ++ size_t sz; ++ ++ sz = sizeof(*nhash->nh_head) * num_hash; ++ head = kmalloc(sz, 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 *pos; ++ struct hlist_node *node; ++ ++ hlist_for_each_entry_safe(pos, node, head, wh_hash) ++ au_kfree_rcu(pos); ++} ++ ++static void au_nhash_de_do_free(struct hlist_head *head) ++{ ++ struct au_vdir_dehstr *pos; ++ struct hlist_node *node; ++ ++ hlist_for_each_entry_safe(pos, node, head, hash) ++ au_cache_free_vdir_dehstr(pos); ++} ++ ++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++); ++ } ++ au_kfree_try_rcu(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 *pos; ++ ++ num = 0; ++ n = whlist->nh_num; ++ head = whlist->nh_head; ++ for (u = 0; u < n; u++, head++) ++ hlist_for_each_entry(pos, head, wh_hash) ++ if (pos->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; ++ if (len > 8) ++ len = 8; ++ 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 *pos; ++ struct au_vdir_destr *str; ++ ++ head = au_name_hash(whlist, name, nlen); ++ hlist_for_each_entry(pos, head, wh_hash) { ++ str = &pos->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 *pos; ++ struct au_vdir_destr *str; ++ ++ head = au_name_hash(delist, name, nlen); ++ hlist_for_each_entry(pos, head, hash) { ++ str = pos->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 = au_krealloc(vdir->vd_deblk, sizeof(*o) * (vdir->vd_nblk + 1), ++ GFP_NOFS, /*may_shrink*/0); ++ 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--) ++ au_kfree_try_rcu(*deblk++); ++ au_kfree_try_rcu(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_path.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 appropriate 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 */ ++ ++ au_kfree_try_rcu(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) { ++ au_kfree_try_rcu(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 dir_context ctx; ++ 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(struct dir_context *ctx, const char *__name, int nlen, ++ loff_t offset __maybe_unused, u64 h_ino, ++ unsigned int d_type) ++{ ++ struct fillvdir_arg *arg = container_of(ctx, struct fillvdir_arg, ctx); ++ 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_path.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 */ ++ ++ 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 */ ++ ++ ino = 0; /* just to suppress a warning */ ++ 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 *pos; ++ struct hlist_node *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(pos, n, head, wh_hash) { ++ destr = &pos->wh_str; ++ memcpy(p, destr->name, destr->len); ++ err = append_de(vdir, o, destr->len + AUFS_WH_PFX_LEN, ++ pos->wh_ino, pos->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 bbot, bindex, btop; ++ unsigned char shwh; ++ struct file *hf, *file; ++ struct super_block *sb; ++ ++ file = arg->file; ++ sb = file->f_path.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); ++ } ++ btop = au_fbtop(file); ++ bbot = au_fbbot_dir(file); ++ for (bindex = btop; !err && bindex <= bbot; 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 != bbot ++ && 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_iterate_dir(hf, &arg->ctx); ++ if (err >= 0) ++ err = arg->err; ++ } while (!err && au_ftest_fillvdir(arg->flags, CALLED)); ++ ++ /* ++ * dir_relax() may be good for concurrency, but aufs should not ++ * use it since it will cause a lockdep problem. ++ */ ++ } ++ ++ 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 = { ++ .ctx = { ++ .actor = fillvdir ++ } ++ }; ++ struct inode *inode; ++ struct au_vdir *vdir, *allocated; ++ ++ err = 0; ++ inode = file_inode(file); ++ IMustLock(inode); ++ IiMustWriteLock(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_eq_iversion(inode, 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; */ /* todo: ctx->pos? */ ++ vdir->vd_version = inode_query_iversion(inode); ++ 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 = au_krealloc(tgt->vd_deblk, sizeof(*p) * src->vd_nblk, ++ GFP_NOFS, /*may_shrink*/0); ++ 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 = au_krealloc(tgt->vd_deblk[0], deblk_sz, GFP_NOFS, ++ /*may_shrink*/1); ++ 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; ++ ++ /* test file->f_pos here instead of ctx->pos */ ++ 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) { ++ /* test file->f_pos here instead of ctx->pos */ ++ err = reinit_vdir(vdir_cache); ++ if (unlikely(err)) ++ goto out; ++ } else ++ return 0; /* success */ ++ ++ inode = file_inode(file); ++ err = copy_vdir(vdir_cache, au_ivdir(inode)); ++ if (!err) { ++ file->f_version = inode_query_iversion(inode); ++ 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, struct dir_context *ctx) ++{ ++ 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 (ctx->pos == offset) ++ goto out; ++ ++ vdir_cache->vd_last.ul = 0; ++ vdir_cache->vd_last.p.deblk = vdir_cache->vd_deblk[0]; ++ if (!ctx->pos) ++ goto out; ++ ++ valid = 0; ++ deblk_sz = vdir_cache->vd_deblk_sz; ++ ul = div64_u64(ctx->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 < ctx->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(); */ ++ if (!valid) ++ AuDbg("valid %d\n", !valid); ++ return valid; ++} ++ ++int au_vdir_fill_de(struct file *file, struct dir_context *ctx) ++{ ++ unsigned int l, deblk_sz; ++ union au_vdir_deblk_p deblk_end; ++ struct au_vdir *vdir_cache; ++ struct au_vdir_de *de; ++ ++ if (!seek_vdir(file, ctx)) ++ return 0; ++ ++ vdir_cache = au_fvdir_cache(file); ++ 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, ctx->pos, ++ (unsigned long)de->de_ino, de->de_type); ++ if (unlikely(!dir_emit(ctx, de->de_str.name, ++ de->de_str.len, de->de_ino, ++ de->de_type))) { ++ /* 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; ++ ctx->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]; ++ ctx->pos = deblk_sz * vdir_cache->vd_last.ul; ++ continue; ++ } ++ break; ++ } ++ ++ /* smp_mb(); */ ++ return 0; ++} +diff -Nurp linux-5.4/fs/aufs/vfsub.c linux-5.4-aufs/fs/aufs/vfsub.c +--- linux-5.4/fs/aufs/vfsub.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/vfsub.c 2019-11-28 01:25:59.068925618 +0200 +@@ -0,0 +1,889 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * sub-routines for VFS ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++#ifdef CONFIG_AUFS_BR_FUSE ++int vfsub_test_mntns(struct vfsmount *mnt, struct super_block *h_sb) ++{ ++ if (!au_test_fuse(h_sb) || !au_userns) ++ return 0; ++ ++ return is_current_mnt_ns(mnt) ? 0 : -EACCES; ++} ++#endif ++ ++int vfsub_sync_filesystem(struct super_block *h_sb, int wait) ++{ ++ int err; ++ ++ lockdep_off(); ++ down_read(&h_sb->s_umount); ++ err = __sync_filesystem(h_sb, wait); ++ up_read(&h_sb->s_umount); ++ lockdep_on(); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++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 = vfsub_getattr(h_path, &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(d_inode(path->dentry)); ++ ++ 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; ++} ++ ++/* ++ * Ideally this function should call VFS:do_last() in order to keep all its ++ * checkings. But it is very hard for aufs to regenerate several VFS internal ++ * structure such as nameidata. This is a second (or third) best approach. ++ * cf. linux/fs/namei.c:do_last(), lookup_open() and atomic_open(). ++ */ ++int vfsub_atomic_open(struct inode *dir, struct dentry *dentry, ++ struct vfsub_aopen_args *args) ++{ ++ int err; ++ struct au_branch *br = args->br; ++ struct file *file = args->file; ++ /* copied from linux/fs/namei.c:atomic_open() */ ++ struct dentry *const DENTRY_NOT_SET = (void *)-1UL; ++ ++ IMustLock(dir); ++ AuDebugOn(!dir->i_op->atomic_open); ++ ++ err = au_br_test_oflag(args->open_flag, br); ++ if (unlikely(err)) ++ goto out; ++ ++ au_lcnt_inc(&br->br_nfiles); ++ file->f_path.dentry = DENTRY_NOT_SET; ++ file->f_path.mnt = au_br_mnt(br); ++ AuDbg("%ps\n", dir->i_op->atomic_open); ++ err = dir->i_op->atomic_open(dir, dentry, file, args->open_flag, ++ args->create_mode); ++ if (unlikely(err < 0)) { ++ au_lcnt_dec(&br->br_nfiles); ++ goto out; ++ } ++ ++ /* temporary workaround for nfsv4 branch */ ++ if (au_test_nfs(dir->i_sb)) ++ nfs_mark_for_revalidate(dir); ++ ++ if (file->f_mode & FMODE_CREATED) ++ fsnotify_create(dir, dentry); ++ if (!(file->f_mode & FMODE_OPENED)) { ++ au_lcnt_dec(&br->br_nfiles); ++ goto out; ++ } ++ ++ /* todo: call VFS:may_open() here */ ++ /* todo: ima_file_check() too? */ ++ if (!err && (args->open_flag & __FMODE_EXEC)) ++ err = deny_write_access(file); ++ if (!err) ++ fsnotify_open(file); ++ else ++ au_lcnt_dec(&br->br_nfiles); ++ /* note that the file is created and still opened */ ++ ++out: ++ return err; ++} ++ ++int vfsub_kern_path(const char *name, unsigned int flags, struct path *path) ++{ ++ int err; ++ ++ err = kern_path(name, flags, path); ++ if (!err && d_is_positive(path->dentry)) ++ vfsub_update_h_iattr(path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++struct dentry *vfsub_lookup_one_len_unlocked(const char *name, ++ struct dentry *parent, int len) ++{ ++ struct path path = { ++ .mnt = NULL ++ }; ++ ++ path.dentry = lookup_one_len_unlocked(name, parent, len); ++ if (IS_ERR(path.dentry)) ++ goto out; ++ if (d_is_positive(path.dentry)) ++ vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/ ++ ++out: ++ AuTraceErrPtr(path.dentry); ++ return path.dentry; ++} ++ ++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(d_inode(parent)); ++ ++ path.dentry = lookup_one_len(name, parent, len); ++ if (IS_ERR(path.dentry)) ++ goto out; ++ if (d_is_positive(path.dentry)) ++ 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; ++ ++ lockdep_off(); ++ err = vfs_create(dir, path->dentry, mode, want_excl); ++ lockdep_on(); ++ 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; ++ ++ lockdep_off(); ++ err = vfs_symlink(dir, path->dentry, symname); ++ lockdep_on(); ++ 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; ++ ++ lockdep_off(); ++ err = vfs_mknod(dir, path->dentry, mode, dev); ++ lockdep_on(); ++ 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, ++ struct inode **delegated_inode) ++{ ++ int err; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ ++ err = au_test_nlink(d_inode(src_dentry)); ++ 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, delegated_inode); ++ 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, ++ struct inode **delegated_inode, unsigned int flags) ++{ ++ 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, /*flags*/0); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ lockdep_off(); ++ err = vfs_rename(src_dir, src_dentry, dir, path->dentry, ++ delegated_inode, flags); ++ 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; ++ ++ lockdep_off(); ++ err = vfs_mkdir(dir, path->dentry, mode); ++ lockdep_on(); ++ 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->flush) { ++ if (!au_test_nfs(file->f_path.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_iterate_dir(struct file *file, struct dir_context *ctx) ++{ ++ int err; ++ ++ AuDbg("%pD, ctx{%ps, %llu}\n", file, ctx->actor, ctx->pos); ++ ++ lockdep_off(); ++ err = iterate_dir(file, ctx); ++ 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 = d_inode(h_path->dentry); ++ 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) { ++ lockdep_off(); ++ err = vfsub_mkdir(dir, path, mode); ++ lockdep_on(); ++ } 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) { ++ lockdep_off(); ++ err = vfsub_rmdir(dir, path); ++ lockdep_on(); ++ } 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; ++ struct inode **delegated_inode; ++}; ++ ++static void call_notify_change(void *args) ++{ ++ struct notify_change_args *a = args; ++ struct inode *h_inode; ++ ++ h_inode = d_inode(a->path->dentry); ++ IMustLock(h_inode); ++ ++ *a->errp = -EPERM; ++ if (!IS_IMMUTABLE(h_inode) && !IS_APPEND(h_inode)) { ++ lockdep_off(); ++ *a->errp = notify_change(a->path->dentry, a->ia, ++ a->delegated_inode); ++ lockdep_on(); ++ 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, ++ struct inode **delegated_inode) ++{ ++ int err; ++ struct notify_change_args args = { ++ .errp = &err, ++ .path = path, ++ .ia = ia, ++ .delegated_inode = delegated_inode ++ }; ++ ++ call_notify_change(&args); ++ ++ return err; ++} ++ ++int vfsub_sio_notify_change(struct path *path, struct iattr *ia, ++ struct inode **delegated_inode) ++{ ++ int err, wkq_err; ++ struct notify_change_args args = { ++ .errp = &err, ++ .path = path, ++ .ia = ia, ++ .delegated_inode = delegated_inode ++ }; ++ ++ 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; ++ struct inode **delegated_inode; ++}; ++ ++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) ++ && au_dcount(d) == 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 = NULL; ++ if (d_is_positive(d)) { ++ h_inode = d_inode(d); ++ ihold(h_inode); ++ } ++ ++ lockdep_off(); ++ *a->errp = vfs_unlink(a->dir, d, a->delegated_inode); ++ 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, ++ struct inode **delegated_inode, int force) ++{ ++ int err; ++ struct unlink_args args = { ++ .errp = &err, ++ .dir = dir, ++ .path = path, ++ .delegated_inode = delegated_inode ++ }; ++ ++ 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 -Nurp linux-5.4/fs/aufs/vfsub.h linux-5.4-aufs/fs/aufs/vfsub.h +--- linux-5.4/fs/aufs/vfsub.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/vfsub.h 2019-11-28 01:25:59.068925618 +0200 +@@ -0,0 +1,341 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * sub-routines for VFS ++ */ ++ ++#ifndef __AUFS_VFSUB_H__ ++#define __AUFS_VFSUB_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++#include "debug.h" ++ ++/* copied from linux/fs/internal.h */ ++/* todo: BAD approach!! */ ++extern void __mnt_drop_write(struct vfsmount *); ++extern struct file *alloc_empty_file(int, const struct cred *); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock subclass for lower inode */ ++/* default MAX_LOCKDEP_SUBCLASSES(8) is not enough */ ++/* reduce? gave up. */ ++enum { ++ AuLsc_I_Begin = I_MUTEX_PARENT2, /* 5 */ ++ 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) AuDebugOn(!inode_is_locked(i)) ++ ++/* ---------------------------------------------------------------------- */ ++ ++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); ++} ++ ++static inline int vfsub_native_ro(struct inode *inode) ++{ ++ return sb_rdonly(inode->i_sb) ++ || IS_RDONLY(inode) ++ /* || IS_APPEND(inode) */ ++ || IS_IMMUTABLE(inode); ++} ++ ++#ifdef CONFIG_AUFS_BR_FUSE ++int vfsub_test_mntns(struct vfsmount *mnt, struct super_block *h_sb); ++#else ++AuStubInt0(vfsub_test_mntns, struct vfsmount *mnt, struct super_block *h_sb); ++#endif ++ ++int vfsub_sync_filesystem(struct super_block *h_sb, int wait); ++ ++/* ---------------------------------------------------------------------- */ ++ ++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); ++struct au_branch; ++struct vfsub_aopen_args { ++ struct file *file; ++ unsigned int open_flag; ++ umode_t create_mode; ++ struct au_branch *br; ++}; ++int vfsub_atomic_open(struct inode *dir, struct dentry *dentry, ++ struct vfsub_aopen_args *args); ++int vfsub_kern_path(const char *name, unsigned int flags, struct path *path); ++ ++struct dentry *vfsub_lookup_one_len_unlocked(const char *name, ++ struct dentry *parent, int len); ++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(); ++} ++ ++#if 0 /* reserved */ ++static inline void vfsub_mnt_drop_write_file(struct file *file) ++{ ++ lockdep_off(); ++ mnt_drop_write_file(file); ++ lockdep_on(); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++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, struct inode **delegated_inode); ++int vfsub_rename(struct inode *src_hdir, struct dentry *src_dentry, ++ struct inode *hdir, struct path *path, ++ struct inode **delegated_inode, unsigned int flags); ++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_iterate_dir(struct file *file, struct dir_context *ctx); ++ ++static inline loff_t vfsub_f_size_read(struct file *file) ++{ ++ return i_size_read(file_inode(file)); ++} ++ ++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 int vfsub_file_execed(struct file *file) ++{ ++ /* todo: direct access f_flags */ ++ return !!(vfsub_file_flags(file) & __FMODE_EXEC); ++} ++ ++#if 0 /* reserved */ ++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*/ ++} ++#endif ++ ++#if 0 /* reserved */ ++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*/ ++} ++#endif ++ ++static inline int vfsub_update_time(struct inode *h_inode, ++ struct timespec64 *ts, int flags) ++{ ++ return update_time(h_inode, ts, flags); ++ /* no vfsub_update_h_iattr() since we don't have struct path */ ++} ++ ++#ifdef CONFIG_FS_POSIX_ACL ++static inline int vfsub_acl_chmod(struct inode *h_inode, umode_t h_mode) ++{ ++ int err; ++ ++ err = posix_acl_chmod(h_inode, h_mode); ++ if (err == -EOPNOTSUPP) ++ err = 0; ++ return err; ++} ++#else ++AuStubInt0(vfsub_acl_chmod, struct inode *h_inode, umode_t h_mode); ++#endif ++ ++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); ++ ++/* ++ * re-use branch fs's ioctl(FICLONE) while aufs itself doesn't support such ++ * ioctl. ++ */ ++static inline loff_t vfsub_clone_file_range(struct file *src, struct file *dst, ++ loff_t len) ++{ ++ loff_t err; ++ ++ lockdep_off(); ++ err = vfs_clone_file_range(src, 0, dst, 0, len, /*remap_flags*/0); ++ lockdep_on(); ++ ++ return err; ++} ++ ++/* copy_file_range(2) is a systemcall */ ++static inline ssize_t vfsub_copy_file_range(struct file *src, loff_t src_pos, ++ struct file *dst, loff_t dst_pos, ++ size_t len, unsigned int flags) ++{ ++ ssize_t ssz; ++ ++ lockdep_off(); ++ ssz = vfs_copy_file_range(src, src_pos, dst, dst_pos, len, flags); ++ lockdep_on(); ++ ++ return ssz; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++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; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++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, ++ struct inode **delegated_inode); ++int vfsub_notify_change(struct path *path, struct iattr *ia, ++ struct inode **delegated_inode); ++int vfsub_unlink(struct inode *dir, struct path *path, ++ struct inode **delegated_inode, int force); ++ ++static inline int vfsub_getattr(const struct path *path, struct kstat *st) ++{ ++ return vfs_getattr(path, st, STATX_BASIC_STATS, AT_STATX_SYNC_AS_STAT); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline int vfsub_setxattr(struct dentry *dentry, const char *name, ++ const void *value, size_t size, int flags) ++{ ++ int err; ++ ++ lockdep_off(); ++ err = vfs_setxattr(dentry, name, value, size, flags); ++ lockdep_on(); ++ ++ return err; ++} ++ ++static inline int vfsub_removexattr(struct dentry *dentry, const char *name) ++{ ++ int err; ++ ++ lockdep_off(); ++ err = vfs_removexattr(dentry, name); ++ lockdep_on(); ++ ++ return err; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_VFSUB_H__ */ +diff -Nurp linux-5.4/fs/aufs/whout.c linux-5.4-aufs/fs/aufs/whout.c +--- linux-5.4/fs/aufs/whout.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/whout.c 2019-11-28 01:25:59.069925618 +0200 +@@ -0,0 +1,1049 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * whiteout for logical deletion and opaque directory ++ */ ++ ++#include "aufs.h" ++ ++#define WH_MASK 0444 ++ ++/* ++ * 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, 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); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) { ++ if (err == -ENAMETOOLONG) ++ err = 0; ++ goto out; ++ } ++ ++ err = 0; ++ if (d_is_negative(wh_dentry)) ++ goto out_wh; /* success */ ++ ++ err = 1; ++ if (d_is_reg(wh_dentry)) ++ goto out_wh; /* success */ ++ ++ err = -EIO; ++ AuIOErr("%pd Invalid whiteout entry type 0%o.\n", ++ wh_dentry, d_inode(wh_dentry)->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) ++{ ++ int err; ++ struct inode *h_dir; ++ ++ h_dir = d_inode(h_dentry); ++ err = au_wh_test(h_dentry, &diropq_name, ++ 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); ++ if (IS_ERR(dentry) || d_is_negative(dentry)) ++ 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) ++ au_kfree_try_rcu(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 = au_br_mnt(br) ++ }; ++ struct inode *h_dir, *delegated; ++ struct dentry *h_parent; ++ ++ h_parent = h_dentry->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ 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() */ ++ delegated = NULL; ++ err = vfsub_rename(h_dir, h_dentry, h_dir, &h_path, &delegated, ++ /*flags*/0); ++ AuTraceErr(err); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ 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 err, force; ++ struct inode *delegated; ++ ++ /* ++ * 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(), d_inode(h_path->dentry)->i_uid); ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, h_path, &delegated, force); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ return err; ++} ++ ++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 = au_br_mnt(br) ++ }; ++ ++ 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 (d_is_reg(h_path.dentry)) ++ err = do_unlink_wh(d_inode(h_parent), &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; ++ struct inode *delegated; ++ ++ if (d_is_negative(whpath->dentry)) ++ return; ++ ++ if (isdir) ++ err = vfsub_rmdir(h_dir, whpath); ++ else { ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, whpath, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ } ++ if (unlikely(err)) ++ pr_warn("failed removing %pd (%d), ignored.\n", ++ whpath->dentry, err); ++} ++ ++static int test_linkable(struct dentry *h_root) ++{ ++ struct inode *h_dir = d_inode(h_root); ++ ++ if (h_dir->i_op->link) ++ return 0; ++ ++ pr_err("%pd (%s) doesn't support link(2), use noplink and rw+nolwh\n", ++ 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 (d_is_negative(path->dentry)) { ++ int mode = 0700; ++ ++ if (au_test_nfs(path->dentry->d_sb)) ++ mode |= 0111; ++ err = vfsub_mkdir(h_dir, path, mode); ++ } else if (d_is_dir(path->dentry)) ++ err = 0; ++ else ++ pr_err("unknown %pd exists\n", 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 message ++ * zero: success ++ * plus: error, caller should NOT print the message ++ */ ++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 = d_inode(h_root); ++ 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 = d_inode(h_root); ++ if (d_is_negative(base[AuBrWh_BASE].dentry)) { ++ h_path->dentry = base[AuBrWh_BASE].dentry; ++ err = vfsub_create(h_dir, h_path, WH_MASK, /*want_excl*/true); ++ } else if (d_is_reg(base[AuBrWh_BASE].dentry)) ++ err = 0; ++ else ++ pr_err("unknown %pd2 exists\n", 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 au_branch *br, struct super_block *sb) ++{ ++ int err, i; ++ const unsigned char do_plink ++ = !!au_opt_test(au_mntflags(sb), PLINK); ++ struct inode *h_dir; ++ struct path path = br->br_path; ++ struct dentry *h_root = path.dentry; ++ 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 = d_inode(h_root); ++ 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 %pd(%s)\n", ++ err, 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, *delegated; ++ 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 = d_inode(a->sb->s_root); ++ hdir = au_hi(dir, bindex); ++ h_root = au_h_dptr(a->sb->s_root, bindex); ++ AuDebugOn(h_root != au_br_dentry(a->br)); ++ ++ au_hn_inode_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) { ++ h_path.dentry = wbr->wbr_whbase; ++ h_path.mnt = au_br_mnt(a->br); ++ delegated = NULL; ++ err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated, ++ /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ } else { ++ pr_warn("%pd is moved, ignored\n", wbr->wbr_whbase); ++ err = 0; ++ } ++ dput(wbr->wbr_whbase); ++ wbr->wbr_whbase = NULL; ++ if (!err) ++ err = au_wh_init(a->br, a->sb); ++ wbr_wh_write_unlock(wbr); ++ au_hn_inode_unlock(hdir); ++ di_read_unlock(a->sb->s_root, AuLock_IR); ++ if (!err) ++ au_fhsm_wrote(a->sb, bindex, /*force*/0); ++ ++out: ++ if (wbr) ++ atomic_dec(&wbr->wbr_wh_running); ++ au_lcnt_dec(&a->br->br_count); ++ si_write_unlock(a->sb); ++ au_nwt_done(&au_sbi(a->sb)->si_nowait); ++ au_kfree_rcu(a); ++ 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; ++ au_lcnt_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); ++ au_lcnt_dec(&br->br_count); ++ au_kfree_rcu(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, *delegated; ++ ++ h_parent = wh->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ ++ br = au_sbr(sb, bindex); ++ h_path.mnt = au_br_mnt(br); ++ wbr = br->br_wbr; ++ wbr_wh_read_lock(wbr); ++ if (wbr->wbr_whbase) { ++ delegated = NULL; ++ err = vfsub_link(wbr->wbr_whbase, h_dir, &h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ 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); ++ if (!err) ++ au_fhsm_wrote(sb, bindex, /*force*/0); ++ ++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 = au_br_mnt(br) ++ }; ++ err = do_unlink_wh(au_h_iptr(d_inode(dentry), 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(d_inode(h_dentry), 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); ++ au_kfree_try_rcu(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) && d_is_negative(wh_dentry)) { ++ err = link_or_create_wh(sb, bindex, wh_dentry); ++ if (!err) { ++ au_set_dbwh(dentry, bindex); ++ au_fhsm_wrote(sb, bindex, /*force*/0); ++ } 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 *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(pos, head, wh_hash) { ++ if (pos->wh_bindex != bindex) ++ continue; ++ ++ str = &pos->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 = kzalloc(sizeof(*whtmp), gfp); ++ if (unlikely(!whtmp)) { ++ whtmp = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ ++ /* 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)) { ++ au_kfree_rcu(whtmp); ++ whtmp = ERR_PTR(err); ++ } ++ ++out: ++ return whtmp; ++} ++ ++void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp) ++{ ++ if (whtmp->br) ++ au_lcnt_dec(&whtmp->br->br_count); ++ dput(whtmp->wh_dentry); ++ iput(whtmp->dir); ++ au_nhash_wh_free(&whtmp->whlist); ++ au_kfree_rcu(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; ++ unsigned int h_nlink; ++ struct path h_tmp; ++ struct inode *wh_inode, *h_dir; ++ struct au_branch *br; ++ ++ h_dir = d_inode(wh_dentry->d_parent); /* dir inode is locked */ ++ IMustLock(h_dir); ++ ++ br = au_sbr(dir->i_sb, bindex); ++ wh_inode = d_inode(wh_dentry); ++ inode_lock_nested(wh_inode, 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; ++ } ++ inode_unlock(wh_inode); ++ ++ if (!err) { ++ h_tmp.dentry = wh_dentry; ++ h_tmp.mnt = au_br_mnt(br); ++ h_nlink = h_dir->i_nlink; ++ err = vfsub_rmdir(h_dir, &h_tmp); ++ /* some fs doesn't change the parent nlink in some cases */ ++ h_nlink -= h_dir->i_nlink; ++ } ++ ++ if (!err) { ++ if (au_ibtop(dir) == bindex) { ++ /* todo: dir->i_mutex is necessary */ ++ au_cpup_attr_timesizes(dir); ++ if (h_nlink) ++ vfsub_drop_nlink(dir); ++ } ++ return 0; /* success */ ++ } ++ ++ pr_warn("failed removing %pd(%d), ignored\n", 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 */ ++ /* inode_lock(a->dir); */ ++ 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 = d_inode(h_parent); ++ hdir = au_hi(a->dir, bindex); ++ err = vfsub_mnt_want_write(au_br_mnt(a->br)); ++ if (unlikely(err)) ++ goto out_mnt; ++ au_hn_inode_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 = au_whtmp_rmdir(a->dir, bindex, a->wh_dentry, &a->whlist); ++ au_hn_inode_unlock(hdir); ++ vfsub_mnt_drop_write(au_br_mnt(a->br)); ++ ++out_mnt: ++ dput(h_parent); ++ ii_write_unlock(a->dir); ++out: ++ /* inode_unlock(a->dir); */ ++ 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); ++ au_lcnt_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 %pd (%d), ignored\n", wh_dentry, wkq_err); ++ au_whtmp_rmdir_free(args); ++ } ++} +diff -Nurp linux-5.4/fs/aufs/whout.h linux-5.4-aufs/fs/aufs/whout.h +--- linux-5.4/fs/aufs/whout.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/whout.h 2019-11-28 01:25:59.069925618 +0200 +@@ -0,0 +1,73 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * 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); ++int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, int try_sio); ++int au_diropq_test(struct dentry *h_dentry); ++struct au_branch; ++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 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 -Nurp linux-5.4/fs/aufs/wkq.c linux-5.4-aufs/fs/aufs/wkq.c +--- linux-5.4/fs/aufs/wkq.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/wkq.c 2019-11-28 01:25:59.069925618 +0200 +@@ -0,0 +1,379 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * workqueue for asynchronous/super-io operations ++ * todo: try new credential 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; ++ ++#ifdef CONFIG_LOCKDEP ++ int dont_check; ++ struct held_lock **hlock; ++#endif ++ ++ struct completion *comp; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * Aufs passes some operations to the workqueue such as the internal copyup. ++ * This scheme looks rather unnatural for LOCKDEP debugging feature, since the ++ * job run by workqueue depends upon the locks acquired in the other task. ++ * Delegating a small operation to the workqueue, aufs passes its lockdep ++ * information too. And the job in the workqueue restores the info in order to ++ * pretend as if it acquired those locks. This is just to make LOCKDEP work ++ * correctly and expectedly. ++ */ ++ ++#ifndef CONFIG_LOCKDEP ++AuStubInt0(au_wkq_lockdep_alloc, struct au_wkinfo *wkinfo); ++AuStubVoid(au_wkq_lockdep_free, struct au_wkinfo *wkinfo); ++AuStubVoid(au_wkq_lockdep_pre, struct au_wkinfo *wkinfo); ++AuStubVoid(au_wkq_lockdep_post, struct au_wkinfo *wkinfo); ++AuStubVoid(au_wkq_lockdep_init, struct au_wkinfo *wkinfo); ++#else ++static void au_wkq_lockdep_init(struct au_wkinfo *wkinfo) ++{ ++ wkinfo->hlock = NULL; ++ wkinfo->dont_check = 0; ++} ++ ++/* ++ * 1: matched ++ * 0: unmatched ++ */ ++static int au_wkq_lockdep_test(struct lock_class_key *key, const char *name) ++{ ++ static DEFINE_SPINLOCK(spin); ++ static struct { ++ char *name; ++ struct lock_class_key *key; ++ } a[] = { ++ { .name = "&sbinfo->si_rwsem" }, ++ { .name = "&finfo->fi_rwsem" }, ++ { .name = "&dinfo->di_rwsem" }, ++ { .name = "&iinfo->ii_rwsem" } ++ }; ++ static int set; ++ int i; ++ ++ /* lockless read from 'set.' see below */ ++ if (set == ARRAY_SIZE(a)) { ++ for (i = 0; i < ARRAY_SIZE(a); i++) ++ if (a[i].key == key) ++ goto match; ++ goto unmatch; ++ } ++ ++ spin_lock(&spin); ++ if (set) ++ for (i = 0; i < ARRAY_SIZE(a); i++) ++ if (a[i].key == key) { ++ spin_unlock(&spin); ++ goto match; ++ } ++ for (i = 0; i < ARRAY_SIZE(a); i++) { ++ if (a[i].key) { ++ if (unlikely(a[i].key == key)) { /* rare but possible */ ++ spin_unlock(&spin); ++ goto match; ++ } else ++ continue; ++ } ++ if (strstr(a[i].name, name)) { ++ /* ++ * the order of these three lines is important for the ++ * lockless read above. ++ */ ++ a[i].key = key; ++ spin_unlock(&spin); ++ set++; ++ /* AuDbg("%d, %s\n", set, name); */ ++ goto match; ++ } ++ } ++ spin_unlock(&spin); ++ goto unmatch; ++ ++match: ++ return 1; ++unmatch: ++ return 0; ++} ++ ++static int au_wkq_lockdep_alloc(struct au_wkinfo *wkinfo) ++{ ++ int err, n; ++ struct task_struct *curr; ++ struct held_lock **hl, *held_locks, *p; ++ ++ err = 0; ++ curr = current; ++ wkinfo->dont_check = lockdep_recursing(curr); ++ if (wkinfo->dont_check) ++ goto out; ++ n = curr->lockdep_depth; ++ if (!n) ++ goto out; ++ ++ err = -ENOMEM; ++ wkinfo->hlock = kmalloc_array(n + 1, sizeof(*wkinfo->hlock), GFP_NOFS); ++ if (unlikely(!wkinfo->hlock)) ++ goto out; ++ ++ err = 0; ++#if 0 ++ if (0 && au_debug_test()) /* left for debugging */ ++ lockdep_print_held_locks(curr); ++#endif ++ held_locks = curr->held_locks; ++ hl = wkinfo->hlock; ++ while (n--) { ++ p = held_locks++; ++ if (au_wkq_lockdep_test(p->instance->key, p->instance->name)) ++ *hl++ = p; ++ } ++ *hl = NULL; ++ ++out: ++ return err; ++} ++ ++static void au_wkq_lockdep_free(struct au_wkinfo *wkinfo) ++{ ++ au_kfree_try_rcu(wkinfo->hlock); ++} ++ ++static void au_wkq_lockdep_pre(struct au_wkinfo *wkinfo) ++{ ++ struct held_lock *p, **hl = wkinfo->hlock; ++ int subclass; ++ ++ if (wkinfo->dont_check) ++ lockdep_off(); ++ if (!hl) ++ return; ++ while ((p = *hl++)) { /* assignment */ ++ subclass = lockdep_hlock_class(p)->subclass; ++ /* AuDbg("%s, %d\n", p->instance->name, subclass); */ ++ if (p->read) ++ rwsem_acquire_read(p->instance, subclass, 0, ++ /*p->acquire_ip*/_RET_IP_); ++ else ++ rwsem_acquire(p->instance, subclass, 0, ++ /*p->acquire_ip*/_RET_IP_); ++ } ++} ++ ++static void au_wkq_lockdep_post(struct au_wkinfo *wkinfo) ++{ ++ struct held_lock *p, **hl = wkinfo->hlock; ++ ++ if (wkinfo->dont_check) ++ lockdep_on(); ++ if (!hl) ++ return; ++ while ((p = *hl++)) /* assignment */ ++ rwsem_release(p->instance, 0, /*p->acquire_ip*/_RET_IP_); ++} ++#endif ++ ++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); ++ ++ au_wkq_lockdep_pre(wkinfo); ++ wkinfo->func(wkinfo->args); ++ au_wkq_lockdep_post(wkinfo); ++ if (au_ftest_wkq(wkinfo->flags, WAIT)) ++ complete(wkinfo->comp); ++ else { ++ kobject_put(wkinfo->kobj); ++ module_put(THIS_MODULE); /* todo: ?? */ ++ au_kfree_rcu(wkinfo); ++ } ++} ++ ++/* ++ * Since struct completion is large, try allocating it dynamically. ++ */ ++#if 1 /* 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) ++{ ++ au_kfree_rcu(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, unless silly-rename on NFS," ++ " due to a dead dir by UDBA," ++ " or async xino write?\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 (unlikely(err)) ++ goto out; ++ err = au_wkq_lockdep_alloc(&wkinfo); ++ if (unlikely(err)) ++ goto out_comp; ++ if (!err) { ++ au_wkq_run(&wkinfo); ++ /* no timeout, no interrupt */ ++ wait_for_completion(wkinfo.comp); ++ } ++ au_wkq_lockdep_free(&wkinfo); ++ ++out_comp: ++ au_wkq_comp_free(comp); ++out: ++ 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; ++ au_wkq_lockdep_init(wkinfo); ++ 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; ++ au_wkq = alloc_workqueue(AUFS_WKQ_NAME, 0, WQ_DFL_ACTIVE); ++ if (IS_ERR(au_wkq)) ++ err = PTR_ERR(au_wkq); ++ else if (!au_wkq) ++ err = -ENOMEM; ++ ++ return err; ++} +diff -Nurp linux-5.4/fs/aufs/wkq.h linux-5.4-aufs/fs/aufs/wkq.h +--- linux-5.4/fs/aufs/wkq.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/wkq.h 2019-11-28 01:25:59.069925618 +0200 +@@ -0,0 +1,76 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * workqueue for asynchronous/super-io operations ++ * todo: try new credentials management scheme ++ */ ++ ++#ifndef __AUFS_WKQ_H__ ++#define __AUFS_WKQ_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++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) ++ ++/* 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 -Nurp linux-5.4/fs/aufs/xattr.c linux-5.4-aufs/fs/aufs/xattr.c +--- linux-5.4/fs/aufs/xattr.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/xattr.c 2019-11-28 01:25:59.069925618 +0200 +@@ -0,0 +1,343 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2014-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * handling xattr functions ++ */ ++ ++#include ++#include ++#include ++#include "aufs.h" ++ ++static int au_xattr_ignore(int err, char *name, unsigned int ignore_flags) ++{ ++ if (!ignore_flags) ++ goto out; ++ switch (err) { ++ case -ENOMEM: ++ case -EDQUOT: ++ goto out; ++ } ++ ++ if ((ignore_flags & AuBrAttr_ICEX) == AuBrAttr_ICEX) { ++ err = 0; ++ goto out; ++ } ++ ++#define cmp(brattr, prefix) do { \ ++ if (!strncmp(name, XATTR_##prefix##_PREFIX, \ ++ XATTR_##prefix##_PREFIX_LEN)) { \ ++ if (ignore_flags & AuBrAttr_ICEX_##brattr) \ ++ err = 0; \ ++ goto out; \ ++ } \ ++ } while (0) ++ ++ cmp(SEC, SECURITY); ++ cmp(SYS, SYSTEM); ++ cmp(TR, TRUSTED); ++ cmp(USR, USER); ++#undef cmp ++ ++ if (ignore_flags & AuBrAttr_ICEX_OTH) ++ err = 0; ++ ++out: ++ return err; ++} ++ ++static const int au_xattr_out_of_list = AuBrAttr_ICEX_OTH << 1; ++ ++static int au_do_cpup_xattr(struct dentry *h_dst, struct dentry *h_src, ++ char *name, char **buf, unsigned int ignore_flags, ++ unsigned int verbose) ++{ ++ int err; ++ ssize_t ssz; ++ struct inode *h_idst; ++ ++ ssz = vfs_getxattr_alloc(h_src, name, buf, 0, GFP_NOFS); ++ err = ssz; ++ if (unlikely(err <= 0)) { ++ if (err == -ENODATA ++ || (err == -EOPNOTSUPP ++ && ((ignore_flags & au_xattr_out_of_list) ++ || (au_test_nfs_noacl(d_inode(h_src)) ++ && (!strcmp(name, XATTR_NAME_POSIX_ACL_ACCESS) ++ || !strcmp(name, ++ XATTR_NAME_POSIX_ACL_DEFAULT)))) ++ )) ++ err = 0; ++ if (err && (verbose || au_debug_test())) ++ pr_err("%s, err %d\n", name, err); ++ goto out; ++ } ++ ++ /* unlock it temporary */ ++ h_idst = d_inode(h_dst); ++ inode_unlock(h_idst); ++ err = vfsub_setxattr(h_dst, name, *buf, ssz, /*flags*/0); ++ inode_lock_nested(h_idst, AuLsc_I_CHILD2); ++ if (unlikely(err)) { ++ if (verbose || au_debug_test()) ++ pr_err("%s, err %d\n", name, err); ++ err = au_xattr_ignore(err, name, ignore_flags); ++ } ++ ++out: ++ return err; ++} ++ ++int au_cpup_xattr(struct dentry *h_dst, struct dentry *h_src, int ignore_flags, ++ unsigned int verbose) ++{ ++ int err, unlocked, acl_access, acl_default; ++ ssize_t ssz; ++ struct inode *h_isrc, *h_idst; ++ char *value, *p, *o, *e; ++ ++ /* try stopping to update the source inode while we are referencing */ ++ /* there should not be the parent-child relationship between them */ ++ h_isrc = d_inode(h_src); ++ h_idst = d_inode(h_dst); ++ inode_unlock(h_idst); ++ inode_lock_shared_nested(h_isrc, AuLsc_I_CHILD); ++ inode_lock_nested(h_idst, AuLsc_I_CHILD2); ++ unlocked = 0; ++ ++ /* some filesystems don't list POSIX ACL, for example tmpfs */ ++ ssz = vfs_listxattr(h_src, NULL, 0); ++ err = ssz; ++ if (unlikely(err < 0)) { ++ AuTraceErr(err); ++ if (err == -ENODATA ++ || err == -EOPNOTSUPP) ++ err = 0; /* ignore */ ++ goto out; ++ } ++ ++ err = 0; ++ p = NULL; ++ o = NULL; ++ if (ssz) { ++ err = -ENOMEM; ++ p = kmalloc(ssz, GFP_NOFS); ++ o = p; ++ if (unlikely(!p)) ++ goto out; ++ err = vfs_listxattr(h_src, p, ssz); ++ } ++ inode_unlock_shared(h_isrc); ++ unlocked = 1; ++ AuDbg("err %d, ssz %zd\n", err, ssz); ++ if (unlikely(err < 0)) ++ goto out_free; ++ ++ err = 0; ++ e = p + ssz; ++ value = NULL; ++ acl_access = 0; ++ acl_default = 0; ++ while (!err && p < e) { ++ acl_access |= !strncmp(p, XATTR_NAME_POSIX_ACL_ACCESS, ++ sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1); ++ acl_default |= !strncmp(p, XATTR_NAME_POSIX_ACL_DEFAULT, ++ sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) ++ - 1); ++ err = au_do_cpup_xattr(h_dst, h_src, p, &value, ignore_flags, ++ verbose); ++ p += strlen(p) + 1; ++ } ++ AuTraceErr(err); ++ ignore_flags |= au_xattr_out_of_list; ++ if (!err && !acl_access) { ++ err = au_do_cpup_xattr(h_dst, h_src, ++ XATTR_NAME_POSIX_ACL_ACCESS, &value, ++ ignore_flags, verbose); ++ AuTraceErr(err); ++ } ++ if (!err && !acl_default) { ++ err = au_do_cpup_xattr(h_dst, h_src, ++ XATTR_NAME_POSIX_ACL_DEFAULT, &value, ++ ignore_flags, verbose); ++ AuTraceErr(err); ++ } ++ ++ au_kfree_try_rcu(value); ++ ++out_free: ++ au_kfree_try_rcu(o); ++out: ++ if (!unlocked) ++ inode_unlock_shared(h_isrc); ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_smack_reentering(struct super_block *sb) ++{ ++#if IS_ENABLED(CONFIG_SECURITY_SMACK) ++ /* ++ * as a part of lookup, smack_d_instantiate() is called, and it calls ++ * i_op->getxattr(). ouch. ++ */ ++ return si_pid_test(sb); ++#else ++ return 0; ++#endif ++} ++ ++enum { ++ AU_XATTR_LIST, ++ AU_XATTR_GET ++}; ++ ++struct au_lgxattr { ++ int type; ++ union { ++ struct { ++ char *list; ++ size_t size; ++ } list; ++ struct { ++ const char *name; ++ void *value; ++ size_t size; ++ } get; ++ } u; ++}; ++ ++static ssize_t au_lgxattr(struct dentry *dentry, struct au_lgxattr *arg) ++{ ++ ssize_t err; ++ int reenter; ++ struct path h_path; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ reenter = au_smack_reentering(sb); ++ if (!reenter) { ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out; ++ } ++ err = au_h_path_getattr(dentry, /*force*/1, &h_path, reenter); ++ if (unlikely(err)) ++ goto out_si; ++ if (unlikely(!h_path.dentry)) ++ /* illegally overlapped or something */ ++ goto out_di; /* pretending success */ ++ ++ /* always topmost entry only */ ++ switch (arg->type) { ++ case AU_XATTR_LIST: ++ err = vfs_listxattr(h_path.dentry, ++ arg->u.list.list, arg->u.list.size); ++ break; ++ case AU_XATTR_GET: ++ AuDebugOn(d_is_negative(h_path.dentry)); ++ err = vfs_getxattr(h_path.dentry, ++ arg->u.get.name, arg->u.get.value, ++ arg->u.get.size); ++ break; ++ } ++ ++out_di: ++ if (!reenter) ++ di_read_unlock(dentry, AuLock_IR); ++out_si: ++ if (!reenter) ++ si_read_unlock(sb); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++ssize_t aufs_listxattr(struct dentry *dentry, char *list, size_t size) ++{ ++ struct au_lgxattr arg = { ++ .type = AU_XATTR_LIST, ++ .u.list = { ++ .list = list, ++ .size = size ++ }, ++ }; ++ ++ return au_lgxattr(dentry, &arg); ++} ++ ++static ssize_t au_getxattr(struct dentry *dentry, ++ struct inode *inode __maybe_unused, ++ const char *name, void *value, size_t size) ++{ ++ struct au_lgxattr arg = { ++ .type = AU_XATTR_GET, ++ .u.get = { ++ .name = name, ++ .value = value, ++ .size = size ++ }, ++ }; ++ ++ return au_lgxattr(dentry, &arg); ++} ++ ++static int au_setxattr(struct dentry *dentry, struct inode *inode, ++ const char *name, const void *value, size_t size, ++ int flags) ++{ ++ struct au_sxattr arg = { ++ .type = AU_XATTR_SET, ++ .u.set = { ++ .name = name, ++ .value = value, ++ .size = size, ++ .flags = flags ++ }, ++ }; ++ ++ return au_sxattr(dentry, inode, &arg); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_xattr_get(const struct xattr_handler *handler, ++ struct dentry *dentry, struct inode *inode, ++ const char *name, void *buffer, size_t size) ++{ ++ return au_getxattr(dentry, inode, name, buffer, size); ++} ++ ++static int au_xattr_set(const struct xattr_handler *handler, ++ struct dentry *dentry, struct inode *inode, ++ const char *name, const void *value, size_t size, ++ int flags) ++{ ++ return au_setxattr(dentry, inode, name, value, size, flags); ++} ++ ++static const struct xattr_handler au_xattr_handler = { ++ .name = "", ++ .prefix = "", ++ .get = au_xattr_get, ++ .set = au_xattr_set ++}; ++ ++static const struct xattr_handler *au_xattr_handlers[] = { ++#ifdef CONFIG_FS_POSIX_ACL ++ &posix_acl_access_xattr_handler, ++ &posix_acl_default_xattr_handler, ++#endif ++ &au_xattr_handler, /* must be last */ ++ NULL ++}; ++ ++void au_xattr_init(struct super_block *sb) ++{ ++ sb->s_xattr = au_xattr_handlers; ++} +diff -Nurp linux-5.4/fs/aufs/xino.c linux-5.4-aufs/fs/aufs/xino.c +--- linux-5.4/fs/aufs/xino.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/xino.c 2019-11-28 01:25:59.069925618 +0200 +@@ -0,0 +1,1952 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * external inode number translation table and bitmap ++ * ++ * things to consider ++ * - the lifetime ++ * + au_xino object ++ * + XINO files (xino, xib, xigen) ++ * + dynamic debugfs entries (xiN) ++ * + static debugfs entries (xib, xigen) ++ * + static sysfs entry (xi_path) ++ * - several entry points to handle them. ++ * + mount(2) without xino option (default) ++ * + mount(2) with xino option ++ * + mount(2) with noxino option ++ * + umount(2) ++ * + remount with add/del branches ++ * + remount with xino/noxino options ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++static aufs_bindex_t sbr_find_shared(struct super_block *sb, aufs_bindex_t btop, ++ aufs_bindex_t bbot, ++ struct super_block *h_sb) ++{ ++ /* todo: try binary-search if the branches are many */ ++ for (; btop <= bbot; btop++) ++ if (h_sb == au_sbr_sb(sb, btop)) ++ return btop; ++ return -1; ++} ++ ++/* ++ * find another branch who is on the same filesystem of the specified ++ * branch{@btgt}. search until @bbot. ++ */ ++static aufs_bindex_t is_sb_shared(struct super_block *sb, aufs_bindex_t btgt, ++ aufs_bindex_t bbot) ++{ ++ aufs_bindex_t bindex; ++ struct super_block *tgt_sb; ++ ++ tgt_sb = au_sbr_sb(sb, btgt); ++ bindex = sbr_find_shared(sb, /*btop*/0, btgt - 1, tgt_sb); ++ if (bindex < 0) ++ bindex = sbr_find_shared(sb, btgt + 1, bbot, tgt_sb); ++ ++ return bindex; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * stop unnecessary notify events at creating xino files ++ */ ++ ++aufs_bindex_t au_xi_root(struct super_block *sb, struct dentry *dentry) ++{ ++ aufs_bindex_t bfound, bindex, bbot; ++ struct dentry *parent; ++ struct au_branch *br; ++ ++ bfound = -1; ++ parent = dentry->d_parent; /* safe d_parent access */ ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_dentry(br) == parent) { ++ bfound = bindex; ++ break; ++ } ++ } ++ ++ AuDbg("bfound b%d\n", bfound); ++ return bfound; ++} ++ ++struct au_xino_lock_dir { ++ struct au_hinode *hdir; ++ struct dentry *parent; ++ struct inode *dir; ++}; ++ ++static struct dentry *au_dget_parent_lock(struct dentry *dentry, ++ unsigned int lsc) ++{ ++ struct dentry *parent; ++ struct inode *dir; ++ ++ parent = dget_parent(dentry); ++ dir = d_inode(parent); ++ inode_lock_nested(dir, lsc); ++#if 0 /* it should not happen */ ++ spin_lock(&dentry->d_lock); ++ if (unlikely(dentry->d_parent != parent)) { ++ spin_unlock(&dentry->d_lock); ++ inode_unlock(dir); ++ dput(parent); ++ parent = NULL; ++ goto out; ++ } ++ spin_unlock(&dentry->d_lock); ++ ++out: ++#endif ++ return parent; ++} ++ ++static void au_xino_lock_dir(struct super_block *sb, struct path *xipath, ++ struct au_xino_lock_dir *ldir) ++{ ++ aufs_bindex_t bindex; ++ ++ ldir->hdir = NULL; ++ bindex = au_xi_root(sb, xipath->dentry); ++ if (bindex >= 0) { ++ /* rw branch root */ ++ ldir->hdir = au_hi(d_inode(sb->s_root), bindex); ++ au_hn_inode_lock_nested(ldir->hdir, AuLsc_I_PARENT); ++ } else { ++ /* other */ ++ ldir->parent = au_dget_parent_lock(xipath->dentry, ++ AuLsc_I_PARENT); ++ ldir->dir = d_inode(ldir->parent); ++ } ++} ++ ++static void au_xino_unlock_dir(struct au_xino_lock_dir *ldir) ++{ ++ if (ldir->hdir) ++ au_hn_inode_unlock(ldir->hdir); ++ else { ++ inode_unlock(ldir->dir); ++ dput(ldir->parent); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create and set a new xino file ++ */ ++struct file *au_xino_create(struct super_block *sb, char *fpath, int silent, ++ int wbrtop) ++{ ++ struct file *file; ++ struct dentry *h_parent, *d; ++ struct inode *h_dir, *inode; ++ int err; ++ static DEFINE_MUTEX(mtx); ++ ++ /* ++ * 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. ++ */ ++ if (!wbrtop) ++ mutex_lock(&mtx); ++ file = vfsub_filp_open(fpath, O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE ++ /* | __FMODE_NONOTIFY */, ++ 0666); ++ if (IS_ERR(file)) { ++ if (!wbrtop) ++ mutex_unlock(&mtx); ++ if (!silent) ++ pr_err("open %s(%ld)\n", fpath, PTR_ERR(file)); ++ return file; ++ } ++ ++ /* keep file count */ ++ err = 0; ++ d = file->f_path.dentry; ++ h_parent = au_dget_parent_lock(d, AuLsc_I_PARENT); ++ if (!wbrtop) ++ mutex_unlock(&mtx); ++ /* mnt_want_write() is unnecessary here */ ++ h_dir = d_inode(h_parent); ++ inode = file_inode(file); ++ /* no delegation since it is just created */ ++ if (inode->i_nlink) ++ err = vfsub_unlink(h_dir, &file->f_path, /*delegated*/NULL, ++ /*force*/0); ++ inode_unlock(h_dir); ++ dput(h_parent); ++ if (unlikely(err)) { ++ if (!silent) ++ pr_err("unlink %s(%d)\n", fpath, err); ++ goto out; ++ } ++ ++ err = -EINVAL; ++ if (unlikely(sb == d->d_sb)) { ++ if (!silent) ++ pr_err("%s must be outside\n", fpath); ++ goto out; ++ } ++ if (unlikely(au_test_fs_bad_xino(d->d_sb))) { ++ if (!silent) ++ pr_err("xino doesn't support %s(%s)\n", ++ fpath, au_sbtype(d->d_sb)); ++ goto out; ++ } ++ return file; /* success */ ++ ++out: ++ fput(file); ++ file = ERR_PTR(err); ++ return file; ++} ++ ++/* ++ * create a new xinofile at the same place/path as @base. ++ */ ++struct file *au_xino_create2(struct super_block *sb, struct path *base, ++ struct file *copy_src) ++{ ++ struct file *file; ++ struct dentry *dentry, *parent; ++ struct inode *dir, *delegated; ++ struct qstr *name; ++ struct path path; ++ int err, do_unlock; ++ struct au_xino_lock_dir ldir; ++ ++ do_unlock = 1; ++ au_xino_lock_dir(sb, base, &ldir); ++ dentry = base->dentry; ++ parent = dentry->d_parent; /* dir inode is locked */ ++ dir = d_inode(parent); ++ IMustLock(dir); ++ ++ name = &dentry->d_name; ++ path.dentry = vfsub_lookup_one_len(name->name, parent, name->len); ++ if (IS_ERR(path.dentry)) { ++ file = (void *)path.dentry; ++ pr_err("%pd lookup err %ld\n", dentry, PTR_ERR(path.dentry)); ++ goto out; ++ } ++ ++ /* no need to mnt_want_write() since we call dentry_open() later */ ++ err = vfs_create(dir, path.dentry, 0666, NULL); ++ if (unlikely(err)) { ++ file = ERR_PTR(err); ++ pr_err("%pd create err %d\n", dentry, err); ++ goto out_dput; ++ } ++ ++ path.mnt = base->mnt; ++ file = vfsub_dentry_open(&path, ++ O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE ++ /* | __FMODE_NONOTIFY */); ++ if (IS_ERR(file)) { ++ pr_err("%pd open err %ld\n", dentry, PTR_ERR(file)); ++ goto out_dput; ++ } ++ ++ delegated = NULL; ++ err = vfsub_unlink(dir, &file->f_path, &delegated, /*force*/0); ++ au_xino_unlock_dir(&ldir); ++ do_unlock = 0; ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) { ++ pr_err("%pd unlink err %d\n", dentry, err); ++ goto out_fput; ++ } ++ ++ if (copy_src) { ++ /* no one can touch copy_src xino */ ++ err = au_copy_file(file, copy_src, vfsub_f_size_read(copy_src)); ++ if (unlikely(err)) { ++ pr_err("%pd copy err %d\n", dentry, err); ++ goto out_fput; ++ } ++ } ++ goto out_dput; /* success */ ++ ++out_fput: ++ fput(file); ++ file = ERR_PTR(err); ++out_dput: ++ dput(path.dentry); ++out: ++ if (do_unlock) ++ au_xino_unlock_dir(&ldir); ++ return file; ++} ++ ++struct file *au_xino_file1(struct au_xino *xi) ++{ ++ struct file *file; ++ unsigned int u, nfile; ++ ++ file = NULL; ++ nfile = xi->xi_nfile; ++ for (u = 0; u < nfile; u++) { ++ file = xi->xi_file[u]; ++ if (file) ++ break; ++ } ++ ++ return file; ++} ++ ++static int au_xino_file_set(struct au_xino *xi, int idx, struct file *file) ++{ ++ int err; ++ struct file *f; ++ void *p; ++ ++ if (file) ++ get_file(file); ++ ++ err = 0; ++ f = NULL; ++ if (idx < xi->xi_nfile) { ++ f = xi->xi_file[idx]; ++ if (f) ++ fput(f); ++ } else { ++ p = au_kzrealloc(xi->xi_file, ++ sizeof(*xi->xi_file) * xi->xi_nfile, ++ sizeof(*xi->xi_file) * (idx + 1), ++ GFP_NOFS, /*may_shrink*/0); ++ if (p) { ++ MtxMustLock(&xi->xi_mtx); ++ xi->xi_file = p; ++ xi->xi_nfile = idx + 1; ++ } else { ++ err = -ENOMEM; ++ if (file) ++ fput(file); ++ goto out; ++ } ++ } ++ xi->xi_file[idx] = file; ++ ++out: ++ return err; ++} ++ ++/* ++ * if @xinew->xi is not set, then create new xigen file. ++ */ ++struct file *au_xi_new(struct super_block *sb, struct au_xi_new *xinew) ++{ ++ struct file *file; ++ int err; ++ ++ SiMustAnyLock(sb); ++ ++ file = au_xino_create2(sb, xinew->base, xinew->copy_src); ++ if (IS_ERR(file)) { ++ err = PTR_ERR(file); ++ pr_err("%s[%d], err %d\n", ++ xinew->xi ? "xino" : "xigen", ++ xinew->idx, err); ++ goto out; ++ } ++ ++ if (xinew->xi) ++ err = au_xino_file_set(xinew->xi, xinew->idx, file); ++ else { ++ BUG(); ++ /* todo: make xigen file an array */ ++ /* err = au_xigen_file_set(sb, xinew->idx, file); */ ++ } ++ fput(file); ++ if (unlikely(err)) ++ file = ERR_PTR(err); ++ ++out: ++ return file; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * truncate xino files ++ */ ++static int au_xino_do_trunc(struct super_block *sb, aufs_bindex_t bindex, ++ int idx, struct kstatfs *st) ++{ ++ int err; ++ blkcnt_t blocks; ++ struct file *file, *new_xino; ++ struct au_xi_new xinew = { ++ .idx = idx ++ }; ++ ++ err = 0; ++ xinew.xi = au_sbr(sb, bindex)->br_xino; ++ file = au_xino_file(xinew.xi, idx); ++ if (!file) ++ goto out; ++ ++ xinew.base = &file->f_path; ++ err = vfs_statfs(xinew.base, st); ++ if (unlikely(err)) { ++ AuErr1("statfs err %d, ignored\n", err); ++ err = 0; ++ goto out; ++ } ++ ++ blocks = file_inode(file)->i_blocks; ++ pr_info("begin truncating xino(b%d-%d), ib%llu, %llu/%llu free blks\n", ++ bindex, idx, (u64)blocks, st->f_bfree, st->f_blocks); ++ ++ xinew.copy_src = file; ++ new_xino = au_xi_new(sb, &xinew); ++ if (IS_ERR(new_xino)) { ++ err = PTR_ERR(new_xino); ++ pr_err("xino(b%d-%d), err %d, ignored\n", bindex, idx, err); ++ goto out; ++ } ++ ++ err = vfs_statfs(&new_xino->f_path, st); ++ if (!err) ++ pr_info("end truncating xino(b%d-%d), ib%llu, %llu/%llu free blks\n", ++ bindex, idx, (u64)file_inode(new_xino)->i_blocks, ++ st->f_bfree, st->f_blocks); ++ else { ++ AuErr1("statfs err %d, ignored\n", err); ++ err = 0; ++ } ++ ++out: ++ return err; ++} ++ ++int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex, int idx_begin) ++{ ++ int err, i; ++ unsigned long jiffy; ++ aufs_bindex_t bbot; ++ struct kstatfs *st; ++ struct au_branch *br; ++ struct au_xino *xi; ++ ++ err = -ENOMEM; ++ st = kmalloc(sizeof(*st), GFP_NOFS); ++ if (unlikely(!st)) ++ goto out; ++ ++ err = -EINVAL; ++ bbot = au_sbbot(sb); ++ if (unlikely(bindex < 0 || bbot < bindex)) ++ goto out_st; ++ ++ err = 0; ++ jiffy = jiffies; ++ br = au_sbr(sb, bindex); ++ xi = br->br_xino; ++ for (i = idx_begin; !err && i < xi->xi_nfile; i++) ++ err = au_xino_do_trunc(sb, bindex, i, st); ++ if (!err) ++ au_sbi(sb)->si_xino_jiffy = jiffy; ++ ++out_st: ++ au_kfree_rcu(st); ++out: ++ return err; ++} ++ ++struct xino_do_trunc_args { ++ struct super_block *sb; ++ struct au_branch *br; ++ int idx; ++}; ++ ++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, idx; ++ aufs_bindex_t bindex; ++ ++ err = 0; ++ sb = args->sb; ++ dir = d_inode(sb->s_root); ++ br = args->br; ++ idx = args->idx; ++ ++ si_noflush_write_lock(sb); ++ ii_read_lock_parent(dir); ++ bindex = au_br_index(sb, br->br_id); ++ err = au_xino_trunc(sb, bindex, idx); ++ ii_read_unlock(dir); ++ if (unlikely(err)) ++ pr_warn("err b%d, (%d)\n", bindex, err); ++ atomic_dec(&br->br_xino->xi_truncating); ++ au_lcnt_dec(&br->br_count); ++ si_write_unlock(sb); ++ au_nwt_done(&au_sbi(sb)->si_nowait); ++ au_kfree_rcu(args); ++} ++ ++/* ++ * returns the index in the xi_file array whose corresponding file is necessary ++ * to truncate, or -1 which means no need to truncate. ++ */ ++static int xino_trunc_test(struct super_block *sb, struct au_branch *br) ++{ ++ int err; ++ unsigned int u; ++ struct kstatfs st; ++ struct au_sbinfo *sbinfo; ++ struct au_xino *xi; ++ struct file *file; ++ ++ /* todo: si_xino_expire and the ratio should be customizable */ ++ sbinfo = au_sbi(sb); ++ if (time_before(jiffies, ++ sbinfo->si_xino_jiffy + sbinfo->si_xino_expire)) ++ return -1; ++ ++ /* truncation border */ ++ xi = br->br_xino; ++ for (u = 0; u < xi->xi_nfile; u++) { ++ file = au_xino_file(xi, u); ++ if (!file) ++ continue; ++ ++ err = vfs_statfs(&file->f_path, &st); ++ if (unlikely(err)) { ++ AuErr1("statfs err %d, ignored\n", err); ++ return -1; ++ } ++ if (div64_u64(st.f_bfree * 100, st.f_blocks) ++ >= AUFS_XINO_DEF_TRUNC) ++ return u; ++ } ++ ++ return -1; ++} ++ ++static void xino_try_trunc(struct super_block *sb, struct au_branch *br) ++{ ++ int idx; ++ struct xino_do_trunc_args *args; ++ int wkq_err; ++ ++ idx = xino_trunc_test(sb, br); ++ if (idx < 0) ++ return; ++ ++ if (atomic_inc_return(&br->br_xino->xi_truncating) > 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; ++ } ++ ++ au_lcnt_inc(&br->br_count); ++ args->sb = sb; ++ args->br = br; ++ args->idx = idx; ++ wkq_err = au_wkq_nowait(xino_do_trunc, args, sb, /*flags*/0); ++ if (!wkq_err) ++ return; /* success */ ++ ++ pr_err("wkq %d\n", wkq_err); ++ au_lcnt_dec(&br->br_count); ++ au_kfree_rcu(args); ++ ++out: ++ atomic_dec(&br->br_xino->xi_truncating); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_xi_calc { ++ int idx; ++ loff_t pos; ++}; ++ ++static void au_xi_calc(struct super_block *sb, ino_t h_ino, ++ struct au_xi_calc *calc) ++{ ++ loff_t maxent; ++ ++ maxent = au_xi_maxent(sb); ++ calc->idx = div64_u64_rem(h_ino, maxent, &calc->pos); ++ calc->pos *= sizeof(ino_t); ++} ++ ++static int au_xino_do_new_async(struct super_block *sb, struct au_branch *br, ++ struct au_xi_calc *calc) ++{ ++ int err; ++ struct file *file; ++ struct au_xino *xi = br->br_xino; ++ struct au_xi_new xinew = { ++ .xi = xi ++ }; ++ ++ SiMustAnyLock(sb); ++ ++ err = 0; ++ if (!xi) ++ goto out; ++ ++ mutex_lock(&xi->xi_mtx); ++ file = au_xino_file(xi, calc->idx); ++ if (file) ++ goto out_mtx; ++ ++ file = au_xino_file(xi, /*idx*/-1); ++ AuDebugOn(!file); ++ xinew.idx = calc->idx; ++ xinew.base = &file->f_path; ++ /* xinew.copy_src = NULL; */ ++ file = au_xi_new(sb, &xinew); ++ if (IS_ERR(file)) ++ err = PTR_ERR(file); ++ ++out_mtx: ++ mutex_unlock(&xi->xi_mtx); ++out: ++ return err; ++} ++ ++struct au_xino_do_new_async_args { ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_xi_calc calc; ++ ino_t ino; ++}; ++ ++struct au_xi_writing { ++ struct hlist_bl_node node; ++ ino_t h_ino, ino; ++}; ++ ++static int au_xino_do_write(vfs_writef_t write, struct file *file, ++ struct au_xi_calc *calc, ino_t ino); ++ ++static void au_xino_call_do_new_async(void *args) ++{ ++ struct au_xino_do_new_async_args *a = args; ++ struct au_branch *br; ++ struct super_block *sb; ++ struct au_sbinfo *sbi; ++ struct inode *root; ++ struct file *file; ++ struct au_xi_writing *del, *p; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ int err; ++ ++ br = a->br; ++ sb = a->sb; ++ sbi = au_sbi(sb); ++ si_noflush_read_lock(sb); ++ root = d_inode(sb->s_root); ++ ii_read_lock_child(root); ++ err = au_xino_do_new_async(sb, br, &a->calc); ++ if (unlikely(err)) { ++ AuIOErr("err %d\n", err); ++ goto out; ++ } ++ ++ file = au_xino_file(br->br_xino, a->calc.idx); ++ AuDebugOn(!file); ++ err = au_xino_do_write(sbi->si_xwrite, file, &a->calc, a->ino); ++ if (unlikely(err)) { ++ AuIOErr("err %d\n", err); ++ goto out; ++ } ++ ++ del = NULL; ++ hbl = &br->br_xino->xi_writing; ++ hlist_bl_lock(hbl); ++ au_hbl_for_each(pos, hbl) { ++ p = container_of(pos, struct au_xi_writing, node); ++ if (p->ino == a->ino) { ++ del = p; ++ hlist_bl_del(&p->node); ++ break; ++ } ++ } ++ hlist_bl_unlock(hbl); ++ au_kfree_rcu(del); ++ ++out: ++ au_lcnt_dec(&br->br_count); ++ ii_read_unlock(root); ++ si_read_unlock(sb); ++ au_nwt_done(&sbi->si_nowait); ++ au_kfree_rcu(a); ++} ++ ++/* ++ * create a new xino file asynchronously ++ */ ++static int au_xino_new_async(struct super_block *sb, struct au_branch *br, ++ struct au_xi_calc *calc, ino_t ino) ++{ ++ int err; ++ struct au_xino_do_new_async_args *arg; ++ ++ err = -ENOMEM; ++ arg = kmalloc(sizeof(*arg), GFP_NOFS); ++ if (unlikely(!arg)) ++ goto out; ++ ++ arg->sb = sb; ++ arg->br = br; ++ arg->calc = *calc; ++ arg->ino = ino; ++ au_lcnt_inc(&br->br_count); ++ err = au_wkq_nowait(au_xino_call_do_new_async, arg, sb, AuWkq_NEST); ++ if (unlikely(err)) { ++ pr_err("wkq %d\n", err); ++ au_lcnt_dec(&br->br_count); ++ au_kfree_rcu(arg); ++ } ++ ++out: ++ return err; ++} ++ ++/* ++ * read @ino from xinofile for the specified branch{@sb, @bindex} ++ * at the position of @h_ino. ++ */ ++int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t *ino) ++{ ++ int err; ++ ssize_t sz; ++ struct au_xi_calc calc; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ struct au_xino *xi; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_xi_writing *p; ++ ++ *ino = 0; ++ if (!au_opt_test(au_mntflags(sb), XINO)) ++ return 0; /* no xino */ ++ ++ err = 0; ++ au_xi_calc(sb, h_ino, &calc); ++ xi = au_sbr(sb, bindex)->br_xino; ++ file = au_xino_file(xi, calc.idx); ++ if (!file) { ++ hbl = &xi->xi_writing; ++ hlist_bl_lock(hbl); ++ au_hbl_for_each(pos, hbl) { ++ p = container_of(pos, struct au_xi_writing, node); ++ if (p->h_ino == h_ino) { ++ AuDbg("hi%llu, i%llu, found\n", ++ (u64)p->h_ino, (u64)p->ino); ++ *ino = p->ino; ++ break; ++ } ++ } ++ hlist_bl_unlock(hbl); ++ return 0; ++ } else if (vfsub_f_size_read(file) < calc.pos + sizeof(*ino)) ++ return 0; /* no xino */ ++ ++ sbinfo = au_sbi(sb); ++ sz = xino_fread(sbinfo->si_xread, file, ino, sizeof(*ino), &calc.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; ++} ++ ++static int au_xino_do_write(vfs_writef_t write, struct file *file, ++ struct au_xi_calc *calc, ino_t ino) ++{ ++ ssize_t sz; ++ ++ sz = xino_fwrite(write, file, &ino, sizeof(ino), &calc->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_xi_calc calc; ++ struct file *file; ++ struct au_branch *br; ++ struct au_xino *xi; ++ struct au_xi_writing *p; ++ ++ SiMustAnyLock(sb); ++ ++ mnt_flags = au_mntflags(sb); ++ if (!au_opt_test(mnt_flags, XINO)) ++ return 0; ++ ++ au_xi_calc(sb, h_ino, &calc); ++ br = au_sbr(sb, bindex); ++ xi = br->br_xino; ++ file = au_xino_file(xi, calc.idx); ++ if (!file) { ++ /* store the inum pair into the list */ ++ p = kmalloc(sizeof(*p), GFP_NOFS | __GFP_NOFAIL); ++ p->h_ino = h_ino; ++ p->ino = ino; ++ au_hbl_add(&p->node, &xi->xi_writing); ++ ++ /* create and write a new xino file asynchronously */ ++ err = au_xino_new_async(sb, br, &calc, ino); ++ if (!err) ++ return 0; /* success */ ++ goto out; ++ } ++ ++ err = au_xino_do_write(au_sbi(sb)->si_xwrite, file, &calc, ino); ++ if (!err) { ++ br = au_sbr(sb, bindex); ++ if (au_opt_test(mnt_flags, TRUNC_XINO) ++ && au_test_fs_trunc_xino(au_br_sb(br))) ++ xino_try_trunc(sb, br); ++ return 0; /* success */ ++ } ++ ++out: ++ AuIOErr("write failed (%d)\n", err); ++ return -EIO; ++} ++ ++static ssize_t xino_fread_wkq(vfs_readf_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos); ++ ++/* todo: unnecessary to support mmap_sem since kernel-space? */ ++ssize_t xino_fread(vfs_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; ++ int i; ++ const int prevent_endless = 10; ++ ++ i = 0; ++ buf.k = kbuf; ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ do { ++ err = func(file, buf.u, size, pos); ++ if (err == -EINTR ++ && !au_wkq_test() ++ && fatal_signal_pending(current)) { ++ set_fs(oldfs); ++ err = xino_fread_wkq(func, file, kbuf, size, pos); ++ BUG_ON(err == -EINTR); ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ } ++ } while (i++ < prevent_endless ++ && (err == -EAGAIN || err == -EINTR)); ++ set_fs(oldfs); ++ ++#if 0 /* reserved for future use */ ++ if (err > 0) ++ fsnotify_access(file->f_path.dentry); ++#endif ++ ++ return err; ++} ++ ++struct xino_fread_args { ++ ssize_t *errp; ++ vfs_readf_t func; ++ struct file *file; ++ void *buf; ++ size_t size; ++ loff_t *pos; ++}; ++ ++static void call_xino_fread(void *args) ++{ ++ struct xino_fread_args *a = args; ++ *a->errp = xino_fread(a->func, a->file, a->buf, a->size, a->pos); ++} ++ ++static ssize_t xino_fread_wkq(vfs_readf_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos) ++{ ++ ssize_t err; ++ int wkq_err; ++ struct xino_fread_args args = { ++ .errp = &err, ++ .func = func, ++ .file = file, ++ .buf = buf, ++ .size = size, ++ .pos = pos ++ }; ++ ++ wkq_err = au_wkq_wait(call_xino_fread, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ ++ return err; ++} ++ ++static ssize_t xino_fwrite_wkq(vfs_writef_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos); ++ ++static ssize_t do_xino_fwrite(vfs_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; ++ int i; ++ const int prevent_endless = 10; ++ ++ i = 0; ++ buf.k = kbuf; ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ do { ++ err = func(file, buf.u, size, pos); ++ if (err == -EINTR ++ && !au_wkq_test() ++ && fatal_signal_pending(current)) { ++ set_fs(oldfs); ++ err = xino_fwrite_wkq(func, file, kbuf, size, pos); ++ BUG_ON(err == -EINTR); ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ } ++ } while (i++ < prevent_endless ++ && (err == -EAGAIN || err == -EINTR)); ++ set_fs(oldfs); ++ ++#if 0 /* reserved for future use */ ++ if (err > 0) ++ fsnotify_modify(file->f_path.dentry); ++#endif ++ ++ return err; ++} ++ ++struct do_xino_fwrite_args { ++ ssize_t *errp; ++ vfs_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); ++} ++ ++static ssize_t xino_fwrite_wkq(vfs_writef_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos) ++{ ++ ssize_t err; ++ int wkq_err; ++ struct do_xino_fwrite_args args = { ++ .errp = &err, ++ .func = func, ++ .file = file, ++ .buf = buf, ++ .size = size, ++ .pos = pos ++ }; ++ ++ /* ++ * it breaks RLIMIT_FSIZE and normal user's limit, ++ * users should care about quota and real 'filesystem full.' ++ */ ++ wkq_err = au_wkq_wait(call_do_xino_fwrite, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ ++ return err; ++} ++ ++ssize_t xino_fwrite(vfs_writef_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos) ++{ ++ ssize_t err; ++ ++ if (rlimit(RLIMIT_FSIZE) == RLIM_INFINITY) { ++ lockdep_off(); ++ err = do_xino_fwrite(func, file, buf, size, pos); ++ lockdep_on(); ++ } else { ++ lockdep_off(); ++ err = xino_fwrite_wkq(func, file, buf, size, pos); ++ lockdep_on(); ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * 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 (vfsub_f_size_read(xib) >= 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); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * truncate 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; ++ vfs_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 = vfsub_f_size_read(file); ++ 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, i; ++ unsigned int nfile; ++ aufs_bindex_t bindex, bbot; ++ void *page; ++ struct au_branch *br; ++ struct au_xino *xi; ++ struct file *file; ++ ++ err = -ENOMEM; ++ page = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!page)) ++ goto out; ++ ++ err = 0; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; !err && bindex <= bbot; bindex++) ++ if (!bindex || is_sb_shared(sb, bindex, bindex - 1) < 0) { ++ br = au_sbr(sb, bindex); ++ xi = br->br_xino; ++ nfile = xi->xi_nfile; ++ for (i = 0; i < nfile; i++) { ++ file = au_xino_file(xi, i); ++ if (file) ++ err = do_xib_restore(sb, file, page); ++ } ++ } else ++ AuDbg("skip shared 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_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 (vfsub_f_size_read(file) <= PAGE_SIZE) ++ goto out; ++ ++ file = au_xino_create2(sb, &sbinfo->si_xib->f_path, NULL); ++ 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; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_xino *au_xino_alloc(unsigned int nfile) ++{ ++ struct au_xino *xi; ++ ++ xi = kzalloc(sizeof(*xi), GFP_NOFS); ++ if (unlikely(!xi)) ++ goto out; ++ xi->xi_nfile = nfile; ++ xi->xi_file = kcalloc(nfile, sizeof(*xi->xi_file), GFP_NOFS); ++ if (unlikely(!xi->xi_file)) ++ goto out_free; ++ ++ xi->xi_nondir.total = 8; /* initial size */ ++ xi->xi_nondir.array = kcalloc(xi->xi_nondir.total, sizeof(ino_t), ++ GFP_NOFS); ++ if (unlikely(!xi->xi_nondir.array)) ++ goto out_file; ++ ++ spin_lock_init(&xi->xi_nondir.spin); ++ init_waitqueue_head(&xi->xi_nondir.wqh); ++ mutex_init(&xi->xi_mtx); ++ INIT_HLIST_BL_HEAD(&xi->xi_writing); ++ atomic_set(&xi->xi_truncating, 0); ++ kref_init(&xi->xi_kref); ++ goto out; /* success */ ++ ++out_file: ++ au_kfree_try_rcu(xi->xi_file); ++out_free: ++ au_kfree_rcu(xi); ++ xi = NULL; ++out: ++ return xi; ++} ++ ++static int au_xino_init(struct au_branch *br, int idx, struct file *file) ++{ ++ int err; ++ struct au_xino *xi; ++ ++ err = 0; ++ xi = au_xino_alloc(idx + 1); ++ if (unlikely(!xi)) { ++ err = -ENOMEM; ++ goto out; ++ } ++ ++ if (file) ++ get_file(file); ++ xi->xi_file[idx] = file; ++ AuDebugOn(br->br_xino); ++ br->br_xino = xi; ++ ++out: ++ return err; ++} ++ ++static void au_xino_release(struct kref *kref) ++{ ++ struct au_xino *xi; ++ int i; ++ unsigned long ul; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos, *n; ++ struct au_xi_writing *p; ++ ++ xi = container_of(kref, struct au_xino, xi_kref); ++ for (i = 0; i < xi->xi_nfile; i++) ++ if (xi->xi_file[i]) ++ fput(xi->xi_file[i]); ++ for (i = xi->xi_nondir.total - 1; i >= 0; i--) ++ AuDebugOn(xi->xi_nondir.array[i]); ++ mutex_destroy(&xi->xi_mtx); ++ hbl = &xi->xi_writing; ++ ul = au_hbl_count(hbl); ++ if (unlikely(ul)) { ++ pr_warn("xi_writing %lu\n", ul); ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry_safe (p, pos, n, hbl, node) { ++ hlist_bl_del(&p->node); ++ au_kfree_rcu(p); ++ } ++ hlist_bl_unlock(hbl); ++ } ++ au_kfree_try_rcu(xi->xi_file); ++ au_kfree_try_rcu(xi->xi_nondir.array); ++ au_kfree_rcu(xi); ++} ++ ++int au_xino_put(struct au_branch *br) ++{ ++ int ret; ++ struct au_xino *xi; ++ ++ ret = 0; ++ xi = br->br_xino; ++ if (xi) { ++ br->br_xino = NULL; ++ ret = kref_put(&xi->xi_kref, au_xino_release); ++ } ++ ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * xino mount option handlers ++ */ ++ ++/* xino bitmap */ ++static void xino_clear_xib(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ /* unnecessary to clear sbinfo->si_xread and ->si_xwrite */ ++ if (sbinfo->si_xib) ++ fput(sbinfo->si_xib); ++ sbinfo->si_xib = NULL; ++ if (sbinfo->si_xib_buf) ++ free_page((unsigned long)sbinfo->si_xib_buf); ++ sbinfo->si_xib_buf = NULL; ++} ++ ++static int au_xino_set_xib(struct super_block *sb, struct path *path) ++{ ++ int err; ++ loff_t pos; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ struct super_block *xi_sb; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ file = au_xino_create2(sb, path, 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 = vfs_readf(file); ++ sbinfo->si_xwrite = vfs_writef(file); ++ xi_sb = file_inode(file)->i_sb; ++ sbinfo->si_ximaxent = xi_sb->s_maxbytes; ++ if (unlikely(sbinfo->si_ximaxent < PAGE_SIZE)) { ++ err = -EIO; ++ pr_err("s_maxbytes(%llu) on %s is too small\n", ++ (u64)sbinfo->si_ximaxent, au_sbtype(xi_sb)); ++ goto out_unset; ++ } ++ sbinfo->si_ximaxent /= sizeof(ino_t); ++ ++ 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 (vfsub_f_size_read(file) < 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: ++ if (sbinfo->si_xib_buf) ++ 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; ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* xino for each branch */ ++static void xino_clear_br(struct super_block *sb) ++{ ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ AuDebugOn(!br); ++ au_xino_put(br); ++ } ++} ++ ++static void au_xino_set_br_shared(struct super_block *sb, struct au_branch *br, ++ aufs_bindex_t bshared) ++{ ++ struct au_branch *brshared; ++ ++ brshared = au_sbr(sb, bshared); ++ AuDebugOn(!brshared->br_xino); ++ AuDebugOn(!brshared->br_xino->xi_file); ++ if (br->br_xino != brshared->br_xino) { ++ au_xino_get(brshared); ++ au_xino_put(br); ++ br->br_xino = brshared->br_xino; ++ } ++} ++ ++struct au_xino_do_set_br { ++ vfs_writef_t writef; ++ struct au_branch *br; ++ ino_t h_ino; ++ aufs_bindex_t bshared; ++}; ++ ++static int au_xino_do_set_br(struct super_block *sb, struct path *path, ++ struct au_xino_do_set_br *args) ++{ ++ int err; ++ struct au_xi_calc calc; ++ struct file *file; ++ struct au_branch *br; ++ struct au_xi_new xinew = { ++ .base = path ++ }; ++ ++ br = args->br; ++ xinew.xi = br->br_xino; ++ au_xi_calc(sb, args->h_ino, &calc); ++ xinew.copy_src = au_xino_file(xinew.xi, calc.idx); ++ if (args->bshared >= 0) ++ /* shared xino */ ++ au_xino_set_br_shared(sb, br, args->bshared); ++ else if (!xinew.xi) { ++ /* new xino */ ++ err = au_xino_init(br, calc.idx, xinew.copy_src); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ /* force re-creating */ ++ xinew.xi = br->br_xino; ++ xinew.idx = calc.idx; ++ mutex_lock(&xinew.xi->xi_mtx); ++ file = au_xi_new(sb, &xinew); ++ mutex_unlock(&xinew.xi->xi_mtx); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ AuDebugOn(!file); ++ ++ err = au_xino_do_write(args->writef, file, &calc, AUFS_ROOT_INO); ++ if (unlikely(err)) ++ au_xino_put(br); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_xino_set_br(struct super_block *sb, struct path *path) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct au_xino_do_set_br args; ++ struct inode *inode; ++ ++ SiMustWriteLock(sb); ++ ++ bbot = au_sbbot(sb); ++ inode = d_inode(sb->s_root); ++ args.writef = au_sbi(sb)->si_xwrite; ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ args.h_ino = au_h_iptr(inode, bindex)->i_ino; ++ args.br = au_sbr(sb, bindex); ++ args.bshared = is_sb_shared(sb, bindex, bindex - 1); ++ err = au_xino_do_set_br(sb, path, &args); ++ if (unlikely(err)) ++ break; ++ } ++ ++ AuTraceErr(err); ++ 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); ++ dbgaufs_brs_del(sb, 0); ++ 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 *xiopt, int remount) ++{ ++ int err, skip; ++ struct dentry *dentry, *parent, *cur_dentry, *cur_parent; ++ struct qstr *dname, *cur_name; ++ struct file *cur_xino; ++ struct au_sbinfo *sbinfo; ++ struct path *path, *cur_path; ++ ++ SiMustWriteLock(sb); ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ path = &xiopt->file->f_path; ++ dentry = path->dentry; ++ parent = dget_parent(dentry); ++ if (remount) { ++ skip = 0; ++ cur_xino = sbinfo->si_xib; ++ if (cur_xino) { ++ cur_path = &cur_xino->f_path; ++ cur_dentry = cur_path->dentry; ++ cur_parent = dget_parent(cur_dentry); ++ cur_name = &cur_dentry->d_name; ++ dname = &dentry->d_name; ++ skip = (cur_parent == parent ++ && au_qstreq(dname, cur_name)); ++ dput(cur_parent); ++ } ++ if (skip) ++ goto out; ++ } ++ ++ au_opt_set(sbinfo->si_mntflags, XINO); ++ err = au_xino_set_xib(sb, path); ++ /* si_x{read,write} are set */ ++ if (!err) ++ err = au_xigen_set(sb, path); ++ if (!err) ++ err = au_xino_set_br(sb, path); ++ if (!err) { ++ dbgaufs_brs_add(sb, 0, /*topdown*/1); ++ goto out; /* success */ ++ } ++ ++ /* reset all */ ++ AuIOErr("failed setting xino(%d).\n", err); ++ au_xino_clr(sb); ++ ++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 bbot, bindex, bwr; ++ ++ br = NULL; ++ bbot = au_sbbot(sb); ++ bwr = -1; ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_writable(br->br_perm) ++ && !au_test_fs_bad_xino(au_br_sb(br))) { ++ bwr = bindex; ++ break; ++ } ++ } ++ ++ if (bwr >= 0) { ++ file = ERR_PTR(-ENOMEM); ++ page = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!page)) ++ goto out; ++ path.mnt = au_br_mnt(br); ++ 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, /*wbrtop*/1); ++ } ++ free_page((unsigned long)page); ++ } else { ++ file = au_xino_create(sb, AUFS_XINO_DEFPATH, /*silent*/0, ++ /*wbrtop*/0); ++ if (IS_ERR(file)) ++ goto out; ++ h_sb = file->f_path.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); ++ } ++ } ++ ++out: ++ return file; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * 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 found then share the xinofile with another branch. ++ */ ++int au_xino_init_br(struct super_block *sb, struct au_branch *br, ino_t h_ino, ++ struct path *base) ++{ ++ int err; ++ struct au_xino_do_set_br args = { ++ .h_ino = h_ino, ++ .br = br ++ }; ++ ++ args.writef = au_sbi(sb)->si_xwrite; ++ args.bshared = sbr_find_shared(sb, /*btop*/0, au_sbbot(sb), ++ au_br_sb(br)); ++ err = au_xino_do_set_br(sb, base, &args); ++ if (unlikely(err)) ++ au_xino_put(br); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * 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 = vfsub_f_size_read(file) / 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; ++} ++ ++/* 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, bbot, 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; ++ vfs_writef_t xwrite; ++ struct au_xi_calc calc; ++ struct file *file; ++ ++ AuDebugOn(au_is_bad_inode(inode)); ++ ++ 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); ++ bindex = iinfo->ii_btop; ++ if (bindex < 0) ++ return; ++ ++ xwrite = au_sbi(sb)->si_xwrite; ++ try_trunc = !!au_opt_test(mnt_flags, TRUNC_XINO); ++ hi = au_hinode(iinfo, bindex); ++ bbot = iinfo->ii_bbot; ++ for (; bindex <= bbot; 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); ++ au_xi_calc(sb, h_inode->i_ino, &calc); ++ file = au_xino_file(br->br_xino, calc.idx); ++ if (IS_ERR_OR_NULL(file)) ++ continue; ++ ++ err = au_xino_do_write(xwrite, file, &calc, /*ino*/0); ++ if (!err && try_trunc ++ && au_test_fs_trunc_xino(au_br_sb(br))) ++ xino_try_trunc(sb, br); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_xinondir_find(struct au_xino *xi, ino_t h_ino) ++{ ++ int found, total, i; ++ ++ found = -1; ++ total = xi->xi_nondir.total; ++ for (i = 0; i < total; i++) { ++ if (xi->xi_nondir.array[i] != h_ino) ++ continue; ++ found = i; ++ break; ++ } ++ ++ return found; ++} ++ ++static int au_xinondir_expand(struct au_xino *xi) ++{ ++ int err, sz; ++ ino_t *p; ++ ++ BUILD_BUG_ON(KMALLOC_MAX_SIZE > INT_MAX); ++ ++ err = -ENOMEM; ++ sz = xi->xi_nondir.total * sizeof(ino_t); ++ if (unlikely(sz > KMALLOC_MAX_SIZE / 2)) ++ goto out; ++ p = au_kzrealloc(xi->xi_nondir.array, sz, sz << 1, GFP_ATOMIC, ++ /*may_shrink*/0); ++ if (p) { ++ xi->xi_nondir.array = p; ++ xi->xi_nondir.total <<= 1; ++ AuDbg("xi_nondir.total %d\n", xi->xi_nondir.total); ++ err = 0; ++ } ++ ++out: ++ return err; ++} ++ ++void au_xinondir_leave(struct super_block *sb, aufs_bindex_t bindex, ++ ino_t h_ino, int idx) ++{ ++ struct au_xino *xi; ++ ++ AuDebugOn(!au_opt_test(au_mntflags(sb), XINO)); ++ xi = au_sbr(sb, bindex)->br_xino; ++ AuDebugOn(idx < 0 || xi->xi_nondir.total <= idx); ++ ++ spin_lock(&xi->xi_nondir.spin); ++ AuDebugOn(xi->xi_nondir.array[idx] != h_ino); ++ xi->xi_nondir.array[idx] = 0; ++ spin_unlock(&xi->xi_nondir.spin); ++ wake_up_all(&xi->xi_nondir.wqh); ++} ++ ++int au_xinondir_enter(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ int *idx) ++{ ++ int err, found, empty; ++ struct au_xino *xi; ++ ++ err = 0; ++ *idx = -1; ++ if (!au_opt_test(au_mntflags(sb), XINO)) ++ goto out; /* no xino */ ++ ++ xi = au_sbr(sb, bindex)->br_xino; ++ ++again: ++ spin_lock(&xi->xi_nondir.spin); ++ found = au_xinondir_find(xi, h_ino); ++ if (found == -1) { ++ empty = au_xinondir_find(xi, /*h_ino*/0); ++ if (empty == -1) { ++ empty = xi->xi_nondir.total; ++ err = au_xinondir_expand(xi); ++ if (unlikely(err)) ++ goto out_unlock; ++ } ++ xi->xi_nondir.array[empty] = h_ino; ++ *idx = empty; ++ } else { ++ spin_unlock(&xi->xi_nondir.spin); ++ wait_event(xi->xi_nondir.wqh, ++ xi->xi_nondir.array[found] != h_ino); ++ goto again; ++ } ++ ++out_unlock: ++ spin_unlock(&xi->xi_nondir.spin); ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_xino_path(struct seq_file *seq, struct file *file) ++{ ++ int err; ++ ++ err = au_seq_path(seq, &file->f_path); ++ if (unlikely(err)) ++ goto out; ++ ++#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 -Nurp linux-5.4/fs/dcache.c linux-5.4-aufs/fs/dcache.c +--- linux-5.4/fs/dcache.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/fs/dcache.c 2019-11-28 01:25:59.069925618 +0200 +@@ -1264,7 +1264,7 @@ enum d_walk_ret { + * + * The @enter() callbacks are called with d_lock held. + */ +-static void d_walk(struct dentry *parent, void *data, ++void d_walk(struct dentry *parent, void *data, + enum d_walk_ret (*enter)(void *, struct dentry *)) + { + struct dentry *this_parent; +diff -Nurp linux-5.4/fs/fcntl.c linux-5.4-aufs/fs/fcntl.c +--- linux-5.4/fs/fcntl.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/fs/fcntl.c 2019-11-28 01:25:59.069925618 +0200 +@@ -32,7 +32,7 @@ + + #define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME) + +-static int setfl(int fd, struct file * filp, unsigned long arg) ++int setfl(int fd, struct file * filp, unsigned long arg) + { + struct inode * inode = file_inode(filp); + int error = 0; +@@ -63,6 +63,8 @@ static int setfl(int fd, struct file * f + + if (filp->f_op->check_flags) + error = filp->f_op->check_flags(arg); ++ if (!error && filp->f_op->setfl) ++ error = filp->f_op->setfl(filp, arg); + if (error) + return error; + +diff -Nurp linux-5.4/fs/inode.c linux-5.4-aufs/fs/inode.c +--- linux-5.4/fs/inode.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/fs/inode.c 2019-11-28 01:25:59.070925617 +0200 +@@ -1673,7 +1673,7 @@ EXPORT_SYMBOL(generic_update_time); + * This does the actual work of updating an inodes time or version. Must have + * had called mnt_want_write() before calling this. + */ +-static int update_time(struct inode *inode, struct timespec64 *time, int flags) ++int update_time(struct inode *inode, struct timespec64 *time, int flags) + { + int (*update_time)(struct inode *, struct timespec64 *, int); + +diff -Nurp linux-5.4/fs/Kconfig linux-5.4-aufs/fs/Kconfig +--- linux-5.4/fs/Kconfig 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/fs/Kconfig 2019-11-28 01:33:04.893908639 +0200 +@@ -121,6 +121,7 @@ source "fs/quota/Kconfig" + source "fs/autofs/Kconfig" + source "fs/fuse/Kconfig" + source "fs/overlayfs/Kconfig" ++source "fs/aufs/Kconfig" + + menu "Caches" + +diff -Nurp linux-5.4/fs/Makefile linux-5.4-aufs/fs/Makefile +--- linux-5.4/fs/Makefile 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/fs/Makefile 2019-11-28 01:34:16.881905768 +0200 +@@ -110,6 +110,7 @@ obj-$(CONFIG_AUTOFS_FS) += autofs/ + obj-$(CONFIG_ADFS_FS) += adfs/ + obj-$(CONFIG_FUSE_FS) += fuse/ + obj-$(CONFIG_OVERLAY_FS) += overlayfs/ ++obj-$(CONFIG_AUFS_FS) += aufs/ + obj-$(CONFIG_ORANGEFS_FS) += orangefs/ + obj-$(CONFIG_UDF_FS) += udf/ + obj-$(CONFIG_SUN_OPENPROMFS) += openpromfs/ +diff -Nurp linux-5.4/fs/namespace.c linux-5.4-aufs/fs/namespace.c +--- linux-5.4/fs/namespace.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/fs/namespace.c 2019-11-28 01:25:59.070925617 +0200 +@@ -776,6 +776,12 @@ static inline int check_mnt(struct mount + return mnt->mnt_ns == current->nsproxy->mnt_ns; + } + ++/* for aufs, CONFIG_AUFS_BR_FUSE */ ++int is_current_mnt_ns(struct vfsmount *mnt) ++{ ++ return check_mnt(real_mount(mnt)); ++} ++ + /* + * vfsmount lock must be held for write + */ +diff -Nurp linux-5.4/fs/proc/base.c linux-5.4-aufs/fs/proc/base.c +--- linux-5.4/fs/proc/base.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/fs/proc/base.c 2019-11-28 01:25:59.070925617 +0200 +@@ -2037,7 +2037,7 @@ static int map_files_get_link(struct den + rc = -ENOENT; + vma = find_exact_vma(mm, vm_start, vm_end); + if (vma && vma->vm_file) { +- *path = vma->vm_file->f_path; ++ *path = vma_pr_or_file(vma)->f_path; + path_get(path); + rc = 0; + } +diff -Nurp linux-5.4/fs/proc/nommu.c linux-5.4-aufs/fs/proc/nommu.c +--- linux-5.4/fs/proc/nommu.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/fs/proc/nommu.c 2019-11-28 01:25:59.070925617 +0200 +@@ -41,7 +41,10 @@ static int nommu_region_show(struct seq_ + file = region->vm_file; + + if (file) { +- struct inode *inode = file_inode(region->vm_file); ++ struct inode *inode; ++ ++ file = vmr_pr_or_file(region); ++ inode = file_inode(file); + dev = inode->i_sb->s_dev; + ino = inode->i_ino; + } +diff -Nurp linux-5.4/fs/proc/task_mmu.c linux-5.4-aufs/fs/proc/task_mmu.c +--- linux-5.4/fs/proc/task_mmu.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/fs/proc/task_mmu.c 2019-11-28 01:25:59.070925617 +0200 +@@ -309,7 +309,10 @@ show_map_vma(struct seq_file *m, struct + const char *name = NULL; + + if (file) { +- struct inode *inode = file_inode(vma->vm_file); ++ struct inode *inode; ++ ++ file = vma_pr_or_file(vma); ++ inode = file_inode(file); + dev = inode->i_sb->s_dev; + ino = inode->i_ino; + pgoff = ((loff_t)vma->vm_pgoff) << PAGE_SHIFT; +@@ -1819,7 +1822,7 @@ static int show_numa_map(struct seq_file + struct proc_maps_private *proc_priv = &numa_priv->proc_maps; + struct vm_area_struct *vma = v; + struct numa_maps *md = &numa_priv->md; +- struct file *file = vma->vm_file; ++ struct file *file = vma_pr_or_file(vma); + struct mm_struct *mm = vma->vm_mm; + struct mempolicy *pol; + char buffer[64]; +diff -Nurp linux-5.4/fs/proc/task_nommu.c linux-5.4-aufs/fs/proc/task_nommu.c +--- linux-5.4/fs/proc/task_nommu.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/fs/proc/task_nommu.c 2019-11-28 01:25:59.070925617 +0200 +@@ -155,7 +155,10 @@ static int nommu_vma_show(struct seq_fil + file = vma->vm_file; + + if (file) { +- struct inode *inode = file_inode(vma->vm_file); ++ struct inode *inode; ++ ++ file = vma_pr_or_file(vma); ++ inode = file_inode(file); + dev = inode->i_sb->s_dev; + ino = inode->i_ino; + pgoff = (loff_t)vma->vm_pgoff << PAGE_SHIFT; +diff -Nurp linux-5.4/fs/read_write.c linux-5.4-aufs/fs/read_write.c +--- linux-5.4/fs/read_write.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/fs/read_write.c 2019-11-28 01:25:59.070925617 +0200 +@@ -498,6 +498,28 @@ static ssize_t __vfs_write(struct file * + return -EINVAL; + } + ++vfs_readf_t vfs_readf(struct file *file) ++{ ++ const struct file_operations *fop = file->f_op; ++ ++ if (fop->read) ++ return fop->read; ++ if (fop->read_iter) ++ return new_sync_read; ++ return ERR_PTR(-ENOSYS); ++} ++ ++vfs_writef_t vfs_writef(struct file *file) ++{ ++ const struct file_operations *fop = file->f_op; ++ ++ if (fop->write) ++ return fop->write; ++ if (fop->write_iter) ++ return new_sync_write; ++ return ERR_PTR(-ENOSYS); ++} ++ + ssize_t __kernel_write(struct file *file, const void *buf, size_t count, loff_t *pos) + { + mm_segment_t old_fs; +diff -Nurp linux-5.4/fs/splice.c linux-5.4-aufs/fs/splice.c +--- linux-5.4/fs/splice.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/fs/splice.c 2019-11-28 01:25:59.071925617 +0200 +@@ -834,8 +834,8 @@ EXPORT_SYMBOL(generic_splice_sendpage); + /* + * Attempt to initiate a splice from pipe to file. + */ +-static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, +- loff_t *ppos, size_t len, unsigned int flags) ++long 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); +@@ -851,9 +851,9 @@ static long do_splice_from(struct pipe_i + /* + * Attempt to initiate a splice from a file to a pipe. + */ +-static long do_splice_to(struct file *in, loff_t *ppos, +- struct pipe_inode_info *pipe, size_t len, +- unsigned int flags) ++long 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); +diff -Nurp linux-5.4/fs/sync.c linux-5.4-aufs/fs/sync.c +--- linux-5.4/fs/sync.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/fs/sync.c 2019-11-28 01:25:59.071925617 +0200 +@@ -28,7 +28,7 @@ + * wait == 1 case since in that case write_inode() functions do + * sync_dirty_buffer() and thus effectively write one block at a time. + */ +-static int __sync_filesystem(struct super_block *sb, int wait) ++int __sync_filesystem(struct super_block *sb, int wait) + { + if (wait) + sync_inodes_sb(sb); +diff -Nurp linux-5.4/include/linux/fs.h linux-5.4-aufs/include/linux/fs.h +--- linux-5.4/include/linux/fs.h 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/include/linux/fs.h 2019-11-28 01:25:59.071925617 +0200 +@@ -1349,6 +1349,7 @@ extern void fasync_free(struct fasync_st + /* can be called from interrupts */ + extern void kill_fasync(struct fasync_struct **, int, int); + ++extern int setfl(int fd, struct file * filp, unsigned long arg); + extern void __f_setown(struct file *filp, struct pid *, enum pid_type, int force); + extern int f_setown(struct file *filp, unsigned long arg, int force); + extern void f_delown(struct file *filp); +@@ -1835,6 +1836,7 @@ struct file_operations { + ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); + unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); + int (*check_flags)(int); ++ int (*setfl)(struct file *, unsigned long); + int (*flock) (struct file *, int, struct file_lock *); + ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); + ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); +@@ -1905,6 +1907,12 @@ ssize_t rw_copy_check_uvector(int type, + struct iovec *fast_pointer, + struct iovec **ret_pointer); + ++typedef ssize_t (*vfs_readf_t)(struct file *, char __user *, size_t, loff_t *); ++typedef ssize_t (*vfs_writef_t)(struct file *, const char __user *, size_t, ++ loff_t *); ++vfs_readf_t vfs_readf(struct file *file); ++vfs_writef_t vfs_writef(struct file *file); ++ + extern ssize_t __vfs_read(struct file *, char __user *, size_t, loff_t *); + extern ssize_t vfs_read(struct file *, char __user *, size_t, loff_t *); + extern ssize_t vfs_write(struct file *, const char __user *, size_t, loff_t *); +@@ -2325,6 +2333,7 @@ extern int current_umask(void); + extern void ihold(struct inode * inode); + extern void iput(struct inode *); + extern int generic_update_time(struct inode *, struct timespec64 *, int); ++extern int update_time(struct inode *, struct timespec64 *, int); + + /* /sys/fs */ + extern struct kobject *fs_kobj; +@@ -2613,6 +2622,7 @@ static inline bool sb_is_blkdev_sb(struc + return false; + } + #endif ++extern int __sync_filesystem(struct super_block *, int); + extern int sync_filesystem(struct super_block *); + extern const struct file_operations def_blk_fops; + extern const struct file_operations def_chr_fops; +diff -Nurp linux-5.4/include/linux/lockdep.h linux-5.4-aufs/include/linux/lockdep.h +--- linux-5.4/include/linux/lockdep.h 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/include/linux/lockdep.h 2019-11-28 01:25:59.071925617 +0200 +@@ -331,6 +331,8 @@ static inline int lockdep_match_key(stru + return lock->key == key; + } + ++struct lock_class *lockdep_hlock_class(struct held_lock *hlock); ++ + /* + * Acquire a lock. + * +@@ -473,6 +475,7 @@ struct lockdep_map { }; + + #define lockdep_depth(tsk) (0) + ++#define lockdep_is_held(lock) (1) + #define lockdep_is_held_type(l, r) (1) + + #define lockdep_assert_held(l) do { (void)(l); } while (0) +diff -Nurp linux-5.4/include/linux/mm.h linux-5.4-aufs/include/linux/mm.h +--- linux-5.4/include/linux/mm.h 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/include/linux/mm.h 2019-11-28 01:25:59.071925617 +0200 +@@ -1510,6 +1510,28 @@ static inline void unmap_shared_mapping_ + unmap_mapping_range(mapping, holebegin, holelen, 0); + } + ++extern void vma_do_file_update_time(struct vm_area_struct *, const char[], int); ++extern struct file *vma_do_pr_or_file(struct vm_area_struct *, const char[], ++ int); ++extern void vma_do_get_file(struct vm_area_struct *, const char[], int); ++extern void vma_do_fput(struct vm_area_struct *, const char[], int); ++ ++#define vma_file_update_time(vma) vma_do_file_update_time(vma, __func__, \ ++ __LINE__) ++#define vma_pr_or_file(vma) vma_do_pr_or_file(vma, __func__, \ ++ __LINE__) ++#define vma_get_file(vma) vma_do_get_file(vma, __func__, __LINE__) ++#define vma_fput(vma) vma_do_fput(vma, __func__, __LINE__) ++ ++#ifndef CONFIG_MMU ++extern struct file *vmr_do_pr_or_file(struct vm_region *, const char[], int); ++extern void vmr_do_fput(struct vm_region *, const char[], int); ++ ++#define vmr_pr_or_file(region) vmr_do_pr_or_file(region, __func__, \ ++ __LINE__) ++#define vmr_fput(region) vmr_do_fput(region, __func__, __LINE__) ++#endif /* !CONFIG_MMU */ ++ + extern int access_process_vm(struct task_struct *tsk, unsigned long addr, + void *buf, int len, unsigned int gup_flags); + extern int access_remote_vm(struct mm_struct *mm, unsigned long addr, +diff -Nurp linux-5.4/include/linux/mm_types.h linux-5.4-aufs/include/linux/mm_types.h +--- linux-5.4/include/linux/mm_types.h 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/include/linux/mm_types.h 2019-11-28 01:25:59.071925617 +0200 +@@ -267,6 +267,7 @@ 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 +@@ -341,6 +342,7 @@ struct vm_area_struct { + unsigned long vm_pgoff; /* Offset (within vm_file) in PAGE_SIZE + units */ + 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) */ + + #ifdef CONFIG_SWAP +diff -Nurp linux-5.4/include/linux/mnt_namespace.h linux-5.4-aufs/include/linux/mnt_namespace.h +--- linux-5.4/include/linux/mnt_namespace.h 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/include/linux/mnt_namespace.h 2019-11-28 01:25:59.071925617 +0200 +@@ -6,11 +6,14 @@ + struct mnt_namespace; + struct fs_struct; + struct user_namespace; ++struct vfsmount; + + extern struct mnt_namespace *copy_mnt_ns(unsigned long, struct mnt_namespace *, + struct user_namespace *, struct fs_struct *); + extern void put_mnt_ns(struct mnt_namespace *ns); + ++extern int is_current_mnt_ns(struct vfsmount *mnt); ++ + extern const struct file_operations proc_mounts_operations; + extern const struct file_operations proc_mountinfo_operations; + extern const struct file_operations proc_mountstats_operations; +diff -Nurp linux-5.4/include/linux/splice.h linux-5.4-aufs/include/linux/splice.h +--- linux-5.4/include/linux/splice.h 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/include/linux/splice.h 2019-11-28 01:25:59.071925617 +0200 +@@ -87,4 +87,10 @@ extern void splice_shrink_spd(struct spl + + extern const struct pipe_buf_operations page_cache_pipe_buf_ops; + extern const struct pipe_buf_operations default_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 -Nurp linux-5.4/include/uapi/linux/aufs_type.h linux-5.4-aufs/include/uapi/linux/aufs_type.h +--- linux-5.4/include/uapi/linux/aufs_type.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/include/uapi/linux/aufs_type.h 2019-11-28 01:25:59.071925617 +0200 +@@ -0,0 +1,439 @@ ++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++#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 "5.4" ++ ++/* 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 and copyup */ ++#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_DEF_SEC 30 /* seconds */ ++#define AUFS_XINO_DEF_TRUNC 45 /* percentage */ ++#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_FHSM_CACHE_DEF_SEC 30 /* seconds */ ++#define AUFS_PLINK_WARN 50 /* number of plinks in a single bucket */ ++ ++/* 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 ++ ++/* dirren, renamed dir */ ++#define AUFS_DR_INFO_PFX AUFS_WH_PFX ".dr." ++#define AUFS_DR_BRHINO_NAME AUFS_WH_PFX "hino" ++/* whiteouted doubly */ ++#define AUFS_WH_DR_INFO_PFX AUFS_WH_PFX AUFS_DR_INFO_PFX ++#define AUFS_WH_DR_BRHINO AUFS_WH_PFX AUFS_DR_BRHINO_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_BRATTR_COO_REG "coo_reg" ++#define AUFS_BRATTR_COO_ALL "coo_all" ++#define AUFS_BRATTR_FHSM "fhsm" ++#define AUFS_BRATTR_UNPIN "unpin" ++#define AUFS_BRATTR_ICEX "icex" ++#define AUFS_BRATTR_ICEX_SEC "icexsec" ++#define AUFS_BRATTR_ICEX_SYS "icexsys" ++#define AUFS_BRATTR_ICEX_TR "icextr" ++#define AUFS_BRATTR_ICEX_USR "icexusr" ++#define AUFS_BRATTR_ICEX_OTH "icexoth" ++#define AUFS_BRRATTR_WH "wh" ++#define AUFS_BRWATTR_NLWH "nolwh" ++#define AUFS_BRWATTR_MOO "moo" ++ ++#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 AuBrAttr_COO_REG (1 << 3) /* copy-up on open */ ++#define AuBrAttr_COO_ALL (1 << 4) ++#define AuBrAttr_COO_Mask (AuBrAttr_COO_REG | AuBrAttr_COO_ALL) ++ ++#define AuBrAttr_FHSM (1 << 5) /* file-based hsm */ ++#define AuBrAttr_UNPIN (1 << 6) /* rename-able top dir of ++ branch. meaningless since ++ linux-3.18-rc1 */ ++ ++/* ignore error in copying XATTR */ ++#define AuBrAttr_ICEX_SEC (1 << 7) ++#define AuBrAttr_ICEX_SYS (1 << 8) ++#define AuBrAttr_ICEX_TR (1 << 9) ++#define AuBrAttr_ICEX_USR (1 << 10) ++#define AuBrAttr_ICEX_OTH (1 << 11) ++#define AuBrAttr_ICEX (AuBrAttr_ICEX_SEC \ ++ | AuBrAttr_ICEX_SYS \ ++ | AuBrAttr_ICEX_TR \ ++ | AuBrAttr_ICEX_USR \ ++ | AuBrAttr_ICEX_OTH) ++ ++#define AuBrRAttr_WH (1 << 12) /* whiteout-able */ ++#define AuBrRAttr_Mask AuBrRAttr_WH ++ ++#define AuBrWAttr_NoLinkWH (1 << 13) /* un-hardlinkable whiteouts */ ++#define AuBrWAttr_MOO (1 << 14) /* move-up on open */ ++#define AuBrWAttr_Mask (AuBrWAttr_NoLinkWH | AuBrWAttr_MOO) ++ ++#define AuBrAttr_CMOO_Mask (AuBrAttr_COO_Mask | AuBrWAttr_MOO) ++ ++/* #warning test userspace */ ++#ifdef __KERNEL__ ++#ifndef CONFIG_AUFS_FHSM ++#undef AuBrAttr_FHSM ++#define AuBrAttr_FHSM 0 ++#endif ++#ifndef CONFIG_AUFS_XATTR ++#undef AuBrAttr_ICEX ++#define AuBrAttr_ICEX 0 ++#undef AuBrAttr_ICEX_SEC ++#define AuBrAttr_ICEX_SEC 0 ++#undef AuBrAttr_ICEX_SYS ++#define AuBrAttr_ICEX_SYS 0 ++#undef AuBrAttr_ICEX_TR ++#define AuBrAttr_ICEX_TR 0 ++#undef AuBrAttr_ICEX_USR ++#define AuBrAttr_ICEX_USR 0 ++#undef AuBrAttr_ICEX_OTH ++#define AuBrAttr_ICEX_OTH 0 ++#endif ++#endif ++ ++/* the longest combination */ ++/* AUFS_BRATTR_ICEX and AUFS_BRATTR_ICEX_TR don't affect here */ ++#define AuBrPermStrSz sizeof(AUFS_BRPERM_RW \ ++ "+" AUFS_BRATTR_COO_REG \ ++ "+" AUFS_BRATTR_FHSM \ ++ "+" AUFS_BRATTR_UNPIN \ ++ "+" AUFS_BRATTR_ICEX_SEC \ ++ "+" AUFS_BRATTR_ICEX_SYS \ ++ "+" AUFS_BRATTR_ICEX_USR \ ++ "+" AUFS_BRATTR_ICEX_OTH \ ++ "+" AUFS_BRWATTR_NLWH) ++ ++typedef struct { ++ char a[AuBrPermStrSz]; ++} au_br_perm_str_t; ++ ++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_cmoo(int brperm) ++{ ++ return brperm & AuBrAttr_CMOO_Mask; ++} ++ ++static inline int au_br_fhsm(int brperm) ++{ ++ return brperm & AuBrAttr_FHSM; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ioctl */ ++enum { ++ /* readdir in userspace */ ++ AuCtl_RDU, ++ AuCtl_RDU_INO, ++ ++ AuCtl_WBR_FD, /* pathconf wrapper */ ++ AuCtl_IBUSY, /* busy inode */ ++ AuCtl_MVDOWN, /* move-down */ ++ AuCtl_BR, /* info about branches */ ++ AuCtl_FHSM_FD /* connection for fhsm */ ++}; ++ ++/* borrowed from linux/include/linux/kernel.h */ ++#ifndef ALIGN ++#ifdef _GNU_SOURCE ++#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1) ++#else ++#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) ++#endif ++#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); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dirren. the branch is identified by the filename who contains this */ ++struct au_drinfo { ++ uint64_t ino; ++ union { ++ uint8_t oldnamelen; ++ uint64_t _padding; ++ }; ++ uint8_t oldname[0]; ++} __aligned(8); ++ ++struct au_drinfo_fdata { ++ uint32_t magic; ++ struct au_drinfo drinfo; ++} __aligned(8); ++ ++#define AUFS_DRINFO_MAGIC_V1 ('a' << 24 | 'd' << 16 | 'r' << 8 | 0x01) ++/* future */ ++#define AUFS_DRINFO_MAGIC_V2 ('a' << 24 | 'd' << 16 | 'r' << 8 | 0x02) ++ ++/* ---------------------------------------------------------------------- */ ++ ++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); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* error code for move-down */ ++/* the actual message strings are implemented in aufs-util.git */ ++enum { ++ EAU_MVDOWN_OPAQUE = 1, ++ EAU_MVDOWN_WHITEOUT, ++ EAU_MVDOWN_UPPER, ++ EAU_MVDOWN_BOTTOM, ++ EAU_MVDOWN_NOUPPER, ++ EAU_MVDOWN_NOLOWERBR, ++ EAU_Last ++}; ++ ++/* flags for move-down */ ++#define AUFS_MVDOWN_DMSG 1 ++#define AUFS_MVDOWN_OWLOWER (1 << 1) /* overwrite lower */ ++#define AUFS_MVDOWN_KUPPER (1 << 2) /* keep upper */ ++#define AUFS_MVDOWN_ROLOWER (1 << 3) /* do even if lower is RO */ ++#define AUFS_MVDOWN_ROLOWER_R (1 << 4) /* did on lower RO */ ++#define AUFS_MVDOWN_ROUPPER (1 << 5) /* do even if upper is RO */ ++#define AUFS_MVDOWN_ROUPPER_R (1 << 6) /* did on upper RO */ ++#define AUFS_MVDOWN_BRID_UPPER (1 << 7) /* upper brid */ ++#define AUFS_MVDOWN_BRID_LOWER (1 << 8) /* lower brid */ ++#define AUFS_MVDOWN_FHSM_LOWER (1 << 9) /* find fhsm attr for lower */ ++#define AUFS_MVDOWN_STFS (1 << 10) /* req. stfs */ ++#define AUFS_MVDOWN_STFS_FAILED (1 << 11) /* output: stfs is unusable */ ++#define AUFS_MVDOWN_BOTTOM (1 << 12) /* output: no more lowers */ ++ ++/* index for move-down */ ++enum { ++ AUFS_MVDOWN_UPPER, ++ AUFS_MVDOWN_LOWER, ++ AUFS_MVDOWN_NARRAY ++}; ++ ++/* ++ * additional info of move-down ++ * number of free blocks and inodes. ++ * subset of struct kstatfs, but smaller and always 64bit. ++ */ ++struct aufs_stfs { ++ uint64_t f_blocks; ++ uint64_t f_bavail; ++ uint64_t f_files; ++ uint64_t f_ffree; ++}; ++ ++struct aufs_stbr { ++ int16_t brid; /* optional input */ ++ int16_t bindex; /* output */ ++ struct aufs_stfs stfs; /* output when AUFS_MVDOWN_STFS set */ ++} __aligned(8); ++ ++struct aufs_mvdown { ++ uint32_t flags; /* input/output */ ++ struct aufs_stbr stbr[AUFS_MVDOWN_NARRAY]; /* input/output */ ++ int8_t au_errno; /* output */ ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++union aufs_brinfo { ++ /* PATH_MAX may differ between kernel-space and user-space */ ++ char _spacer[4096]; ++ struct { ++ int16_t id; ++ int perm; ++ char path[0]; ++ }; ++} __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) ++#define AUFS_CTL_MVDOWN _IOWR(AuCtlType, AuCtl_MVDOWN, \ ++ struct aufs_mvdown) ++#define AUFS_CTL_BRINFO _IOW(AuCtlType, AuCtl_BR, union aufs_brinfo) ++#define AUFS_CTL_FHSM_FD _IOW(AuCtlType, AuCtl_FHSM_FD, int) ++ ++#endif /* __AUFS_TYPE_H__ */ +diff -Nurp linux-5.4/kernel/fork.c linux-5.4-aufs/kernel/fork.c +--- linux-5.4/kernel/fork.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/kernel/fork.c 2019-11-28 01:25:59.072925617 +0200 +@@ -562,7 +562,7 @@ static __latent_entropy int dup_mmap(str + struct inode *inode = file_inode(file); + struct address_space *mapping = file->f_mapping; + +- get_file(file); ++ vma_get_file(tmp); + if (tmp->vm_flags & VM_DENYWRITE) + atomic_dec(&inode->i_writecount); + i_mmap_lock_write(mapping); +diff -Nurp linux-5.4/kernel/locking/lockdep.c linux-5.4-aufs/kernel/locking/lockdep.c +--- linux-5.4/kernel/locking/lockdep.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/kernel/locking/lockdep.c 2019-11-28 01:25:59.072925617 +0200 +@@ -153,7 +153,7 @@ static + struct lock_class lock_classes[MAX_LOCKDEP_KEYS]; + static DECLARE_BITMAP(lock_classes_in_use, MAX_LOCKDEP_KEYS); + +-static inline struct lock_class *hlock_class(struct held_lock *hlock) ++inline struct lock_class *lockdep_hlock_class(struct held_lock *hlock) + { + unsigned int class_idx = hlock->class_idx; + +@@ -174,6 +174,7 @@ static inline struct lock_class *hlock_c + */ + return lock_classes + class_idx; + } ++#define hlock_class(hlock) lockdep_hlock_class(hlock) + + #ifdef CONFIG_LOCK_STAT + static DEFINE_PER_CPU(struct lock_class_stats[MAX_LOCKDEP_KEYS], cpu_lock_stats); +diff -Nurp linux-5.4/MAINTAINERS linux-5.4-aufs/MAINTAINERS +--- linux-5.4/MAINTAINERS 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/MAINTAINERS 2019-11-28 01:25:59.062925618 +0200 +@@ -2832,6 +2832,19 @@ F: include/linux/audit.h + F: include/uapi/linux/audit.h + F: kernel/audit* + ++AUFS (advanced multi layered unification filesystem) FILESYSTEM ++M: "J. R. Okajima" ++L: aufs-users@lists.sourceforge.net (members only) ++L: linux-unionfs@vger.kernel.org ++W: http://aufs.sourceforge.net ++T: git://github.com/sfjro/aufs4-linux.git ++S: Supported ++F: Documentation/filesystems/aufs/ ++F: Documentation/ABI/testing/debugfs-aufs ++F: Documentation/ABI/testing/sysfs-aufs ++F: fs/aufs/ ++F: include/uapi/linux/aufs_type.h ++ + AUXILIARY DISPLAY DRIVERS + M: Miguel Ojeda Sandonis + S: Maintained +diff -Nurp linux-5.4/mm/filemap.c linux-5.4-aufs/mm/filemap.c +--- linux-5.4/mm/filemap.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/mm/filemap.c 2019-11-28 01:25:59.072925617 +0200 +@@ -2696,7 +2696,7 @@ vm_fault_t filemap_page_mkwrite(struct v + vm_fault_t ret = VM_FAULT_LOCKED; + + sb_start_pagefault(inode->i_sb); +- file_update_time(vmf->vma->vm_file); ++ vma_file_update_time(vmf->vma); + lock_page(page); + if (page->mapping != inode->i_mapping) { + unlock_page(page); +diff -Nurp linux-5.4/mm/Makefile linux-5.4-aufs/mm/Makefile +--- linux-5.4/mm/Makefile 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/mm/Makefile 2019-11-28 01:25:59.072925617 +0200 +@@ -42,7 +42,7 @@ obj-y := filemap.o mempool.o oom_kill. + mm_init.o mmu_context.o percpu.o slab_common.o \ + compaction.o vmacache.o \ + interval_tree.o list_lru.o workingset.o \ +- debug.o gup.o $(mmu-y) ++ prfile.o debug.o gup.o $(mmu-y) + + # Give 'page_alloc' its own module-parameter namespace + page-alloc-y := page_alloc.o +diff -Nurp linux-5.4/mm/mmap.c linux-5.4-aufs/mm/mmap.c +--- linux-5.4/mm/mmap.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/mm/mmap.c 2019-11-28 01:25:59.073925617 +0200 +@@ -182,7 +182,7 @@ static struct vm_area_struct *remove_vma + if (vma->vm_ops && vma->vm_ops->close) + vma->vm_ops->close(vma); + if (vma->vm_file) +- fput(vma->vm_file); ++ vma_fput(vma); + mpol_put(vma_policy(vma)); + vm_area_free(vma); + return next; +@@ -940,7 +940,7 @@ again: + if (remove_next) { + if (file) { + uprobe_munmap(next, next->vm_start, next->vm_end); +- fput(file); ++ vma_fput(vma); + } + if (next->anon_vma) + anon_vma_merge(vma, next); +@@ -1865,8 +1865,8 @@ out: + return addr; + + unmap_and_free_vma: ++ vma_fput(vma); + vma->vm_file = NULL; +- fput(file); + + /* Undo any partial mapping done by a device driver. */ + unmap_region(mm, vma, prev, vma->vm_start, vma->vm_end); +@@ -2695,7 +2695,7 @@ int __split_vma(struct mm_struct *mm, st + goto out_free_mpol; + + if (new->vm_file) +- get_file(new->vm_file); ++ vma_get_file(new); + + if (new->vm_ops && new->vm_ops->open) + new->vm_ops->open(new); +@@ -2714,7 +2714,7 @@ int __split_vma(struct mm_struct *mm, st + if (new->vm_ops && new->vm_ops->close) + new->vm_ops->close(new); + if (new->vm_file) +- fput(new->vm_file); ++ vma_fput(new); + unlink_anon_vmas(new); + out_free_mpol: + mpol_put(vma_policy(new)); +@@ -2906,7 +2906,7 @@ SYSCALL_DEFINE5(remap_file_pages, unsign + struct vm_area_struct *vma; + unsigned long populate = 0; + unsigned long ret = -EINVAL; +- struct file *file; ++ struct file *file, *prfile; + + pr_warn_once("%s (%d) uses deprecated remap_file_pages() syscall. See Documentation/vm/remap_file_pages.rst.\n", + current->comm, current->pid); +@@ -2981,10 +2981,27 @@ SYSCALL_DEFINE5(remap_file_pages, unsign + } + } + +- file = get_file(vma->vm_file); ++ vma_get_file(vma); ++ file = vma->vm_file; ++ prfile = vma->vm_prfile; + ret = do_mmap_pgoff(vma->vm_file, start, size, + prot, flags, pgoff, &populate, NULL); ++ if (!IS_ERR_VALUE(ret) && file && prfile) { ++ struct vm_area_struct *new_vma; ++ ++ new_vma = find_vma(mm, ret); ++ if (!new_vma->vm_prfile) ++ new_vma->vm_prfile = prfile; ++ if (new_vma != vma) ++ get_file(prfile); ++ } ++ /* ++ * two fput()s instead of vma_fput(vma), ++ * coz vma may not be available anymore. ++ */ + fput(file); ++ if (prfile) ++ fput(prfile); + out: + up_write(&mm->mmap_sem); + if (populate) +@@ -3274,7 +3291,7 @@ struct vm_area_struct *copy_vma(struct v + if (anon_vma_clone(new_vma, vma)) + goto out_free_mempol; + if (new_vma->vm_file) +- get_file(new_vma->vm_file); ++ vma_get_file(new_vma); + 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 -Nurp linux-5.4/mm/nommu.c linux-5.4-aufs/mm/nommu.c +--- linux-5.4/mm/nommu.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/mm/nommu.c 2019-11-28 01:25:59.073925617 +0200 +@@ -552,7 +552,7 @@ static void __put_nommu_region(struct vm + up_write(&nommu_region_sem); + + if (region->vm_file) +- fput(region->vm_file); ++ vmr_fput(region); + + /* IO memory and memory shared directly out of the pagecache + * from ramfs/tmpfs mustn't be released here */ +@@ -690,7 +690,7 @@ static void delete_vma(struct mm_struct + if (vma->vm_ops && vma->vm_ops->close) + vma->vm_ops->close(vma); + if (vma->vm_file) +- fput(vma->vm_file); ++ vma_fput(vma); + put_nommu_region(vma->vm_region); + vm_area_free(vma); + } +@@ -1213,7 +1213,7 @@ unsigned long do_mmap(struct file *file, + goto error_just_free; + } + } +- fput(region->vm_file); ++ vmr_fput(region); + kmem_cache_free(vm_region_jar, region); + region = pregion; + result = start; +@@ -1290,10 +1290,10 @@ error_just_free: + up_write(&nommu_region_sem); + error: + if (region->vm_file) +- fput(region->vm_file); ++ vmr_fput(region); + kmem_cache_free(vm_region_jar, region); + if (vma->vm_file) +- fput(vma->vm_file); ++ vma_fput(vma); + vm_area_free(vma); + return ret; + +diff -Nurp linux-5.4/mm/prfile.c linux-5.4-aufs/mm/prfile.c +--- linux-5.4/mm/prfile.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/mm/prfile.c 2019-11-28 01:25:59.073925617 +0200 +@@ -0,0 +1,86 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Mainly for aufs which mmap(2) different file and wants to print different ++ * path in /proc/PID/maps. ++ * Call these functions via macros defined in linux/mm.h. ++ * ++ * See Documentation/filesystems/aufs/design/06mmap.txt ++ * ++ * Copyright (c) 2014-2019 Junjro R. Okajima ++ * Copyright (c) 2014 Ian Campbell ++ */ ++ ++#include ++#include ++#include ++ ++/* #define PRFILE_TRACE */ ++static inline void prfile_trace(struct file *f, struct file *pr, ++ const char func[], int line, const char func2[]) ++{ ++#ifdef PRFILE_TRACE ++ if (pr) ++ pr_info("%s:%d: %s, %pD2\n", func, line, func2, f); ++#endif ++} ++ ++void vma_do_file_update_time(struct vm_area_struct *vma, const char func[], ++ int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ file_update_time(f); ++ if (f && pr) ++ file_update_time(pr); ++} ++ ++struct file *vma_do_pr_or_file(struct vm_area_struct *vma, const char func[], ++ int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ return (f && pr) ? pr : f; ++} ++ ++void vma_do_get_file(struct vm_area_struct *vma, const char func[], int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ get_file(f); ++ if (f && pr) ++ get_file(pr); ++} ++ ++void vma_do_fput(struct vm_area_struct *vma, const char func[], int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ fput(f); ++ if (f && pr) ++ fput(pr); ++} ++ ++#ifndef CONFIG_MMU ++struct file *vmr_do_pr_or_file(struct vm_region *region, const char func[], ++ int line) ++{ ++ struct file *f = region->vm_file, *pr = region->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ return (f && pr) ? pr : f; ++} ++ ++void vmr_do_fput(struct vm_region *region, const char func[], int line) ++{ ++ struct file *f = region->vm_file, *pr = region->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ fput(f); ++ if (f && pr) ++ fput(pr); ++} ++#endif /* !CONFIG_MMU */ diff --git a/kernel/kernel/files/patches/mageia/fs-vboxsf.patch b/kernel/kernel/files/patches/mageia/fs-vboxsf.patch new file mode 100644 index 00000000..434fdee6 --- /dev/null +++ b/kernel/kernel/files/patches/mageia/fs-vboxsf.patch @@ -0,0 +1,3410 @@ +From df4028658f9dd7f82fd190e9db5bd82c05f94625 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 28 Oct 2019 12:17:44 +0100 +Subject: staging: Add VirtualBox guest shared folder (vboxsf) support + +VirtualBox hosts can share folders with guests, this commit adds a +VFS driver implementing the Linux-guest side of this, allowing folders +exported by the host to be mounted under Linux. + +This driver depends on the guest <-> host IPC functions exported by +the vboxguest driver. + +Signed-off-by: Hans de Goede +Link: https://lore.kernel.org/r/20191028111744.143863-2-hdegoede@redhat.com +Signed-off-by: Greg Kroah-Hartman +--- + MAINTAINERS | 6 + + drivers/staging/Kconfig | 2 + + drivers/staging/Makefile | 1 + + drivers/staging/vboxsf/Kconfig | 10 + + drivers/staging/vboxsf/Makefile | 5 + + drivers/staging/vboxsf/TODO | 7 + + drivers/staging/vboxsf/dir.c | 418 ++++++++++++++ + drivers/staging/vboxsf/file.c | 370 +++++++++++++ + drivers/staging/vboxsf/shfl_hostintf.h | 901 +++++++++++++++++++++++++++++++ + drivers/staging/vboxsf/super.c | 499 +++++++++++++++++ + drivers/staging/vboxsf/utils.c | 550 +++++++++++++++++++ + drivers/staging/vboxsf/vboxsf_wrappers.c | 371 +++++++++++++ + drivers/staging/vboxsf/vfsmod.h | 138 +++++ + 13 files changed, 3278 insertions(+) + create mode 100644 drivers/staging/vboxsf/Kconfig + create mode 100644 drivers/staging/vboxsf/Makefile + create mode 100644 drivers/staging/vboxsf/TODO + create mode 100644 drivers/staging/vboxsf/dir.c + create mode 100644 drivers/staging/vboxsf/file.c + create mode 100644 drivers/staging/vboxsf/shfl_hostintf.h + create mode 100644 drivers/staging/vboxsf/super.c + create mode 100644 drivers/staging/vboxsf/utils.c + create mode 100644 drivers/staging/vboxsf/vboxsf_wrappers.c + create mode 100644 drivers/staging/vboxsf/vfsmod.h + +diff --git a/MAINTAINERS b/MAINTAINERS +index c6c34d04ce95..71789e42ed17 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -17335,6 +17335,12 @@ F: include/linux/vbox_utils.h + F: include/uapi/linux/vbox*.h + F: drivers/virt/vboxguest/ + ++VIRTUAL BOX SHARED FOLDER VFS DRIVER: ++M: Hans de Goede ++L: linux-fsdevel@vger.kernel.org ++S: Maintained ++F: drivers/staging/vboxsf/* ++ + VIRTUAL SERIO DEVICE DRIVER + M: Stephen Chandler Paul + S: Maintained +diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig +index 6f1fa4c849a1..927d29eb92c6 100644 +--- a/drivers/staging/Kconfig ++++ b/drivers/staging/Kconfig +@@ -125,4 +125,6 @@ source "drivers/staging/exfat/Kconfig" + + source "drivers/staging/qlge/Kconfig" + ++source "drivers/staging/vboxsf/Kconfig" ++ + endif # STAGING +diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile +index a90f9b308c8d..f01f04199073 100644 +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -53,3 +53,4 @@ obj-$(CONFIG_UWB) += uwb/ + obj-$(CONFIG_USB_WUSB) += wusbcore/ + obj-$(CONFIG_EXFAT_FS) += exfat/ + obj-$(CONFIG_QLGE) += qlge/ ++obj-$(CONFIG_VBOXSF_FS) += vboxsf/ +diff --git a/drivers/staging/vboxsf/Kconfig b/drivers/staging/vboxsf/Kconfig +new file mode 100644 +index 000000000000..b84586ae08b3 +--- /dev/null ++++ b/drivers/staging/vboxsf/Kconfig +@@ -0,0 +1,10 @@ ++config VBOXSF_FS ++ tristate "VirtualBox guest shared folder (vboxsf) support" ++ depends on X86 && VBOXGUEST ++ select NLS ++ help ++ VirtualBox hosts can share folders with guests, this driver ++ implements the Linux-guest side of this allowing folders exported ++ by the host to be mounted under Linux. ++ ++ If you want to use shared folders in VirtualBox guests, answer Y or M. +diff --git a/drivers/staging/vboxsf/Makefile b/drivers/staging/vboxsf/Makefile +new file mode 100644 +index 000000000000..9e4328e79623 +--- /dev/null ++++ b/drivers/staging/vboxsf/Makefile +@@ -0,0 +1,5 @@ ++# SPDX-License-Identifier: MIT ++ ++obj-$(CONFIG_VBOXSF_FS) += vboxsf.o ++ ++vboxsf-y := dir.o file.o utils.o vboxsf_wrappers.o super.o +diff --git a/drivers/staging/vboxsf/TODO b/drivers/staging/vboxsf/TODO +new file mode 100644 +index 000000000000..8b9193d0d4f0 +--- /dev/null ++++ b/drivers/staging/vboxsf/TODO +@@ -0,0 +1,7 @@ ++TODO: ++- Find a file-system developer to review this and give their Reviewed-By ++- Address any items coming up during review ++- Move to fs/vboxfs ++ ++Please send any patches to Greg Kroah-Hartman ++and Hans de Goede +diff --git a/drivers/staging/vboxsf/dir.c b/drivers/staging/vboxsf/dir.c +new file mode 100644 +index 000000000000..f260b5cc1646 +--- /dev/null ++++ b/drivers/staging/vboxsf/dir.c +@@ -0,0 +1,418 @@ ++// SPDX-License-Identifier: MIT ++/* ++ * VirtualBox Guest Shared Folders support: Directory inode and file operations ++ * ++ * Copyright (C) 2006-2018 Oracle Corporation ++ */ ++ ++#include ++#include ++#include "vfsmod.h" ++ ++static int vboxsf_dir_open(struct inode *inode, struct file *file) ++{ ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(inode->i_sb); ++ struct shfl_createparms params = {}; ++ struct vboxsf_dir_info *sf_d; ++ int err; ++ ++ sf_d = vboxsf_dir_info_alloc(); ++ if (!sf_d) ++ return -ENOMEM; ++ ++ params.handle = SHFL_HANDLE_NIL; ++ params.create_flags = SHFL_CF_DIRECTORY | SHFL_CF_ACT_OPEN_IF_EXISTS | ++ SHFL_CF_ACT_FAIL_IF_NEW | SHFL_CF_ACCESS_READ; ++ ++ err = vboxsf_create_at_dentry(file_dentry(file), ¶ms); ++ if (err) ++ goto err_free_dir_info; ++ ++ if (params.result != SHFL_FILE_EXISTS) { ++ err = -ENOENT; ++ goto err_close; ++ } ++ ++ err = vboxsf_dir_read_all(sbi, sf_d, params.handle); ++ if (err) ++ goto err_close; ++ ++ vboxsf_close(sbi->root, params.handle); ++ file->private_data = sf_d; ++ return 0; ++ ++err_close: ++ vboxsf_close(sbi->root, params.handle); ++err_free_dir_info: ++ vboxsf_dir_info_free(sf_d); ++ return err; ++} ++ ++static int vboxsf_dir_release(struct inode *inode, struct file *file) ++{ ++ if (file->private_data) ++ vboxsf_dir_info_free(file->private_data); ++ ++ return 0; ++} ++ ++static unsigned int vboxsf_get_d_type(u32 mode) ++{ ++ unsigned int d_type; ++ ++ switch (mode & SHFL_TYPE_MASK) { ++ case SHFL_TYPE_FIFO: ++ d_type = DT_FIFO; ++ break; ++ case SHFL_TYPE_DEV_CHAR: ++ d_type = DT_CHR; ++ break; ++ case SHFL_TYPE_DIRECTORY: ++ d_type = DT_DIR; ++ break; ++ case SHFL_TYPE_DEV_BLOCK: ++ d_type = DT_BLK; ++ break; ++ case SHFL_TYPE_FILE: ++ d_type = DT_REG; ++ break; ++ case SHFL_TYPE_SYMLINK: ++ d_type = DT_LNK; ++ break; ++ case SHFL_TYPE_SOCKET: ++ d_type = DT_SOCK; ++ break; ++ case SHFL_TYPE_WHITEOUT: ++ d_type = DT_WHT; ++ break; ++ default: ++ d_type = DT_UNKNOWN; ++ break; ++ } ++ return d_type; ++} ++ ++static bool vboxsf_dir_emit(struct file *dir, struct dir_context *ctx) ++{ ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(file_inode(dir)->i_sb); ++ struct vboxsf_dir_info *sf_d = dir->private_data; ++ struct shfl_dirinfo *info; ++ struct vboxsf_dir_buf *b; ++ unsigned int d_type; ++ loff_t i, cur = 0; ++ ino_t fake_ino; ++ size_t size; ++ int err; ++ ++ list_for_each_entry(b, &sf_d->info_list, head) { ++try_next_entry: ++ if (ctx->pos >= cur + b->entries) { ++ cur += b->entries; ++ continue; ++ } ++ ++ /* ++ * Note the vboxsf_dir_info objects we are iterating over here ++ * are variable sized, so the info pointer may end up being ++ * unaligned. This is how we get the data from the host. ++ * Since vboxsf is only supported on x86 machines this is not ++ * a problem. ++ */ ++ for (i = 0, info = b->buf; i < ctx->pos - cur; i++) { ++ size = offsetof(struct shfl_dirinfo, name.string) + ++ info->name.size; ++ info = (struct shfl_dirinfo *)((uintptr_t)info + size); ++ } ++ ++ /* Info now points to the right entry, emit it. */ ++ d_type = vboxsf_get_d_type(info->info.attr.mode); ++ ++ /* ++ * On 32 bit systems pos is 64 signed, while ino is 32 bit ++ * unsigned so fake_ino may overflow, check for this. ++ */ ++ if ((ino_t)(ctx->pos + 1) != (u64)(ctx->pos + 1)) { ++ vbg_err("vboxsf: fake ino overflow, truncating dir\n"); ++ return false; ++ } ++ fake_ino = ctx->pos + 1; ++ ++ if (sbi->nls) { ++ char d_name[NAME_MAX]; ++ ++ err = vboxsf_nlscpy(sbi, d_name, NAME_MAX, ++ info->name.string.utf8, ++ info->name.length); ++ if (err) { ++ /* skip erroneous entry and proceed */ ++ ctx->pos += 1; ++ goto try_next_entry; ++ } ++ ++ return dir_emit(ctx, d_name, strlen(d_name), ++ fake_ino, d_type); ++ } ++ ++ return dir_emit(ctx, info->name.string.utf8, info->name.length, ++ fake_ino, d_type); ++ } ++ ++ return false; ++} ++ ++static int vboxsf_dir_iterate(struct file *dir, struct dir_context *ctx) ++{ ++ bool keep_iterating; ++ ++ for (keep_iterating = true; keep_iterating; ctx->pos += 1) ++ keep_iterating = vboxsf_dir_emit(dir, ctx); ++ ++ return 0; ++} ++ ++const struct file_operations vboxsf_dir_fops = { ++ .open = vboxsf_dir_open, ++ .iterate = vboxsf_dir_iterate, ++ .release = vboxsf_dir_release, ++ .read = generic_read_dir, ++ .llseek = generic_file_llseek, ++}; ++ ++/* ++ * This is called during name resolution/lookup to check if the @dentry in ++ * the cache is still valid. the job is handled by vboxsf_inode_revalidate. ++ */ ++static int vboxsf_dentry_revalidate(struct dentry *dentry, unsigned int flags) ++{ ++ if (flags & LOOKUP_RCU) ++ return -ECHILD; ++ ++ if (d_really_is_positive(dentry)) ++ return vboxsf_inode_revalidate(dentry) == 0; ++ else ++ return vboxsf_stat_dentry(dentry, NULL) == -ENOENT; ++} ++ ++const struct dentry_operations vboxsf_dentry_ops = { ++ .d_revalidate = vboxsf_dentry_revalidate ++}; ++ ++/* iops */ ++ ++static struct dentry *vboxsf_dir_lookup(struct inode *parent, ++ struct dentry *dentry, ++ unsigned int flags) ++{ ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(parent->i_sb); ++ struct shfl_fsobjinfo fsinfo; ++ struct inode *inode; ++ int err; ++ ++ dentry->d_time = jiffies; ++ ++ err = vboxsf_stat_dentry(dentry, &fsinfo); ++ if (err) { ++ inode = (err == -ENOENT) ? NULL : ERR_PTR(err); ++ } else { ++ inode = vboxsf_new_inode(parent->i_sb); ++ if (!IS_ERR(inode)) ++ vboxsf_init_inode(sbi, inode, &fsinfo); ++ } ++ ++ return d_splice_alias(inode, dentry); ++} ++ ++static int vboxsf_dir_instantiate(struct inode *parent, struct dentry *dentry, ++ struct shfl_fsobjinfo *info) ++{ ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(parent->i_sb); ++ struct vboxsf_inode *sf_i; ++ struct inode *inode; ++ ++ inode = vboxsf_new_inode(parent->i_sb); ++ if (IS_ERR(inode)) ++ return PTR_ERR(inode); ++ ++ sf_i = VBOXSF_I(inode); ++ /* The host may have given us different attr then requested */ ++ sf_i->force_restat = 1; ++ vboxsf_init_inode(sbi, inode, info); ++ ++ d_instantiate(dentry, inode); ++ ++ return 0; ++} ++ ++static int vboxsf_dir_create(struct inode *parent, struct dentry *dentry, ++ umode_t mode, int is_dir) ++{ ++ struct vboxsf_inode *sf_parent_i = VBOXSF_I(parent); ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(parent->i_sb); ++ struct shfl_createparms params = {}; ++ int err; ++ ++ params.handle = SHFL_HANDLE_NIL; ++ params.create_flags = SHFL_CF_ACT_CREATE_IF_NEW | ++ SHFL_CF_ACT_FAIL_IF_EXISTS | ++ SHFL_CF_ACCESS_READWRITE | ++ (is_dir ? SHFL_CF_DIRECTORY : 0); ++ params.info.attr.mode = (mode & 0777) | ++ (is_dir ? SHFL_TYPE_DIRECTORY : SHFL_TYPE_FILE); ++ params.info.attr.additional = SHFLFSOBJATTRADD_NOTHING; ++ ++ err = vboxsf_create_at_dentry(dentry, ¶ms); ++ if (err) ++ return err; ++ ++ if (params.result != SHFL_FILE_CREATED) ++ return -EPERM; ++ ++ vboxsf_close(sbi->root, params.handle); ++ ++ err = vboxsf_dir_instantiate(parent, dentry, ¶ms.info); ++ if (err) ++ return err; ++ ++ /* parent directory access/change time changed */ ++ sf_parent_i->force_restat = 1; ++ ++ return 0; ++} ++ ++static int vboxsf_dir_mkfile(struct inode *parent, struct dentry *dentry, ++ umode_t mode, bool excl) ++{ ++ return vboxsf_dir_create(parent, dentry, mode, 0); ++} ++ ++static int vboxsf_dir_mkdir(struct inode *parent, struct dentry *dentry, ++ umode_t mode) ++{ ++ return vboxsf_dir_create(parent, dentry, mode, 1); ++} ++ ++static int vboxsf_dir_unlink(struct inode *parent, struct dentry *dentry) ++{ ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(parent->i_sb); ++ struct vboxsf_inode *sf_parent_i = VBOXSF_I(parent); ++ struct inode *inode = d_inode(dentry); ++ struct shfl_string *path; ++ u32 flags; ++ int err; ++ ++ if (S_ISDIR(inode->i_mode)) ++ flags = SHFL_REMOVE_DIR; ++ else ++ flags = SHFL_REMOVE_FILE; ++ ++ if (S_ISLNK(inode->i_mode)) ++ flags |= SHFL_REMOVE_SYMLINK; ++ ++ path = vboxsf_path_from_dentry(sbi, dentry); ++ if (IS_ERR(path)) ++ return PTR_ERR(path); ++ ++ err = vboxsf_remove(sbi->root, path, flags); ++ __putname(path); ++ if (err) ++ return err; ++ ++ /* parent directory access/change time changed */ ++ sf_parent_i->force_restat = 1; ++ ++ return 0; ++} ++ ++static int vboxsf_dir_rename(struct inode *old_parent, ++ struct dentry *old_dentry, ++ struct inode *new_parent, ++ struct dentry *new_dentry, ++ unsigned int flags) ++{ ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(old_parent->i_sb); ++ struct vboxsf_inode *sf_old_parent_i = VBOXSF_I(old_parent); ++ struct vboxsf_inode *sf_new_parent_i = VBOXSF_I(new_parent); ++ u32 shfl_flags = SHFL_RENAME_FILE | SHFL_RENAME_REPLACE_IF_EXISTS; ++ struct shfl_string *old_path, *new_path; ++ int err; ++ ++ if (flags) ++ return -EINVAL; ++ ++ old_path = vboxsf_path_from_dentry(sbi, old_dentry); ++ if (IS_ERR(old_path)) ++ return PTR_ERR(old_path); ++ ++ new_path = vboxsf_path_from_dentry(sbi, new_dentry); ++ if (IS_ERR(new_path)) { ++ err = PTR_ERR(new_path); ++ goto err_put_old_path; ++ } ++ ++ if (d_inode(old_dentry)->i_mode & S_IFDIR) ++ shfl_flags = 0; ++ ++ err = vboxsf_rename(sbi->root, old_path, new_path, shfl_flags); ++ if (err == 0) { ++ /* parent directories access/change time changed */ ++ sf_new_parent_i->force_restat = 1; ++ sf_old_parent_i->force_restat = 1; ++ } ++ ++ __putname(new_path); ++err_put_old_path: ++ __putname(old_path); ++ return err; ++} ++ ++static int vboxsf_dir_symlink(struct inode *parent, struct dentry *dentry, ++ const char *symname) ++{ ++ struct vboxsf_inode *sf_parent_i = VBOXSF_I(parent); ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(parent->i_sb); ++ int symname_size = strlen(symname) + 1; ++ struct shfl_string *path, *ssymname; ++ struct shfl_fsobjinfo info; ++ int err; ++ ++ path = vboxsf_path_from_dentry(sbi, dentry); ++ if (IS_ERR(path)) ++ return PTR_ERR(path); ++ ++ ssymname = kmalloc(SHFLSTRING_HEADER_SIZE + symname_size, GFP_KERNEL); ++ if (!ssymname) { ++ __putname(path); ++ return -ENOMEM; ++ } ++ ssymname->length = symname_size - 1; ++ ssymname->size = symname_size; ++ memcpy(ssymname->string.utf8, symname, symname_size); ++ ++ err = vboxsf_symlink(sbi->root, path, ssymname, &info); ++ kfree(ssymname); ++ __putname(path); ++ if (err) { ++ /* -EROFS means symlinks are note support -> -EPERM */ ++ return (err == -EROFS) ? -EPERM : err; ++ } ++ ++ err = vboxsf_dir_instantiate(parent, dentry, &info); ++ if (err) ++ return err; ++ ++ /* parent directory access/change time changed */ ++ sf_parent_i->force_restat = 1; ++ return 0; ++} ++ ++const struct inode_operations vboxsf_dir_iops = { ++ .lookup = vboxsf_dir_lookup, ++ .create = vboxsf_dir_mkfile, ++ .mkdir = vboxsf_dir_mkdir, ++ .rmdir = vboxsf_dir_unlink, ++ .unlink = vboxsf_dir_unlink, ++ .rename = vboxsf_dir_rename, ++ .symlink = vboxsf_dir_symlink, ++ .getattr = vboxsf_getattr, ++ .setattr = vboxsf_setattr, ++}; +diff --git a/drivers/staging/vboxsf/file.c b/drivers/staging/vboxsf/file.c +new file mode 100644 +index 000000000000..4b61ccf83fca +--- /dev/null ++++ b/drivers/staging/vboxsf/file.c +@@ -0,0 +1,370 @@ ++// SPDX-License-Identifier: MIT ++/* ++ * VirtualBox Guest Shared Folders support: Regular file inode and file ops. ++ * ++ * Copyright (C) 2006-2018 Oracle Corporation ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "vfsmod.h" ++ ++struct vboxsf_handle { ++ u64 handle; ++ u32 root; ++ u32 access_flags; ++ struct kref refcount; ++ struct list_head head; ++}; ++ ++static int vboxsf_file_open(struct inode *inode, struct file *file) ++{ ++ struct vboxsf_inode *sf_i = VBOXSF_I(inode); ++ struct shfl_createparms params = {}; ++ struct vboxsf_handle *sf_handle; ++ u32 access_flags = 0; ++ int err; ++ ++ sf_handle = kmalloc(sizeof(*sf_handle), GFP_KERNEL); ++ if (!sf_handle) ++ return -ENOMEM; ++ ++ /* ++ * We check the value of params.handle afterwards to find out if ++ * the call succeeded or failed, as the API does not seem to cleanly ++ * distinguish error and informational messages. ++ * ++ * Furthermore, we must set params.handle to SHFL_HANDLE_NIL to ++ * make the shared folders host service use our mode parameter. ++ */ ++ params.handle = SHFL_HANDLE_NIL; ++ if (file->f_flags & O_CREAT) { ++ params.create_flags |= SHFL_CF_ACT_CREATE_IF_NEW; ++ /* ++ * We ignore O_EXCL, as the Linux kernel seems to call create ++ * beforehand itself, so O_EXCL should always fail. ++ */ ++ if (file->f_flags & O_TRUNC) ++ params.create_flags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS; ++ else ++ params.create_flags |= SHFL_CF_ACT_OPEN_IF_EXISTS; ++ } else { ++ params.create_flags |= SHFL_CF_ACT_FAIL_IF_NEW; ++ if (file->f_flags & O_TRUNC) ++ params.create_flags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS; ++ } ++ ++ switch (file->f_flags & O_ACCMODE) { ++ case O_RDONLY: ++ access_flags |= SHFL_CF_ACCESS_READ; ++ break; ++ ++ case O_WRONLY: ++ access_flags |= SHFL_CF_ACCESS_WRITE; ++ break; ++ ++ case O_RDWR: ++ access_flags |= SHFL_CF_ACCESS_READWRITE; ++ break; ++ ++ default: ++ WARN_ON(1); ++ } ++ ++ if (file->f_flags & O_APPEND) ++ access_flags |= SHFL_CF_ACCESS_APPEND; ++ ++ params.create_flags |= access_flags; ++ params.info.attr.mode = inode->i_mode; ++ ++ err = vboxsf_create_at_dentry(file_dentry(file), ¶ms); ++ if (err == 0 && params.handle == SHFL_HANDLE_NIL) ++ err = (params.result == SHFL_FILE_EXISTS) ? -EEXIST : -ENOENT; ++ if (err) { ++ kfree(sf_handle); ++ return err; ++ } ++ ++ /* the host may have given us different attr then requested */ ++ sf_i->force_restat = 1; ++ ++ /* init our handle struct and add it to the inode's handles list */ ++ sf_handle->handle = params.handle; ++ sf_handle->root = VBOXSF_SBI(inode->i_sb)->root; ++ sf_handle->access_flags = access_flags; ++ kref_init(&sf_handle->refcount); ++ ++ mutex_lock(&sf_i->handle_list_mutex); ++ list_add(&sf_handle->head, &sf_i->handle_list); ++ mutex_unlock(&sf_i->handle_list_mutex); ++ ++ file->private_data = sf_handle; ++ return 0; ++} ++ ++static void vboxsf_handle_release(struct kref *refcount) ++{ ++ struct vboxsf_handle *sf_handle = ++ container_of(refcount, struct vboxsf_handle, refcount); ++ ++ vboxsf_close(sf_handle->root, sf_handle->handle); ++ kfree(sf_handle); ++} ++ ++static int vboxsf_file_release(struct inode *inode, struct file *file) ++{ ++ struct vboxsf_inode *sf_i = VBOXSF_I(inode); ++ struct vboxsf_handle *sf_handle = file->private_data; ++ ++ /* ++ * When a file is closed on our (the guest) side, we want any subsequent ++ * accesses done on the host side to see all changes done from our side. ++ */ ++ filemap_write_and_wait(inode->i_mapping); ++ ++ mutex_lock(&sf_i->handle_list_mutex); ++ list_del(&sf_handle->head); ++ mutex_unlock(&sf_i->handle_list_mutex); ++ ++ kref_put(&sf_handle->refcount, vboxsf_handle_release); ++ return 0; ++} ++ ++/* ++ * Write back dirty pages now, because there may not be any suitable ++ * open files later ++ */ ++static void vboxsf_vma_close(struct vm_area_struct *vma) ++{ ++ filemap_write_and_wait(vma->vm_file->f_mapping); ++} ++ ++static const struct vm_operations_struct vboxsf_file_vm_ops = { ++ .close = vboxsf_vma_close, ++ .fault = filemap_fault, ++ .map_pages = filemap_map_pages, ++}; ++ ++static int vboxsf_file_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ int err; ++ ++ err = generic_file_mmap(file, vma); ++ if (!err) ++ vma->vm_ops = &vboxsf_file_vm_ops; ++ ++ return err; ++} ++ ++/* ++ * Note that since we are accessing files on the host's filesystem, files ++ * may always be changed underneath us by the host! ++ * ++ * The vboxsf API between the guest and the host does not offer any functions ++ * to deal with this. There is no inode-generation to check for changes, no ++ * events / callback on changes and no way to lock files. ++ * ++ * To avoid returning stale data when a file gets *opened* on our (the guest) ++ * side, we do a "stat" on the host side, then compare the mtime with the ++ * last known mtime and invalidate the page-cache if they differ. ++ * This is done from vboxsf_inode_revalidate(). ++ * ++ * When reads are done through the read_iter fop, it is possible to do ++ * further cache revalidation then, there are 3 options to deal with this: ++ * ++ * 1) Rely solely on the revalidation done at open time ++ * 2) Do another "stat" and compare mtime again. Unfortunately the vboxsf ++ * host API does not allow stat on handles, so we would need to use ++ * file->f_path.dentry and the stat will then fail if the file was unlinked ++ * or renamed (and there is no thing like NFS' silly-rename). So we get: ++ * 2a) "stat" and compare mtime, on stat failure invalidate the cache ++ * 2b) "stat" and compare mtime, on stat failure do nothing ++ * 3) Simply always call invalidate_inode_pages2_range on the range of the read ++ * ++ * Currently we are keeping things KISS and using option 1. this allows ++ * directly using generic_file_read_iter without wrapping it. ++ * ++ * This means that only data written on the host side before open() on ++ * the guest side is guaranteed to be seen by the guest. If necessary ++ * we may provide other read-cache strategies in the future and make this ++ * configurable through a mount option. ++ */ ++const struct file_operations vboxsf_reg_fops = { ++ .llseek = generic_file_llseek, ++ .read_iter = generic_file_read_iter, ++ .write_iter = generic_file_write_iter, ++ .mmap = vboxsf_file_mmap, ++ .open = vboxsf_file_open, ++ .release = vboxsf_file_release, ++ .fsync = noop_fsync, ++ .splice_read = generic_file_splice_read, ++}; ++ ++const struct inode_operations vboxsf_reg_iops = { ++ .getattr = vboxsf_getattr, ++ .setattr = vboxsf_setattr ++}; ++ ++static int vboxsf_readpage(struct file *file, struct page *page) ++{ ++ struct vboxsf_handle *sf_handle = file->private_data; ++ loff_t off = page_offset(page); ++ u32 nread = PAGE_SIZE; ++ u8 *buf; ++ int err; ++ ++ buf = kmap(page); ++ ++ err = vboxsf_read(sf_handle->root, sf_handle->handle, off, &nread, buf); ++ if (err == 0) { ++ memset(&buf[nread], 0, PAGE_SIZE - nread); ++ flush_dcache_page(page); ++ SetPageUptodate(page); ++ } else { ++ SetPageError(page); ++ } ++ ++ kunmap(page); ++ unlock_page(page); ++ return err; ++} ++ ++static struct vboxsf_handle *vboxsf_get_write_handle(struct vboxsf_inode *sf_i) ++{ ++ struct vboxsf_handle *h, *sf_handle = NULL; ++ ++ mutex_lock(&sf_i->handle_list_mutex); ++ list_for_each_entry(h, &sf_i->handle_list, head) { ++ if (h->access_flags == SHFL_CF_ACCESS_WRITE || ++ h->access_flags == SHFL_CF_ACCESS_READWRITE) { ++ kref_get(&h->refcount); ++ sf_handle = h; ++ break; ++ } ++ } ++ mutex_unlock(&sf_i->handle_list_mutex); ++ ++ return sf_handle; ++} ++ ++static int vboxsf_writepage(struct page *page, struct writeback_control *wbc) ++{ ++ struct inode *inode = page->mapping->host; ++ struct vboxsf_inode *sf_i = VBOXSF_I(inode); ++ struct vboxsf_handle *sf_handle; ++ loff_t off = page_offset(page); ++ loff_t size = i_size_read(inode); ++ u32 nwrite = PAGE_SIZE; ++ u8 *buf; ++ int err; ++ ++ if (off + PAGE_SIZE > size) ++ nwrite = size & ~PAGE_MASK; ++ ++ sf_handle = vboxsf_get_write_handle(sf_i); ++ if (!sf_handle) ++ return -EBADF; ++ ++ buf = kmap(page); ++ err = vboxsf_write(sf_handle->root, sf_handle->handle, ++ off, &nwrite, buf); ++ kunmap(page); ++ ++ kref_put(&sf_handle->refcount, vboxsf_handle_release); ++ ++ if (err == 0) { ++ ClearPageError(page); ++ /* mtime changed */ ++ sf_i->force_restat = 1; ++ } else { ++ ClearPageUptodate(page); ++ } ++ ++ unlock_page(page); ++ return err; ++} ++ ++static int vboxsf_write_end(struct file *file, struct address_space *mapping, ++ loff_t pos, unsigned int len, unsigned int copied, ++ struct page *page, void *fsdata) ++{ ++ struct inode *inode = mapping->host; ++ struct vboxsf_handle *sf_handle = file->private_data; ++ unsigned int from = pos & ~PAGE_MASK; ++ u32 nwritten = len; ++ u8 *buf; ++ int err; ++ ++ buf = kmap(page); ++ err = vboxsf_write(sf_handle->root, sf_handle->handle, ++ pos, &nwritten, buf + from); ++ kunmap(page); ++ ++ if (err) { ++ nwritten = 0; ++ goto out; ++ } ++ ++ /* mtime changed */ ++ VBOXSF_I(inode)->force_restat = 1; ++ ++ if (!PageUptodate(page) && nwritten == PAGE_SIZE) ++ SetPageUptodate(page); ++ ++ pos += nwritten; ++ if (pos > inode->i_size) ++ i_size_write(inode, pos); ++ ++out: ++ unlock_page(page); ++ put_page(page); ++ ++ return nwritten; ++} ++ ++const struct address_space_operations vboxsf_reg_aops = { ++ .readpage = vboxsf_readpage, ++ .writepage = vboxsf_writepage, ++ .set_page_dirty = __set_page_dirty_nobuffers, ++ .write_begin = simple_write_begin, ++ .write_end = vboxsf_write_end, ++}; ++ ++static const char *vboxsf_get_link(struct dentry *dentry, struct inode *inode, ++ struct delayed_call *done) ++{ ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(inode->i_sb); ++ struct shfl_string *path; ++ char *link; ++ int err; ++ ++ if (!dentry) ++ return ERR_PTR(-ECHILD); ++ ++ path = vboxsf_path_from_dentry(sbi, dentry); ++ if (IS_ERR(path)) ++ return (char *)path; ++ ++ link = kzalloc(PATH_MAX, GFP_KERNEL); ++ if (!link) { ++ __putname(path); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ err = vboxsf_readlink(sbi->root, path, PATH_MAX, link); ++ __putname(path); ++ if (err) { ++ kfree(link); ++ return ERR_PTR(err); ++ } ++ ++ set_delayed_call(done, kfree_link, link); ++ return link; ++} ++ ++const struct inode_operations vboxsf_lnk_iops = { ++ .get_link = vboxsf_get_link ++}; +diff --git a/drivers/staging/vboxsf/shfl_hostintf.h b/drivers/staging/vboxsf/shfl_hostintf.h +new file mode 100644 +index 000000000000..aca829062c12 +--- /dev/null ++++ b/drivers/staging/vboxsf/shfl_hostintf.h +@@ -0,0 +1,901 @@ ++/* SPDX-License-Identifier: MIT */ ++/* ++ * VirtualBox Shared Folders: host interface definition. ++ * ++ * Copyright (C) 2006-2018 Oracle Corporation ++ */ ++ ++#ifndef SHFL_HOSTINTF_H ++#define SHFL_HOSTINTF_H ++ ++#include ++ ++/* The max in/out buffer size for a FN_READ or FN_WRITE call */ ++#define SHFL_MAX_RW_COUNT (16 * SZ_1M) ++ ++/* ++ * Structures shared between guest and the service ++ * can be relocated and use offsets to point to variable ++ * length parts. ++ * ++ * Shared folders protocol works with handles. ++ * Before doing any action on a file system object, ++ * one have to obtain the object handle via a SHFL_FN_CREATE ++ * request. A handle must be closed with SHFL_FN_CLOSE. ++ */ ++ ++enum { ++ SHFL_FN_QUERY_MAPPINGS = 1, /* Query mappings changes. */ ++ SHFL_FN_QUERY_MAP_NAME = 2, /* Query map name. */ ++ SHFL_FN_CREATE = 3, /* Open/create object. */ ++ SHFL_FN_CLOSE = 4, /* Close object handle. */ ++ SHFL_FN_READ = 5, /* Read object content. */ ++ SHFL_FN_WRITE = 6, /* Write new object content. */ ++ SHFL_FN_LOCK = 7, /* Lock/unlock a range in the object. */ ++ SHFL_FN_LIST = 8, /* List object content. */ ++ SHFL_FN_INFORMATION = 9, /* Query/set object information. */ ++ /* Note function number 10 is not used! */ ++ SHFL_FN_REMOVE = 11, /* Remove object */ ++ SHFL_FN_MAP_FOLDER_OLD = 12, /* Map folder (legacy) */ ++ SHFL_FN_UNMAP_FOLDER = 13, /* Unmap folder */ ++ SHFL_FN_RENAME = 14, /* Rename object */ ++ SHFL_FN_FLUSH = 15, /* Flush file */ ++ SHFL_FN_SET_UTF8 = 16, /* Select UTF8 filename encoding */ ++ SHFL_FN_MAP_FOLDER = 17, /* Map folder */ ++ SHFL_FN_READLINK = 18, /* Read symlink dest (as of VBox 4.0) */ ++ SHFL_FN_SYMLINK = 19, /* Create symlink (as of VBox 4.0) */ ++ SHFL_FN_SET_SYMLINKS = 20, /* Ask host to show symlinks (4.0+) */ ++}; ++ ++/* Root handles for a mapping are of type u32, Root handles are unique. */ ++#define SHFL_ROOT_NIL UINT_MAX ++ ++/* Shared folders handle for an opened object are of type u64. */ ++#define SHFL_HANDLE_NIL ULLONG_MAX ++ ++/* Hardcoded maximum length (in chars) of a shared folder name. */ ++#define SHFL_MAX_LEN (256) ++/* Hardcoded maximum number of shared folder mapping available to the guest. */ ++#define SHFL_MAX_MAPPINGS (64) ++ ++/** Shared folder string buffer structure. */ ++struct shfl_string { ++ /** Allocated size of the string member in bytes. */ ++ u16 size; ++ ++ /** Length of string without trailing nul in bytes. */ ++ u16 length; ++ ++ /** UTF-8 or UTF-16 string. Nul terminated. */ ++ union { ++ u8 utf8[2]; ++ u16 utf16[1]; ++ u16 ucs2[1]; /* misnomer, use utf16. */ ++ } string; ++}; ++VMMDEV_ASSERT_SIZE(shfl_string, 6); ++ ++/* The size of shfl_string w/o the string part. */ ++#define SHFLSTRING_HEADER_SIZE 4 ++ ++/* Calculate size of the string. */ ++static inline u32 shfl_string_buf_size(const struct shfl_string *string) ++{ ++ return string ? SHFLSTRING_HEADER_SIZE + string->size : 0; ++} ++ ++/* Set user id on execution (S_ISUID). */ ++#define SHFL_UNIX_ISUID 0004000U ++/* Set group id on execution (S_ISGID). */ ++#define SHFL_UNIX_ISGID 0002000U ++/* Sticky bit (S_ISVTX / S_ISTXT). */ ++#define SHFL_UNIX_ISTXT 0001000U ++ ++/* Owner readable (S_IRUSR). */ ++#define SHFL_UNIX_IRUSR 0000400U ++/* Owner writable (S_IWUSR). */ ++#define SHFL_UNIX_IWUSR 0000200U ++/* Owner executable (S_IXUSR). */ ++#define SHFL_UNIX_IXUSR 0000100U ++ ++/* Group readable (S_IRGRP). */ ++#define SHFL_UNIX_IRGRP 0000040U ++/* Group writable (S_IWGRP). */ ++#define SHFL_UNIX_IWGRP 0000020U ++/* Group executable (S_IXGRP). */ ++#define SHFL_UNIX_IXGRP 0000010U ++ ++/* Other readable (S_IROTH). */ ++#define SHFL_UNIX_IROTH 0000004U ++/* Other writable (S_IWOTH). */ ++#define SHFL_UNIX_IWOTH 0000002U ++/* Other executable (S_IXOTH). */ ++#define SHFL_UNIX_IXOTH 0000001U ++ ++/* Named pipe (fifo) (S_IFIFO). */ ++#define SHFL_TYPE_FIFO 0010000U ++/* Character device (S_IFCHR). */ ++#define SHFL_TYPE_DEV_CHAR 0020000U ++/* Directory (S_IFDIR). */ ++#define SHFL_TYPE_DIRECTORY 0040000U ++/* Block device (S_IFBLK). */ ++#define SHFL_TYPE_DEV_BLOCK 0060000U ++/* Regular file (S_IFREG). */ ++#define SHFL_TYPE_FILE 0100000U ++/* Symbolic link (S_IFLNK). */ ++#define SHFL_TYPE_SYMLINK 0120000U ++/* Socket (S_IFSOCK). */ ++#define SHFL_TYPE_SOCKET 0140000U ++/* Whiteout (S_IFWHT). */ ++#define SHFL_TYPE_WHITEOUT 0160000U ++/* Type mask (S_IFMT). */ ++#define SHFL_TYPE_MASK 0170000U ++ ++/* Checks the mode flags indicate a directory (S_ISDIR). */ ++#define SHFL_IS_DIRECTORY(m) (((m) & SHFL_TYPE_MASK) == SHFL_TYPE_DIRECTORY) ++/* Checks the mode flags indicate a symbolic link (S_ISLNK). */ ++#define SHFL_IS_SYMLINK(m) (((m) & SHFL_TYPE_MASK) == SHFL_TYPE_SYMLINK) ++ ++/** The available additional information in a shfl_fsobjattr object. */ ++enum shfl_fsobjattr_add { ++ /** No additional information is available / requested. */ ++ SHFLFSOBJATTRADD_NOTHING = 1, ++ /** ++ * The additional unix attributes (shfl_fsobjattr::u::unix_attr) are ++ * available / requested. ++ */ ++ SHFLFSOBJATTRADD_UNIX, ++ /** ++ * The additional extended attribute size (shfl_fsobjattr::u::size) is ++ * available / requested. ++ */ ++ SHFLFSOBJATTRADD_EASIZE, ++ /** ++ * The last valid item (inclusive). ++ * The valid range is SHFLFSOBJATTRADD_NOTHING thru ++ * SHFLFSOBJATTRADD_LAST. ++ */ ++ SHFLFSOBJATTRADD_LAST = SHFLFSOBJATTRADD_EASIZE, ++ ++ /** The usual 32-bit hack. */ ++ SHFLFSOBJATTRADD_32BIT_SIZE_HACK = 0x7fffffff ++}; ++ ++/** ++ * Additional unix Attributes, these are available when ++ * shfl_fsobjattr.additional == SHFLFSOBJATTRADD_UNIX. ++ */ ++struct shfl_fsobjattr_unix { ++ /** ++ * The user owning the filesystem object (st_uid). ++ * This field is ~0U if not supported. ++ */ ++ u32 uid; ++ ++ /** ++ * The group the filesystem object is assigned (st_gid). ++ * This field is ~0U if not supported. ++ */ ++ u32 gid; ++ ++ /** ++ * Number of hard links to this filesystem object (st_nlink). ++ * This field is 1 if the filesystem doesn't support hardlinking or ++ * the information isn't available. ++ */ ++ u32 hardlinks; ++ ++ /** ++ * The device number of the device which this filesystem object resides ++ * on (st_dev). This field is 0 if this information is not available. ++ */ ++ u32 inode_id_device; ++ ++ /** ++ * The unique identifier (within the filesystem) of this filesystem ++ * object (st_ino). Together with inode_id_device, this field can be ++ * used as a OS wide unique id, when both their values are not 0. ++ * This field is 0 if the information is not available. ++ */ ++ u64 inode_id; ++ ++ /** ++ * User flags (st_flags). ++ * This field is 0 if this information is not available. ++ */ ++ u32 flags; ++ ++ /** ++ * The current generation number (st_gen). ++ * This field is 0 if this information is not available. ++ */ ++ u32 generation_id; ++ ++ /** ++ * The device number of a char. or block device type object (st_rdev). ++ * This field is 0 if the file isn't a char. or block device or when ++ * the OS doesn't use the major+minor device idenfication scheme. ++ */ ++ u32 device; ++} __packed; ++ ++/** Extended attribute size. */ ++struct shfl_fsobjattr_easize { ++ /** Size of EAs. */ ++ s64 cb; ++} __packed; ++ ++/** Shared folder filesystem object attributes. */ ++struct shfl_fsobjattr { ++ /** Mode flags (st_mode). SHFL_UNIX_*, SHFL_TYPE_*, and SHFL_DOS_*. */ ++ u32 mode; ++ ++ /** The additional attributes available. */ ++ enum shfl_fsobjattr_add additional; ++ ++ /** ++ * Additional attributes. ++ * ++ * Unless explicitly specified to an API, the API can provide additional ++ * data as it is provided by the underlying OS. ++ */ ++ union { ++ struct shfl_fsobjattr_unix unix_attr; ++ struct shfl_fsobjattr_easize size; ++ } __packed u; ++} __packed; ++VMMDEV_ASSERT_SIZE(shfl_fsobjattr, 44); ++ ++struct shfl_timespec { ++ s64 ns_relative_to_unix_epoch; ++}; ++ ++/** Filesystem object information structure. */ ++struct shfl_fsobjinfo { ++ /** ++ * Logical size (st_size). ++ * For normal files this is the size of the file. ++ * For symbolic links, this is the length of the path name contained ++ * in the symbolic link. ++ * For other objects this fields needs to be specified. ++ */ ++ s64 size; ++ ++ /** Disk allocation size (st_blocks * DEV_BSIZE). */ ++ s64 allocated; ++ ++ /** Time of last access (st_atime). */ ++ struct shfl_timespec access_time; ++ ++ /** Time of last data modification (st_mtime). */ ++ struct shfl_timespec modification_time; ++ ++ /** ++ * Time of last status change (st_ctime). ++ * If not available this is set to modification_time. ++ */ ++ struct shfl_timespec change_time; ++ ++ /** ++ * Time of file birth (st_birthtime). ++ * If not available this is set to change_time. ++ */ ++ struct shfl_timespec birth_time; ++ ++ /** Attributes. */ ++ struct shfl_fsobjattr attr; ++ ++} __packed; ++VMMDEV_ASSERT_SIZE(shfl_fsobjinfo, 92); ++ ++/** ++ * result of an open/create request. ++ * Along with handle value the result code ++ * identifies what has happened while ++ * trying to open the object. ++ */ ++enum shfl_create_result { ++ SHFL_NO_RESULT, ++ /** Specified path does not exist. */ ++ SHFL_PATH_NOT_FOUND, ++ /** Path to file exists, but the last component does not. */ ++ SHFL_FILE_NOT_FOUND, ++ /** File already exists and either has been opened or not. */ ++ SHFL_FILE_EXISTS, ++ /** New file was created. */ ++ SHFL_FILE_CREATED, ++ /** Existing file was replaced or overwritten. */ ++ SHFL_FILE_REPLACED ++}; ++ ++/* No flags. Initialization value. */ ++#define SHFL_CF_NONE (0x00000000) ++ ++/* ++ * Only lookup the object, do not return a handle. When this is set all other ++ * flags are ignored. ++ */ ++#define SHFL_CF_LOOKUP (0x00000001) ++ ++/* ++ * Open parent directory of specified object. ++ * Useful for the corresponding Windows FSD flag ++ * and for opening paths like \\dir\\*.* to search the 'dir'. ++ */ ++#define SHFL_CF_OPEN_TARGET_DIRECTORY (0x00000002) ++ ++/* Create/open a directory. */ ++#define SHFL_CF_DIRECTORY (0x00000004) ++ ++/* ++ * Open/create action to do if object exists ++ * and if the object does not exists. ++ * REPLACE file means atomically DELETE and CREATE. ++ * OVERWRITE file means truncating the file to 0 and ++ * setting new size. ++ * When opening an existing directory REPLACE and OVERWRITE ++ * actions are considered invalid, and cause returning ++ * FILE_EXISTS with NIL handle. ++ */ ++#define SHFL_CF_ACT_MASK_IF_EXISTS (0x000000f0) ++#define SHFL_CF_ACT_MASK_IF_NEW (0x00000f00) ++ ++/* What to do if object exists. */ ++#define SHFL_CF_ACT_OPEN_IF_EXISTS (0x00000000) ++#define SHFL_CF_ACT_FAIL_IF_EXISTS (0x00000010) ++#define SHFL_CF_ACT_REPLACE_IF_EXISTS (0x00000020) ++#define SHFL_CF_ACT_OVERWRITE_IF_EXISTS (0x00000030) ++ ++/* What to do if object does not exist. */ ++#define SHFL_CF_ACT_CREATE_IF_NEW (0x00000000) ++#define SHFL_CF_ACT_FAIL_IF_NEW (0x00000100) ++ ++/* Read/write requested access for the object. */ ++#define SHFL_CF_ACCESS_MASK_RW (0x00003000) ++ ++/* No access requested. */ ++#define SHFL_CF_ACCESS_NONE (0x00000000) ++/* Read access requested. */ ++#define SHFL_CF_ACCESS_READ (0x00001000) ++/* Write access requested. */ ++#define SHFL_CF_ACCESS_WRITE (0x00002000) ++/* Read/Write access requested. */ ++#define SHFL_CF_ACCESS_READWRITE (0x00003000) ++ ++/* Requested share access for the object. */ ++#define SHFL_CF_ACCESS_MASK_DENY (0x0000c000) ++ ++/* Allow any access. */ ++#define SHFL_CF_ACCESS_DENYNONE (0x00000000) ++/* Do not allow read. */ ++#define SHFL_CF_ACCESS_DENYREAD (0x00004000) ++/* Do not allow write. */ ++#define SHFL_CF_ACCESS_DENYWRITE (0x00008000) ++/* Do not allow access. */ ++#define SHFL_CF_ACCESS_DENYALL (0x0000c000) ++ ++/* Requested access to attributes of the object. */ ++#define SHFL_CF_ACCESS_MASK_ATTR (0x00030000) ++ ++/* No access requested. */ ++#define SHFL_CF_ACCESS_ATTR_NONE (0x00000000) ++/* Read access requested. */ ++#define SHFL_CF_ACCESS_ATTR_READ (0x00010000) ++/* Write access requested. */ ++#define SHFL_CF_ACCESS_ATTR_WRITE (0x00020000) ++/* Read/Write access requested. */ ++#define SHFL_CF_ACCESS_ATTR_READWRITE (0x00030000) ++ ++/* ++ * The file is opened in append mode. ++ * Ignored if SHFL_CF_ACCESS_WRITE is not set. ++ */ ++#define SHFL_CF_ACCESS_APPEND (0x00040000) ++ ++/** Create parameters buffer struct for SHFL_FN_CREATE call */ ++struct shfl_createparms { ++ /** Returned handle of opened object. */ ++ u64 handle; ++ ++ /** Returned result of the operation */ ++ enum shfl_create_result result; ++ ++ /** SHFL_CF_* */ ++ u32 create_flags; ++ ++ /** ++ * Attributes of object to create and ++ * returned actual attributes of opened/created object. ++ */ ++ struct shfl_fsobjinfo info; ++} __packed; ++ ++/** Shared Folder directory information */ ++struct shfl_dirinfo { ++ /** Full information about the object. */ ++ struct shfl_fsobjinfo info; ++ /** ++ * The length of the short field (number of UTF16 chars). ++ * It is 16-bit for reasons of alignment. ++ */ ++ u16 short_name_len; ++ /** ++ * The short name for 8.3 compatibility. ++ * Empty string if not available. ++ */ ++ u16 short_name[14]; ++ struct shfl_string name; ++}; ++ ++/** Shared folder filesystem properties. */ ++struct shfl_fsproperties { ++ /** ++ * The maximum size of a filesystem object name. ++ * This does not include the '\\0'. ++ */ ++ u32 max_component_len; ++ ++ /** ++ * True if the filesystem is remote. ++ * False if the filesystem is local. ++ */ ++ bool remote; ++ ++ /** ++ * True if the filesystem is case sensitive. ++ * False if the filesystem is case insensitive. ++ */ ++ bool case_sensitive; ++ ++ /** ++ * True if the filesystem is mounted read only. ++ * False if the filesystem is mounted read write. ++ */ ++ bool read_only; ++ ++ /** ++ * True if the filesystem can encode unicode object names. ++ * False if it can't. ++ */ ++ bool supports_unicode; ++ ++ /** ++ * True if the filesystem is compresses. ++ * False if it isn't or we don't know. ++ */ ++ bool compressed; ++ ++ /** ++ * True if the filesystem compresses of individual files. ++ * False if it doesn't or we don't know. ++ */ ++ bool file_compression; ++}; ++VMMDEV_ASSERT_SIZE(shfl_fsproperties, 12); ++ ++struct shfl_volinfo { ++ s64 total_allocation_bytes; ++ s64 available_allocation_bytes; ++ u32 bytes_per_allocation_unit; ++ u32 bytes_per_sector; ++ u32 serial; ++ struct shfl_fsproperties properties; ++}; ++ ++ ++/** SHFL_FN_MAP_FOLDER Parameters structure. */ ++struct shfl_map_folder { ++ /** ++ * pointer, in: ++ * Points to struct shfl_string buffer. ++ */ ++ struct vmmdev_hgcm_function_parameter path; ++ ++ /** ++ * pointer, out: SHFLROOT (u32) ++ * Root handle of the mapping which name is queried. ++ */ ++ struct vmmdev_hgcm_function_parameter root; ++ ++ /** ++ * pointer, in: UTF16 ++ * Path delimiter ++ */ ++ struct vmmdev_hgcm_function_parameter delimiter; ++ ++ /** ++ * pointer, in: SHFLROOT (u32) ++ * Case senstive flag ++ */ ++ struct vmmdev_hgcm_function_parameter case_sensitive; ++ ++}; ++ ++/* Number of parameters */ ++#define SHFL_CPARMS_MAP_FOLDER (4) ++ ++ ++/** SHFL_FN_UNMAP_FOLDER Parameters structure. */ ++struct shfl_unmap_folder { ++ /** ++ * pointer, in: SHFLROOT (u32) ++ * Root handle of the mapping which name is queried. ++ */ ++ struct vmmdev_hgcm_function_parameter root; ++ ++}; ++ ++/* Number of parameters */ ++#define SHFL_CPARMS_UNMAP_FOLDER (1) ++ ++ ++/** SHFL_FN_CREATE Parameters structure. */ ++struct shfl_create { ++ /** ++ * pointer, in: SHFLROOT (u32) ++ * Root handle of the mapping which name is queried. ++ */ ++ struct vmmdev_hgcm_function_parameter root; ++ ++ /** ++ * pointer, in: ++ * Points to struct shfl_string buffer. ++ */ ++ struct vmmdev_hgcm_function_parameter path; ++ ++ /** ++ * pointer, in/out: ++ * Points to struct shfl_createparms buffer. ++ */ ++ struct vmmdev_hgcm_function_parameter parms; ++ ++}; ++ ++/* Number of parameters */ ++#define SHFL_CPARMS_CREATE (3) ++ ++ ++/** SHFL_FN_CLOSE Parameters structure. */ ++struct shfl_close { ++ /** ++ * pointer, in: SHFLROOT (u32) ++ * Root handle of the mapping which name is queried. ++ */ ++ struct vmmdev_hgcm_function_parameter root; ++ ++ /** ++ * value64, in: ++ * SHFLHANDLE (u64) of object to close. ++ */ ++ struct vmmdev_hgcm_function_parameter handle; ++ ++}; ++ ++/* Number of parameters */ ++#define SHFL_CPARMS_CLOSE (2) ++ ++ ++/** SHFL_FN_READ Parameters structure. */ ++struct shfl_read { ++ /** ++ * pointer, in: SHFLROOT (u32) ++ * Root handle of the mapping which name is queried. ++ */ ++ struct vmmdev_hgcm_function_parameter root; ++ ++ /** ++ * value64, in: ++ * SHFLHANDLE (u64) of object to read from. ++ */ ++ struct vmmdev_hgcm_function_parameter handle; ++ ++ /** ++ * value64, in: ++ * Offset to read from. ++ */ ++ struct vmmdev_hgcm_function_parameter offset; ++ ++ /** ++ * value64, in/out: ++ * Bytes to read/How many were read. ++ */ ++ struct vmmdev_hgcm_function_parameter cb; ++ ++ /** ++ * pointer, out: ++ * Buffer to place data to. ++ */ ++ struct vmmdev_hgcm_function_parameter buffer; ++ ++}; ++ ++/* Number of parameters */ ++#define SHFL_CPARMS_READ (5) ++ ++ ++/** SHFL_FN_WRITE Parameters structure. */ ++struct shfl_write { ++ /** ++ * pointer, in: SHFLROOT (u32) ++ * Root handle of the mapping which name is queried. ++ */ ++ struct vmmdev_hgcm_function_parameter root; ++ ++ /** ++ * value64, in: ++ * SHFLHANDLE (u64) of object to write to. ++ */ ++ struct vmmdev_hgcm_function_parameter handle; ++ ++ /** ++ * value64, in: ++ * Offset to write to. ++ */ ++ struct vmmdev_hgcm_function_parameter offset; ++ ++ /** ++ * value64, in/out: ++ * Bytes to write/How many were written. ++ */ ++ struct vmmdev_hgcm_function_parameter cb; ++ ++ /** ++ * pointer, in: ++ * Data to write. ++ */ ++ struct vmmdev_hgcm_function_parameter buffer; ++ ++}; ++ ++/* Number of parameters */ ++#define SHFL_CPARMS_WRITE (5) ++ ++ ++/* ++ * SHFL_FN_LIST ++ * Listing information includes variable length RTDIRENTRY[EX] structures. ++ */ ++ ++#define SHFL_LIST_NONE 0 ++#define SHFL_LIST_RETURN_ONE 1 ++ ++/** SHFL_FN_LIST Parameters structure. */ ++struct shfl_list { ++ /** ++ * pointer, in: SHFLROOT (u32) ++ * Root handle of the mapping which name is queried. ++ */ ++ struct vmmdev_hgcm_function_parameter root; ++ ++ /** ++ * value64, in: ++ * SHFLHANDLE (u64) of object to be listed. ++ */ ++ struct vmmdev_hgcm_function_parameter handle; ++ ++ /** ++ * value32, in: ++ * List flags SHFL_LIST_*. ++ */ ++ struct vmmdev_hgcm_function_parameter flags; ++ ++ /** ++ * value32, in/out: ++ * Bytes to be used for listing information/How many bytes were used. ++ */ ++ struct vmmdev_hgcm_function_parameter cb; ++ ++ /** ++ * pointer, in/optional ++ * Points to struct shfl_string buffer that specifies a search path. ++ */ ++ struct vmmdev_hgcm_function_parameter path; ++ ++ /** ++ * pointer, out: ++ * Buffer to place listing information to. (struct shfl_dirinfo) ++ */ ++ struct vmmdev_hgcm_function_parameter buffer; ++ ++ /** ++ * value32, in/out: ++ * Indicates a key where the listing must be resumed. ++ * in: 0 means start from begin of object. ++ * out: 0 means listing completed. ++ */ ++ struct vmmdev_hgcm_function_parameter resume_point; ++ ++ /** ++ * pointer, out: ++ * Number of files returned ++ */ ++ struct vmmdev_hgcm_function_parameter file_count; ++}; ++ ++/* Number of parameters */ ++#define SHFL_CPARMS_LIST (8) ++ ++ ++/** SHFL_FN_READLINK Parameters structure. */ ++struct shfl_readLink { ++ /** ++ * pointer, in: SHFLROOT (u32) ++ * Root handle of the mapping which name is queried. ++ */ ++ struct vmmdev_hgcm_function_parameter root; ++ ++ /** ++ * pointer, in: ++ * Points to struct shfl_string buffer. ++ */ ++ struct vmmdev_hgcm_function_parameter path; ++ ++ /** ++ * pointer, out: ++ * Buffer to place data to. ++ */ ++ struct vmmdev_hgcm_function_parameter buffer; ++ ++}; ++ ++/* Number of parameters */ ++#define SHFL_CPARMS_READLINK (3) ++ ++ ++/* SHFL_FN_INFORMATION */ ++ ++/* Mask of Set/Get bit. */ ++#define SHFL_INFO_MODE_MASK (0x1) ++/* Get information */ ++#define SHFL_INFO_GET (0x0) ++/* Set information */ ++#define SHFL_INFO_SET (0x1) ++ ++/* Get name of the object. */ ++#define SHFL_INFO_NAME (0x2) ++/* Set size of object (extend/trucate); only applies to file objects */ ++#define SHFL_INFO_SIZE (0x4) ++/* Get/Set file object info. */ ++#define SHFL_INFO_FILE (0x8) ++/* Get volume information. */ ++#define SHFL_INFO_VOLUME (0x10) ++ ++/** SHFL_FN_INFORMATION Parameters structure. */ ++struct shfl_information { ++ /** ++ * pointer, in: SHFLROOT (u32) ++ * Root handle of the mapping which name is queried. ++ */ ++ struct vmmdev_hgcm_function_parameter root; ++ ++ /** ++ * value64, in: ++ * SHFLHANDLE (u64) of object to be listed. ++ */ ++ struct vmmdev_hgcm_function_parameter handle; ++ ++ /** ++ * value32, in: ++ * SHFL_INFO_* ++ */ ++ struct vmmdev_hgcm_function_parameter flags; ++ ++ /** ++ * value32, in/out: ++ * Bytes to be used for information/How many bytes were used. ++ */ ++ struct vmmdev_hgcm_function_parameter cb; ++ ++ /** ++ * pointer, in/out: ++ * Information to be set/get (shfl_fsobjinfo or shfl_string). Do not ++ * forget to set the shfl_fsobjinfo::attr::additional for a get ++ * operation as well. ++ */ ++ struct vmmdev_hgcm_function_parameter info; ++ ++}; ++ ++/* Number of parameters */ ++#define SHFL_CPARMS_INFORMATION (5) ++ ++ ++/* SHFL_FN_REMOVE */ ++ ++#define SHFL_REMOVE_FILE (0x1) ++#define SHFL_REMOVE_DIR (0x2) ++#define SHFL_REMOVE_SYMLINK (0x4) ++ ++/** SHFL_FN_REMOVE Parameters structure. */ ++struct shfl_remove { ++ /** ++ * pointer, in: SHFLROOT (u32) ++ * Root handle of the mapping which name is queried. ++ */ ++ struct vmmdev_hgcm_function_parameter root; ++ ++ /** ++ * pointer, in: ++ * Points to struct shfl_string buffer. ++ */ ++ struct vmmdev_hgcm_function_parameter path; ++ ++ /** ++ * value32, in: ++ * remove flags (file/directory) ++ */ ++ struct vmmdev_hgcm_function_parameter flags; ++ ++}; ++ ++#define SHFL_CPARMS_REMOVE (3) ++ ++ ++/* SHFL_FN_RENAME */ ++ ++#define SHFL_RENAME_FILE (0x1) ++#define SHFL_RENAME_DIR (0x2) ++#define SHFL_RENAME_REPLACE_IF_EXISTS (0x4) ++ ++/** SHFL_FN_RENAME Parameters structure. */ ++struct shfl_rename { ++ /** ++ * pointer, in: SHFLROOT (u32) ++ * Root handle of the mapping which name is queried. ++ */ ++ struct vmmdev_hgcm_function_parameter root; ++ ++ /** ++ * pointer, in: ++ * Points to struct shfl_string src. ++ */ ++ struct vmmdev_hgcm_function_parameter src; ++ ++ /** ++ * pointer, in: ++ * Points to struct shfl_string dest. ++ */ ++ struct vmmdev_hgcm_function_parameter dest; ++ ++ /** ++ * value32, in: ++ * rename flags (file/directory) ++ */ ++ struct vmmdev_hgcm_function_parameter flags; ++ ++}; ++ ++#define SHFL_CPARMS_RENAME (4) ++ ++ ++/** SHFL_FN_SYMLINK Parameters structure. */ ++struct shfl_symlink { ++ /** ++ * pointer, in: SHFLROOT (u32) ++ * Root handle of the mapping which name is queried. ++ */ ++ struct vmmdev_hgcm_function_parameter root; ++ ++ /** ++ * pointer, in: ++ * Points to struct shfl_string of path for the new symlink. ++ */ ++ struct vmmdev_hgcm_function_parameter new_path; ++ ++ /** ++ * pointer, in: ++ * Points to struct shfl_string of destination for symlink. ++ */ ++ struct vmmdev_hgcm_function_parameter old_path; ++ ++ /** ++ * pointer, out: ++ * Information about created symlink. ++ */ ++ struct vmmdev_hgcm_function_parameter info; ++ ++}; ++ ++#define SHFL_CPARMS_SYMLINK (4) ++ ++#endif +diff --git a/drivers/staging/vboxsf/super.c b/drivers/staging/vboxsf/super.c +new file mode 100644 +index 000000000000..3913ffafa83b +--- /dev/null ++++ b/drivers/staging/vboxsf/super.c +@@ -0,0 +1,499 @@ ++// SPDX-License-Identifier: MIT ++/* ++ * VirtualBox Guest Shared Folders support: Virtual File System. ++ * ++ * Module initialization/finalization ++ * File system registration/deregistration ++ * Superblock reading ++ * Few utility functions ++ * ++ * Copyright (C) 2006-2018 Oracle Corporation ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "vfsmod.h" ++ ++#define VBOXSF_SUPER_MAGIC 0x786f4256 /* 'VBox' little endian */ ++ ++#define VBSF_MOUNT_SIGNATURE_BYTE_0 ('\000') ++#define VBSF_MOUNT_SIGNATURE_BYTE_1 ('\377') ++#define VBSF_MOUNT_SIGNATURE_BYTE_2 ('\376') ++#define VBSF_MOUNT_SIGNATURE_BYTE_3 ('\375') ++ ++static int follow_symlinks; ++module_param(follow_symlinks, int, 0444); ++MODULE_PARM_DESC(follow_symlinks, ++ "Let host resolve symlinks rather than showing them"); ++ ++static DEFINE_IDA(vboxsf_bdi_ida); ++static DEFINE_MUTEX(vboxsf_setup_mutex); ++static bool vboxsf_setup_done; ++static struct super_operations vboxsf_super_ops; /* forward declaration */ ++static struct kmem_cache *vboxsf_inode_cachep; ++ ++static char * const vboxsf_default_nls = CONFIG_NLS_DEFAULT; ++ ++enum { opt_nls, opt_uid, opt_gid, opt_ttl, opt_dmode, opt_fmode, ++ opt_dmask, opt_fmask }; ++ ++static const struct fs_parameter_spec vboxsf_param_specs[] = { ++ fsparam_string ("nls", opt_nls), ++ fsparam_u32 ("uid", opt_uid), ++ fsparam_u32 ("gid", opt_gid), ++ fsparam_u32 ("ttl", opt_ttl), ++ fsparam_u32oct ("dmode", opt_dmode), ++ fsparam_u32oct ("fmode", opt_fmode), ++ fsparam_u32oct ("dmask", opt_dmask), ++ fsparam_u32oct ("fmask", opt_fmask), ++ {} ++}; ++ ++static const struct fs_parameter_description vboxsf_fs_parameters = { ++ .name = "vboxsf", ++ .specs = vboxsf_param_specs, ++}; ++ ++static int vboxsf_parse_param(struct fs_context *fc, struct fs_parameter *param) ++{ ++ struct vboxsf_fs_context *ctx = fc->fs_private; ++ struct fs_parse_result result; ++ kuid_t uid; ++ kgid_t gid; ++ int opt; ++ ++ opt = fs_parse(fc, &vboxsf_fs_parameters, param, &result); ++ if (opt < 0) ++ return opt; ++ ++ switch (opt) { ++ case opt_nls: ++ if (fc->purpose != FS_CONTEXT_FOR_MOUNT) { ++ vbg_err("vboxsf: Cannot reconfigure nls option\n"); ++ return -EINVAL; ++ } ++ ctx->nls_name = param->string; ++ param->string = NULL; ++ break; ++ case opt_uid: ++ uid = make_kuid(current_user_ns(), result.uint_32); ++ if (!uid_valid(uid)) ++ return -EINVAL; ++ ctx->o.uid = uid; ++ break; ++ case opt_gid: ++ gid = make_kgid(current_user_ns(), result.uint_32); ++ if (!gid_valid(gid)) ++ return -EINVAL; ++ ctx->o.gid = gid; ++ break; ++ case opt_ttl: ++ ctx->o.ttl = msecs_to_jiffies(result.uint_32); ++ break; ++ case opt_dmode: ++ if (result.uint_32 & ~0777) ++ return -EINVAL; ++ ctx->o.dmode = result.uint_32; ++ ctx->o.dmode_set = true; ++ break; ++ case opt_fmode: ++ if (result.uint_32 & ~0777) ++ return -EINVAL; ++ ctx->o.fmode = result.uint_32; ++ ctx->o.fmode_set = true; ++ break; ++ case opt_dmask: ++ if (result.uint_32 & ~07777) ++ return -EINVAL; ++ ctx->o.dmask = result.uint_32; ++ break; ++ case opt_fmask: ++ if (result.uint_32 & ~07777) ++ return -EINVAL; ++ ctx->o.fmask = result.uint_32; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int vboxsf_fill_super(struct super_block *sb, struct fs_context *fc) ++{ ++ struct vboxsf_fs_context *ctx = fc->fs_private; ++ struct shfl_string *folder_name, root_path; ++ struct vboxsf_sbi *sbi; ++ struct dentry *droot; ++ struct inode *iroot; ++ char *nls_name; ++ size_t size; ++ int err; ++ ++ if (!fc->source) ++ return -EINVAL; ++ ++ sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); ++ if (!sbi) ++ return -ENOMEM; ++ ++ sbi->o = ctx->o; ++ idr_init(&sbi->ino_idr); ++ spin_lock_init(&sbi->ino_idr_lock); ++ sbi->next_generation = 1; ++ sbi->bdi_id = -1; ++ ++ /* Load nls if not utf8 */ ++ nls_name = ctx->nls_name ? ctx->nls_name : vboxsf_default_nls; ++ if (strcmp(nls_name, "utf8") != 0) { ++ if (nls_name == vboxsf_default_nls) ++ sbi->nls = load_nls_default(); ++ else ++ sbi->nls = load_nls(nls_name); ++ ++ if (!sbi->nls) { ++ vbg_err("vboxsf: Count not load '%s' nls\n", nls_name); ++ err = -EINVAL; ++ goto fail_free; ++ } ++ } ++ ++ sbi->bdi_id = ida_simple_get(&vboxsf_bdi_ida, 0, 0, GFP_KERNEL); ++ if (sbi->bdi_id < 0) { ++ err = sbi->bdi_id; ++ goto fail_free; ++ } ++ ++ err = super_setup_bdi_name(sb, "vboxsf-%s.%d", fc->source, sbi->bdi_id); ++ if (err) ++ goto fail_free; ++ ++ /* Turn source into a shfl_string and map the folder */ ++ size = strlen(fc->source) + 1; ++ folder_name = kmalloc(SHFLSTRING_HEADER_SIZE + size, GFP_KERNEL); ++ if (!folder_name) ++ goto fail_free; ++ folder_name->size = size; ++ folder_name->length = size - 1; ++ strlcpy(folder_name->string.utf8, fc->source, size); ++ err = vboxsf_map_folder(folder_name, &sbi->root); ++ kfree(folder_name); ++ if (err) { ++ vbg_err("vboxsf: Host rejected mount of '%s' with error %d\n", ++ fc->source, err); ++ goto fail_free; ++ } ++ ++ root_path.length = 1; ++ root_path.size = 2; ++ root_path.string.utf8[0] = '/'; ++ root_path.string.utf8[1] = 0; ++ err = vboxsf_stat(sbi, &root_path, &sbi->root_info); ++ if (err) ++ goto fail_unmap; ++ ++ sb->s_magic = VBOXSF_SUPER_MAGIC; ++ sb->s_blocksize = 1024; ++ sb->s_maxbytes = MAX_LFS_FILESIZE; ++ sb->s_op = &vboxsf_super_ops; ++ sb->s_d_op = &vboxsf_dentry_ops; ++ ++ iroot = iget_locked(sb, 0); ++ if (!iroot) { ++ err = -ENOMEM; ++ goto fail_unmap; ++ } ++ vboxsf_init_inode(sbi, iroot, &sbi->root_info); ++ unlock_new_inode(iroot); ++ ++ droot = d_make_root(iroot); ++ if (!droot) { ++ err = -ENOMEM; ++ goto fail_unmap; ++ } ++ ++ sb->s_root = droot; ++ sb->s_fs_info = sbi; ++ return 0; ++ ++fail_unmap: ++ vboxsf_unmap_folder(sbi->root); ++fail_free: ++ if (sbi->bdi_id >= 0) ++ ida_simple_remove(&vboxsf_bdi_ida, sbi->bdi_id); ++ if (sbi->nls) ++ unload_nls(sbi->nls); ++ idr_destroy(&sbi->ino_idr); ++ kfree(sbi); ++ return err; ++} ++ ++static void vboxsf_inode_init_once(void *data) ++{ ++ struct vboxsf_inode *sf_i = data; ++ ++ mutex_init(&sf_i->handle_list_mutex); ++ inode_init_once(&sf_i->vfs_inode); ++} ++ ++static struct inode *vboxsf_alloc_inode(struct super_block *sb) ++{ ++ struct vboxsf_inode *sf_i; ++ ++ sf_i = kmem_cache_alloc(vboxsf_inode_cachep, GFP_NOFS); ++ if (!sf_i) ++ return NULL; ++ ++ sf_i->force_restat = 0; ++ INIT_LIST_HEAD(&sf_i->handle_list); ++ ++ return &sf_i->vfs_inode; ++} ++ ++static void vboxsf_free_inode(struct inode *inode) ++{ ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(inode->i_sb); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&sbi->ino_idr_lock, flags); ++ idr_remove(&sbi->ino_idr, inode->i_ino); ++ spin_unlock_irqrestore(&sbi->ino_idr_lock, flags); ++ kmem_cache_free(vboxsf_inode_cachep, VBOXSF_I(inode)); ++} ++ ++static void vboxsf_put_super(struct super_block *sb) ++{ ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(sb); ++ ++ vboxsf_unmap_folder(sbi->root); ++ if (sbi->bdi_id >= 0) ++ ida_simple_remove(&vboxsf_bdi_ida, sbi->bdi_id); ++ if (sbi->nls) ++ unload_nls(sbi->nls); ++ ++ /* ++ * vboxsf_free_inode uses the idr, make sure all delayed rcu free ++ * inodes are flushed. ++ */ ++ rcu_barrier(); ++ idr_destroy(&sbi->ino_idr); ++ kfree(sbi); ++} ++ ++static int vboxsf_statfs(struct dentry *dentry, struct kstatfs *stat) ++{ ++ struct super_block *sb = dentry->d_sb; ++ struct shfl_volinfo shfl_volinfo; ++ struct vboxsf_sbi *sbi; ++ u32 buf_len; ++ int err; ++ ++ sbi = VBOXSF_SBI(sb); ++ buf_len = sizeof(shfl_volinfo); ++ err = vboxsf_fsinfo(sbi->root, 0, SHFL_INFO_GET | SHFL_INFO_VOLUME, ++ &buf_len, &shfl_volinfo); ++ if (err) ++ return err; ++ ++ stat->f_type = VBOXSF_SUPER_MAGIC; ++ stat->f_bsize = shfl_volinfo.bytes_per_allocation_unit; ++ ++ do_div(shfl_volinfo.total_allocation_bytes, ++ shfl_volinfo.bytes_per_allocation_unit); ++ stat->f_blocks = shfl_volinfo.total_allocation_bytes; ++ ++ do_div(shfl_volinfo.available_allocation_bytes, ++ shfl_volinfo.bytes_per_allocation_unit); ++ stat->f_bfree = shfl_volinfo.available_allocation_bytes; ++ stat->f_bavail = shfl_volinfo.available_allocation_bytes; ++ ++ stat->f_files = 1000; ++ /* ++ * Don't return 0 here since the guest may then think that it is not ++ * possible to create any more files. ++ */ ++ stat->f_ffree = 1000000; ++ stat->f_fsid.val[0] = 0; ++ stat->f_fsid.val[1] = 0; ++ stat->f_namelen = 255; ++ return 0; ++} ++ ++static struct super_operations vboxsf_super_ops = { ++ .alloc_inode = vboxsf_alloc_inode, ++ .free_inode = vboxsf_free_inode, ++ .put_super = vboxsf_put_super, ++ .statfs = vboxsf_statfs, ++}; ++ ++static int vboxsf_setup(void) ++{ ++ int err; ++ ++ mutex_lock(&vboxsf_setup_mutex); ++ ++ if (vboxsf_setup_done) ++ goto success; ++ ++ vboxsf_inode_cachep = ++ kmem_cache_create("vboxsf_inode_cache", ++ sizeof(struct vboxsf_inode), 0, ++ (SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD | ++ SLAB_ACCOUNT), ++ vboxsf_inode_init_once); ++ if (!vboxsf_inode_cachep) { ++ err = -ENOMEM; ++ goto fail_nomem; ++ } ++ ++ err = vboxsf_connect(); ++ if (err) { ++ vbg_err("vboxsf: err %d connecting to guest PCI-device\n", err); ++ vbg_err("vboxsf: make sure you are inside a VirtualBox VM\n"); ++ vbg_err("vboxsf: and check dmesg for vboxguest errors\n"); ++ goto fail_free_cache; ++ } ++ ++ err = vboxsf_set_utf8(); ++ if (err) { ++ vbg_err("vboxsf_setutf8 error %d\n", err); ++ goto fail_disconnect; ++ } ++ ++ if (!follow_symlinks) { ++ err = vboxsf_set_symlinks(); ++ if (err) ++ vbg_warn("vboxsf: Unable to show symlinks: %d\n", err); ++ } ++ ++ vboxsf_setup_done = true; ++success: ++ mutex_unlock(&vboxsf_setup_mutex); ++ return 0; ++ ++fail_disconnect: ++ vboxsf_disconnect(); ++fail_free_cache: ++ kmem_cache_destroy(vboxsf_inode_cachep); ++fail_nomem: ++ mutex_unlock(&vboxsf_setup_mutex); ++ return err; ++} ++ ++static int vboxsf_parse_monolithic(struct fs_context *fc, void *data) ++{ ++ char *options = data; ++ ++ if (options && options[0] == VBSF_MOUNT_SIGNATURE_BYTE_0 && ++ options[1] == VBSF_MOUNT_SIGNATURE_BYTE_1 && ++ options[2] == VBSF_MOUNT_SIGNATURE_BYTE_2 && ++ options[3] == VBSF_MOUNT_SIGNATURE_BYTE_3) { ++ vbg_err("vboxsf: Old binary mount data not supported, remove obsolete mount.vboxsf and/or update your VBoxService.\n"); ++ return -EINVAL; ++ } ++ ++ return generic_parse_monolithic(fc, data); ++} ++ ++static int vboxsf_get_tree(struct fs_context *fc) ++{ ++ int err; ++ ++ err = vboxsf_setup(); ++ if (err) ++ return err; ++ ++ return vfs_get_super(fc, vfs_get_independent_super, vboxsf_fill_super); ++} ++ ++static int vboxsf_reconfigure(struct fs_context *fc) ++{ ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(fc->root->d_sb); ++ struct vboxsf_fs_context *ctx = fc->fs_private; ++ struct inode *iroot; ++ ++ iroot = ilookup(fc->root->d_sb, 0); ++ if (!iroot) ++ return -ENOENT; ++ ++ /* Apply changed options to the root inode */ ++ sbi->o = ctx->o; ++ vboxsf_init_inode(sbi, iroot, &sbi->root_info); ++ ++ return 0; ++} ++ ++static void vboxsf_free_fc(struct fs_context *fc) ++{ ++ struct vboxsf_fs_context *ctx = fc->fs_private; ++ ++ kfree(ctx->nls_name); ++ kfree(ctx); ++} ++ ++static const struct fs_context_operations vboxsf_context_ops = { ++ .free = vboxsf_free_fc, ++ .parse_param = vboxsf_parse_param, ++ .parse_monolithic = vboxsf_parse_monolithic, ++ .get_tree = vboxsf_get_tree, ++ .reconfigure = vboxsf_reconfigure, ++}; ++ ++static int vboxsf_init_fs_context(struct fs_context *fc) ++{ ++ struct vboxsf_fs_context *ctx; ++ ++ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); ++ if (!ctx) ++ return -ENOMEM; ++ ++ current_uid_gid(&ctx->o.uid, &ctx->o.gid); ++ ++ fc->fs_private = ctx; ++ fc->ops = &vboxsf_context_ops; ++ return 0; ++} ++ ++static struct file_system_type vboxsf_fs_type = { ++ .owner = THIS_MODULE, ++ .name = "vboxsf", ++ .init_fs_context = vboxsf_init_fs_context, ++ .parameters = &vboxsf_fs_parameters, ++ .kill_sb = kill_anon_super ++}; ++ ++/* Module initialization/finalization handlers */ ++static int __init vboxsf_init(void) ++{ ++ return register_filesystem(&vboxsf_fs_type); ++} ++ ++static void __exit vboxsf_fini(void) ++{ ++ unregister_filesystem(&vboxsf_fs_type); ++ ++ mutex_lock(&vboxsf_setup_mutex); ++ if (vboxsf_setup_done) { ++ vboxsf_disconnect(); ++ /* ++ * Make sure all delayed rcu free inodes are flushed ++ * before we destroy the cache. ++ */ ++ rcu_barrier(); ++ kmem_cache_destroy(vboxsf_inode_cachep); ++ } ++ mutex_unlock(&vboxsf_setup_mutex); ++} ++ ++module_init(vboxsf_init); ++module_exit(vboxsf_fini); ++ ++MODULE_DESCRIPTION("Oracle VM VirtualBox Module for Host File System Access"); ++MODULE_AUTHOR("Oracle Corporation"); ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS_FS("vboxsf"); +diff --git a/drivers/staging/vboxsf/utils.c b/drivers/staging/vboxsf/utils.c +new file mode 100644 +index 000000000000..1870b69c824e +--- /dev/null ++++ b/drivers/staging/vboxsf/utils.c +@@ -0,0 +1,550 @@ ++// SPDX-License-Identifier: MIT ++/* ++ * VirtualBox Guest Shared Folders support: Utility functions. ++ * Mainly conversion from/to VirtualBox/Linux data structures. ++ * ++ * Copyright (C) 2006-2018 Oracle Corporation ++ */ ++ ++#include ++#include ++#include ++#include ++#include "vfsmod.h" ++ ++struct inode *vboxsf_new_inode(struct super_block *sb) ++{ ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(sb); ++ struct inode *inode; ++ unsigned long flags; ++ int cursor, ret; ++ u32 gen; ++ ++ inode = new_inode(sb); ++ if (!inode) ++ return ERR_PTR(-ENOMEM); ++ ++ idr_preload(GFP_KERNEL); ++ spin_lock_irqsave(&sbi->ino_idr_lock, flags); ++ cursor = idr_get_cursor(&sbi->ino_idr); ++ ret = idr_alloc_cyclic(&sbi->ino_idr, inode, 1, 0, GFP_ATOMIC); ++ if (ret >= 0 && ret < cursor) ++ sbi->next_generation++; ++ gen = sbi->next_generation; ++ spin_unlock_irqrestore(&sbi->ino_idr_lock, flags); ++ idr_preload_end(); ++ ++ if (ret < 0) { ++ iput(inode); ++ return ERR_PTR(ret); ++ } ++ ++ inode->i_ino = ret; ++ inode->i_generation = gen; ++ return inode; ++} ++ ++/* set [inode] attributes based on [info], uid/gid based on [sbi] */ ++void vboxsf_init_inode(struct vboxsf_sbi *sbi, struct inode *inode, ++ const struct shfl_fsobjinfo *info) ++{ ++ const struct shfl_fsobjattr *attr; ++ s64 allocated; ++ int mode; ++ ++ attr = &info->attr; ++ ++#define mode_set(r) ((attr->mode & (SHFL_UNIX_##r)) ? (S_##r) : 0) ++ ++ mode = mode_set(IRUSR); ++ mode |= mode_set(IWUSR); ++ mode |= mode_set(IXUSR); ++ ++ mode |= mode_set(IRGRP); ++ mode |= mode_set(IWGRP); ++ mode |= mode_set(IXGRP); ++ ++ mode |= mode_set(IROTH); ++ mode |= mode_set(IWOTH); ++ mode |= mode_set(IXOTH); ++ ++#undef mode_set ++ ++ /* We use the host-side values for these */ ++ inode->i_flags |= S_NOATIME | S_NOCMTIME; ++ inode->i_mapping->a_ops = &vboxsf_reg_aops; ++ ++ if (SHFL_IS_DIRECTORY(attr->mode)) { ++ inode->i_mode = sbi->o.dmode_set ? sbi->o.dmode : mode; ++ inode->i_mode &= ~sbi->o.dmask; ++ inode->i_mode |= S_IFDIR; ++ inode->i_op = &vboxsf_dir_iops; ++ inode->i_fop = &vboxsf_dir_fops; ++ /* ++ * XXX: this probably should be set to the number of entries ++ * in the directory plus two (. ..) ++ */ ++ set_nlink(inode, 1); ++ } else if (SHFL_IS_SYMLINK(attr->mode)) { ++ inode->i_mode = sbi->o.fmode_set ? sbi->o.fmode : mode; ++ inode->i_mode &= ~sbi->o.fmask; ++ inode->i_mode |= S_IFLNK; ++ inode->i_op = &vboxsf_lnk_iops; ++ set_nlink(inode, 1); ++ } else { ++ inode->i_mode = sbi->o.fmode_set ? sbi->o.fmode : mode; ++ inode->i_mode &= ~sbi->o.fmask; ++ inode->i_mode |= S_IFREG; ++ inode->i_op = &vboxsf_reg_iops; ++ inode->i_fop = &vboxsf_reg_fops; ++ set_nlink(inode, 1); ++ } ++ ++ inode->i_uid = sbi->o.uid; ++ inode->i_gid = sbi->o.gid; ++ ++ inode->i_size = info->size; ++ inode->i_blkbits = 12; ++ /* i_blocks always in units of 512 bytes! */ ++ allocated = info->allocated + 511; ++ do_div(allocated, 512); ++ inode->i_blocks = allocated; ++ ++ inode->i_atime = ns_to_timespec64( ++ info->access_time.ns_relative_to_unix_epoch); ++ inode->i_ctime = ns_to_timespec64( ++ info->change_time.ns_relative_to_unix_epoch); ++ inode->i_mtime = ns_to_timespec64( ++ info->modification_time.ns_relative_to_unix_epoch); ++} ++ ++int vboxsf_create_at_dentry(struct dentry *dentry, ++ struct shfl_createparms *params) ++{ ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(dentry->d_sb); ++ struct shfl_string *path; ++ int err; ++ ++ path = vboxsf_path_from_dentry(sbi, dentry); ++ if (IS_ERR(path)) ++ return PTR_ERR(path); ++ ++ err = vboxsf_create(sbi->root, path, params); ++ __putname(path); ++ ++ return err; ++} ++ ++int vboxsf_stat(struct vboxsf_sbi *sbi, struct shfl_string *path, ++ struct shfl_fsobjinfo *info) ++{ ++ struct shfl_createparms params = {}; ++ int err; ++ ++ params.handle = SHFL_HANDLE_NIL; ++ params.create_flags = SHFL_CF_LOOKUP | SHFL_CF_ACT_FAIL_IF_NEW; ++ ++ err = vboxsf_create(sbi->root, path, ¶ms); ++ if (err) ++ return err; ++ ++ if (params.result != SHFL_FILE_EXISTS) ++ return -ENOENT; ++ ++ if (info) ++ *info = params.info; ++ ++ return 0; ++} ++ ++int vboxsf_stat_dentry(struct dentry *dentry, struct shfl_fsobjinfo *info) ++{ ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(dentry->d_sb); ++ struct shfl_string *path; ++ int err; ++ ++ path = vboxsf_path_from_dentry(sbi, dentry); ++ if (IS_ERR(path)) ++ return PTR_ERR(path); ++ ++ err = vboxsf_stat(sbi, path, info); ++ __putname(path); ++ return err; ++} ++ ++int vboxsf_inode_revalidate(struct dentry *dentry) ++{ ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(dentry->d_sb); ++ struct vboxsf_inode *sf_i; ++ struct shfl_fsobjinfo info; ++ struct timespec64 prev_mtime; ++ struct inode *inode; ++ int err; ++ ++ if (!dentry || !d_really_is_positive(dentry)) ++ return -EINVAL; ++ ++ inode = d_inode(dentry); ++ prev_mtime = inode->i_mtime; ++ sf_i = VBOXSF_I(inode); ++ if (!sf_i->force_restat) { ++ if (time_before(jiffies, dentry->d_time + sbi->o.ttl)) ++ return 0; ++ } ++ ++ err = vboxsf_stat_dentry(dentry, &info); ++ if (err) ++ return err; ++ ++ dentry->d_time = jiffies; ++ sf_i->force_restat = 0; ++ vboxsf_init_inode(sbi, inode, &info); ++ ++ /* ++ * If the file was changed on the host side we need to invalidate the ++ * page-cache for it. Note this also gets triggered by our own writes, ++ * this is unavoidable. ++ */ ++ if (timespec64_compare(&inode->i_mtime, &prev_mtime) > 0) ++ invalidate_inode_pages2(inode->i_mapping); ++ ++ return 0; ++} ++ ++int vboxsf_getattr(const struct path *path, struct kstat *kstat, ++ u32 request_mask, unsigned int flags) ++{ ++ int err; ++ struct dentry *dentry = path->dentry; ++ struct inode *inode = d_inode(dentry); ++ struct vboxsf_inode *sf_i = VBOXSF_I(inode); ++ ++ switch (flags & AT_STATX_SYNC_TYPE) { ++ case AT_STATX_DONT_SYNC: ++ err = 0; ++ break; ++ case AT_STATX_FORCE_SYNC: ++ sf_i->force_restat = 1; ++ /* fall-through */ ++ default: ++ err = vboxsf_inode_revalidate(dentry); ++ } ++ if (err) ++ return err; ++ ++ generic_fillattr(d_inode(dentry), kstat); ++ return 0; ++} ++ ++int vboxsf_setattr(struct dentry *dentry, struct iattr *iattr) ++{ ++ struct vboxsf_inode *sf_i = VBOXSF_I(d_inode(dentry)); ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(dentry->d_sb); ++ struct shfl_createparms params = {}; ++ struct shfl_fsobjinfo info = {}; ++ u32 buf_len; ++ int err; ++ ++ params.handle = SHFL_HANDLE_NIL; ++ params.create_flags = SHFL_CF_ACT_OPEN_IF_EXISTS | ++ SHFL_CF_ACT_FAIL_IF_NEW | ++ SHFL_CF_ACCESS_ATTR_WRITE; ++ ++ /* this is at least required for Posix hosts */ ++ if (iattr->ia_valid & ATTR_SIZE) ++ params.create_flags |= SHFL_CF_ACCESS_WRITE; ++ ++ err = vboxsf_create_at_dentry(dentry, ¶ms); ++ if (err || params.result != SHFL_FILE_EXISTS) ++ return err ? err : -ENOENT; ++ ++#define mode_set(r) ((iattr->ia_mode & (S_##r)) ? SHFL_UNIX_##r : 0) ++ ++ /* ++ * Setting the file size and setting the other attributes has to ++ * be handled separately. ++ */ ++ if (iattr->ia_valid & (ATTR_MODE | ATTR_ATIME | ATTR_MTIME)) { ++ if (iattr->ia_valid & ATTR_MODE) { ++ info.attr.mode = mode_set(IRUSR); ++ info.attr.mode |= mode_set(IWUSR); ++ info.attr.mode |= mode_set(IXUSR); ++ info.attr.mode |= mode_set(IRGRP); ++ info.attr.mode |= mode_set(IWGRP); ++ info.attr.mode |= mode_set(IXGRP); ++ info.attr.mode |= mode_set(IROTH); ++ info.attr.mode |= mode_set(IWOTH); ++ info.attr.mode |= mode_set(IXOTH); ++ ++ if (iattr->ia_mode & S_IFDIR) ++ info.attr.mode |= SHFL_TYPE_DIRECTORY; ++ else ++ info.attr.mode |= SHFL_TYPE_FILE; ++ } ++ ++ if (iattr->ia_valid & ATTR_ATIME) ++ info.access_time.ns_relative_to_unix_epoch = ++ timespec64_to_ns(&iattr->ia_atime); ++ ++ if (iattr->ia_valid & ATTR_MTIME) ++ info.modification_time.ns_relative_to_unix_epoch = ++ timespec64_to_ns(&iattr->ia_mtime); ++ ++ /* ++ * Ignore ctime (inode change time) as it can't be set ++ * from userland anyway. ++ */ ++ ++ buf_len = sizeof(info); ++ err = vboxsf_fsinfo(sbi->root, params.handle, ++ SHFL_INFO_SET | SHFL_INFO_FILE, &buf_len, ++ &info); ++ if (err) { ++ vboxsf_close(sbi->root, params.handle); ++ return err; ++ } ++ ++ /* the host may have given us different attr then requested */ ++ sf_i->force_restat = 1; ++ } ++ ++#undef mode_set ++ ++ if (iattr->ia_valid & ATTR_SIZE) { ++ memset(&info, 0, sizeof(info)); ++ info.size = iattr->ia_size; ++ buf_len = sizeof(info); ++ err = vboxsf_fsinfo(sbi->root, params.handle, ++ SHFL_INFO_SET | SHFL_INFO_SIZE, &buf_len, ++ &info); ++ if (err) { ++ vboxsf_close(sbi->root, params.handle); ++ return err; ++ } ++ ++ /* the host may have given us different attr then requested */ ++ sf_i->force_restat = 1; ++ } ++ ++ vboxsf_close(sbi->root, params.handle); ++ ++ /* Update the inode with what the host has actually given us. */ ++ if (sf_i->force_restat) ++ vboxsf_inode_revalidate(dentry); ++ ++ return 0; ++} ++ ++/* ++ * [dentry] contains string encoded in coding system that corresponds ++ * to [sbi]->nls, we must convert it to UTF8 here. ++ * Returns a shfl_string allocated through __getname (must be freed using ++ * __putname), or an ERR_PTR on error. ++ */ ++struct shfl_string *vboxsf_path_from_dentry(struct vboxsf_sbi *sbi, ++ struct dentry *dentry) ++{ ++ struct shfl_string *shfl_path; ++ int path_len, out_len, nb; ++ char *buf, *path; ++ wchar_t uni; ++ u8 *out; ++ ++ buf = __getname(); ++ if (!buf) ++ return ERR_PTR(-ENOMEM); ++ ++ path = dentry_path_raw(dentry, buf, PATH_MAX); ++ if (IS_ERR(path)) { ++ __putname(buf); ++ return (struct shfl_string *)path; ++ } ++ path_len = strlen(path); ++ ++ if (sbi->nls) { ++ shfl_path = __getname(); ++ if (!shfl_path) { ++ __putname(buf); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ out = shfl_path->string.utf8; ++ out_len = PATH_MAX - SHFLSTRING_HEADER_SIZE - 1; ++ ++ while (path_len) { ++ nb = sbi->nls->char2uni(path, path_len, &uni); ++ if (nb < 0) { ++ __putname(shfl_path); ++ __putname(buf); ++ return ERR_PTR(-EINVAL); ++ } ++ path += nb; ++ path_len -= nb; ++ ++ nb = utf32_to_utf8(uni, out, out_len); ++ if (nb < 0) { ++ __putname(shfl_path); ++ __putname(buf); ++ return ERR_PTR(-ENAMETOOLONG); ++ } ++ out += nb; ++ out_len -= nb; ++ } ++ *out = 0; ++ shfl_path->length = out - shfl_path->string.utf8; ++ shfl_path->size = shfl_path->length + 1; ++ __putname(buf); ++ } else { ++ if ((SHFLSTRING_HEADER_SIZE + path_len + 1) > PATH_MAX) { ++ __putname(buf); ++ return ERR_PTR(-ENAMETOOLONG); ++ } ++ /* ++ * dentry_path stores the name at the end of buf, but the ++ * shfl_string string we return must be properly aligned. ++ */ ++ shfl_path = (struct shfl_string *)buf; ++ memmove(shfl_path->string.utf8, path, path_len); ++ shfl_path->string.utf8[path_len] = 0; ++ shfl_path->length = path_len; ++ shfl_path->size = path_len + 1; ++ } ++ ++ return shfl_path; ++} ++ ++int vboxsf_nlscpy(struct vboxsf_sbi *sbi, char *name, size_t name_bound_len, ++ const unsigned char *utf8_name, size_t utf8_len) ++{ ++ const char *in; ++ char *out; ++ size_t out_len; ++ size_t out_bound_len; ++ size_t in_bound_len; ++ ++ in = utf8_name; ++ in_bound_len = utf8_len; ++ ++ out = name; ++ out_len = 0; ++ /* Reserve space for terminating 0 */ ++ out_bound_len = name_bound_len - 1; ++ ++ while (in_bound_len) { ++ int nb; ++ unicode_t uni; ++ ++ nb = utf8_to_utf32(in, in_bound_len, &uni); ++ if (nb < 0) ++ return -EINVAL; ++ ++ in += nb; ++ in_bound_len -= nb; ++ ++ nb = sbi->nls->uni2char(uni, out, out_bound_len); ++ if (nb < 0) ++ return nb; ++ ++ out += nb; ++ out_bound_len -= nb; ++ out_len += nb; ++ } ++ ++ *out = 0; ++ ++ return 0; ++} ++ ++static struct vboxsf_dir_buf *vboxsf_dir_buf_alloc(struct list_head *list) ++{ ++ struct vboxsf_dir_buf *b; ++ ++ b = kmalloc(sizeof(*b), GFP_KERNEL); ++ if (!b) ++ return NULL; ++ ++ b->buf = kmalloc(DIR_BUFFER_SIZE, GFP_KERNEL); ++ if (!b->buf) { ++ kfree(b); ++ return NULL; ++ } ++ ++ b->entries = 0; ++ b->used = 0; ++ b->free = DIR_BUFFER_SIZE; ++ list_add(&b->head, list); ++ ++ return b; ++} ++ ++static void vboxsf_dir_buf_free(struct vboxsf_dir_buf *b) ++{ ++ list_del(&b->head); ++ kfree(b->buf); ++ kfree(b); ++} ++ ++struct vboxsf_dir_info *vboxsf_dir_info_alloc(void) ++{ ++ struct vboxsf_dir_info *p; ++ ++ p = kmalloc(sizeof(*p), GFP_KERNEL); ++ if (!p) ++ return NULL; ++ ++ INIT_LIST_HEAD(&p->info_list); ++ return p; ++} ++ ++void vboxsf_dir_info_free(struct vboxsf_dir_info *p) ++{ ++ struct list_head *list, *pos, *tmp; ++ ++ list = &p->info_list; ++ list_for_each_safe(pos, tmp, list) { ++ struct vboxsf_dir_buf *b; ++ ++ b = list_entry(pos, struct vboxsf_dir_buf, head); ++ vboxsf_dir_buf_free(b); ++ } ++ kfree(p); ++} ++ ++int vboxsf_dir_read_all(struct vboxsf_sbi *sbi, struct vboxsf_dir_info *sf_d, ++ u64 handle) ++{ ++ struct vboxsf_dir_buf *b; ++ u32 entries, size; ++ int err = 0; ++ void *buf; ++ ++ /* vboxsf_dirinfo returns 1 on end of dir */ ++ while (err == 0) { ++ b = vboxsf_dir_buf_alloc(&sf_d->info_list); ++ if (!b) { ++ err = -ENOMEM; ++ break; ++ } ++ ++ buf = b->buf; ++ size = b->free; ++ ++ err = vboxsf_dirinfo(sbi->root, handle, NULL, 0, 0, ++ &size, buf, &entries); ++ if (err < 0) ++ break; ++ ++ b->entries += entries; ++ b->free -= size; ++ b->used += size; ++ } ++ ++ if (b && b->used == 0) ++ vboxsf_dir_buf_free(b); ++ ++ /* -EILSEQ means the host could not translate a filename, ignore */ ++ if (err > 0 || err == -EILSEQ) ++ err = 0; ++ ++ return err; ++} +diff --git a/drivers/staging/vboxsf/vboxsf_wrappers.c b/drivers/staging/vboxsf/vboxsf_wrappers.c +new file mode 100644 +index 000000000000..bfc78a097dae +--- /dev/null ++++ b/drivers/staging/vboxsf/vboxsf_wrappers.c +@@ -0,0 +1,371 @@ ++// SPDX-License-Identifier: MIT ++/* ++ * Wrapper functions for the shfl host calls. ++ * ++ * Copyright (C) 2006-2018 Oracle Corporation ++ */ ++ ++#include ++#include ++#include ++#include ++#include "vfsmod.h" ++ ++#define SHFL_REQUEST \ ++ (VMMDEV_REQUESTOR_KERNEL | VMMDEV_REQUESTOR_USR_DRV_OTHER | \ ++ VMMDEV_REQUESTOR_CON_DONT_KNOW | VMMDEV_REQUESTOR_TRUST_NOT_GIVEN) ++ ++static u32 vboxsf_client_id; ++ ++int vboxsf_connect(void) ++{ ++ struct vbg_dev *gdev; ++ struct vmmdev_hgcm_service_location loc; ++ int err, vbox_status; ++ ++ loc.type = VMMDEV_HGCM_LOC_LOCALHOST_EXISTING; ++ strcpy(loc.u.localhost.service_name, "VBoxSharedFolders"); ++ ++ gdev = vbg_get_gdev(); ++ if (IS_ERR(gdev)) ++ return -ENODEV; /* No guest-device */ ++ ++ err = vbg_hgcm_connect(gdev, SHFL_REQUEST, &loc, ++ &vboxsf_client_id, &vbox_status); ++ vbg_put_gdev(gdev); ++ ++ return err ? err : vbg_status_code_to_errno(vbox_status); ++} ++ ++void vboxsf_disconnect(void) ++{ ++ struct vbg_dev *gdev; ++ int vbox_status; ++ ++ gdev = vbg_get_gdev(); ++ if (IS_ERR(gdev)) ++ return; /* guest-device is gone, already disconnected */ ++ ++ vbg_hgcm_disconnect(gdev, SHFL_REQUEST, vboxsf_client_id, &vbox_status); ++ vbg_put_gdev(gdev); ++} ++ ++static int vboxsf_call(u32 function, void *parms, u32 parm_count, int *status) ++{ ++ struct vbg_dev *gdev; ++ int err, vbox_status; ++ ++ gdev = vbg_get_gdev(); ++ if (IS_ERR(gdev)) ++ return -ESHUTDOWN; /* guest-dev removed underneath us */ ++ ++ err = vbg_hgcm_call(gdev, SHFL_REQUEST, vboxsf_client_id, function, ++ U32_MAX, parms, parm_count, &vbox_status); ++ vbg_put_gdev(gdev); ++ ++ if (err < 0) ++ return err; ++ ++ if (status) ++ *status = vbox_status; ++ ++ return vbg_status_code_to_errno(vbox_status); ++} ++ ++int vboxsf_map_folder(struct shfl_string *folder_name, u32 *root) ++{ ++ struct shfl_map_folder parms; ++ int err, status; ++ ++ parms.path.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL; ++ parms.path.u.pointer.size = shfl_string_buf_size(folder_name); ++ parms.path.u.pointer.u.linear_addr = (uintptr_t)folder_name; ++ ++ parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.root.u.value32 = 0; ++ ++ parms.delimiter.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.delimiter.u.value32 = '/'; ++ ++ parms.case_sensitive.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.case_sensitive.u.value32 = 1; ++ ++ err = vboxsf_call(SHFL_FN_MAP_FOLDER, &parms, SHFL_CPARMS_MAP_FOLDER, ++ &status); ++ if (err == -ENOSYS && status == VERR_NOT_IMPLEMENTED) ++ vbg_err("%s: Error host is too old\n", __func__); ++ ++ *root = parms.root.u.value32; ++ return err; ++} ++ ++int vboxsf_unmap_folder(u32 root) ++{ ++ struct shfl_unmap_folder parms; ++ ++ parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.root.u.value32 = root; ++ ++ return vboxsf_call(SHFL_FN_UNMAP_FOLDER, &parms, ++ SHFL_CPARMS_UNMAP_FOLDER, NULL); ++} ++ ++/** ++ * vboxsf_create - Create a new file or folder ++ * @root: Root of the shared folder in which to create the file ++ * @parsed_path: The path of the file or folder relative to the shared folder ++ * @param: create_parms Parameters for file/folder creation. ++ * ++ * Create a new file or folder or open an existing one in a shared folder. ++ * Note this function always returns 0 / success unless an exceptional condition ++ * occurs - out of memory, invalid arguments, etc. If the file or folder could ++ * not be opened or created, create_parms->handle will be set to ++ * SHFL_HANDLE_NIL on return. In this case the value in create_parms->result ++ * provides information as to why (e.g. SHFL_FILE_EXISTS), create_parms->result ++ * is also set on success as additional information. ++ * ++ * Returns: ++ * 0 or negative errno value. ++ */ ++int vboxsf_create(u32 root, struct shfl_string *parsed_path, ++ struct shfl_createparms *create_parms) ++{ ++ struct shfl_create parms; ++ ++ parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.root.u.value32 = root; ++ ++ parms.path.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL; ++ parms.path.u.pointer.size = shfl_string_buf_size(parsed_path); ++ parms.path.u.pointer.u.linear_addr = (uintptr_t)parsed_path; ++ ++ parms.parms.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL; ++ parms.parms.u.pointer.size = sizeof(struct shfl_createparms); ++ parms.parms.u.pointer.u.linear_addr = (uintptr_t)create_parms; ++ ++ return vboxsf_call(SHFL_FN_CREATE, &parms, SHFL_CPARMS_CREATE, NULL); ++} ++ ++int vboxsf_close(u32 root, u64 handle) ++{ ++ struct shfl_close parms; ++ ++ parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.root.u.value32 = root; ++ ++ parms.handle.type = VMMDEV_HGCM_PARM_TYPE_64BIT; ++ parms.handle.u.value64 = handle; ++ ++ return vboxsf_call(SHFL_FN_CLOSE, &parms, SHFL_CPARMS_CLOSE, NULL); ++} ++ ++int vboxsf_remove(u32 root, struct shfl_string *parsed_path, u32 flags) ++{ ++ struct shfl_remove parms; ++ ++ parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.root.u.value32 = root; ++ ++ parms.path.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN; ++ parms.path.u.pointer.size = shfl_string_buf_size(parsed_path); ++ parms.path.u.pointer.u.linear_addr = (uintptr_t)parsed_path; ++ ++ parms.flags.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.flags.u.value32 = flags; ++ ++ return vboxsf_call(SHFL_FN_REMOVE, &parms, SHFL_CPARMS_REMOVE, NULL); ++} ++ ++int vboxsf_rename(u32 root, struct shfl_string *src_path, ++ struct shfl_string *dest_path, u32 flags) ++{ ++ struct shfl_rename parms; ++ ++ parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.root.u.value32 = root; ++ ++ parms.src.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN; ++ parms.src.u.pointer.size = shfl_string_buf_size(src_path); ++ parms.src.u.pointer.u.linear_addr = (uintptr_t)src_path; ++ ++ parms.dest.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN; ++ parms.dest.u.pointer.size = shfl_string_buf_size(dest_path); ++ parms.dest.u.pointer.u.linear_addr = (uintptr_t)dest_path; ++ ++ parms.flags.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.flags.u.value32 = flags; ++ ++ return vboxsf_call(SHFL_FN_RENAME, &parms, SHFL_CPARMS_RENAME, NULL); ++} ++ ++int vboxsf_read(u32 root, u64 handle, u64 offset, u32 *buf_len, u8 *buf) ++{ ++ struct shfl_read parms; ++ int err; ++ ++ parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.root.u.value32 = root; ++ ++ parms.handle.type = VMMDEV_HGCM_PARM_TYPE_64BIT; ++ parms.handle.u.value64 = handle; ++ parms.offset.type = VMMDEV_HGCM_PARM_TYPE_64BIT; ++ parms.offset.u.value64 = offset; ++ parms.cb.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.cb.u.value32 = *buf_len; ++ parms.buffer.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_OUT; ++ parms.buffer.u.pointer.size = *buf_len; ++ parms.buffer.u.pointer.u.linear_addr = (uintptr_t)buf; ++ ++ err = vboxsf_call(SHFL_FN_READ, &parms, SHFL_CPARMS_READ, NULL); ++ ++ *buf_len = parms.cb.u.value32; ++ return err; ++} ++ ++int vboxsf_write(u32 root, u64 handle, u64 offset, u32 *buf_len, u8 *buf) ++{ ++ struct shfl_write parms; ++ int err; ++ ++ parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.root.u.value32 = root; ++ ++ parms.handle.type = VMMDEV_HGCM_PARM_TYPE_64BIT; ++ parms.handle.u.value64 = handle; ++ parms.offset.type = VMMDEV_HGCM_PARM_TYPE_64BIT; ++ parms.offset.u.value64 = offset; ++ parms.cb.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.cb.u.value32 = *buf_len; ++ parms.buffer.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN; ++ parms.buffer.u.pointer.size = *buf_len; ++ parms.buffer.u.pointer.u.linear_addr = (uintptr_t)buf; ++ ++ err = vboxsf_call(SHFL_FN_WRITE, &parms, SHFL_CPARMS_WRITE, NULL); ++ ++ *buf_len = parms.cb.u.value32; ++ return err; ++} ++ ++/* Returns 0 on success, 1 on end-of-dir, negative errno otherwise */ ++int vboxsf_dirinfo(u32 root, u64 handle, ++ struct shfl_string *parsed_path, u32 flags, u32 index, ++ u32 *buf_len, struct shfl_dirinfo *buf, u32 *file_count) ++{ ++ struct shfl_list parms; ++ int err, status; ++ ++ parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.root.u.value32 = root; ++ ++ parms.handle.type = VMMDEV_HGCM_PARM_TYPE_64BIT; ++ parms.handle.u.value64 = handle; ++ parms.flags.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.flags.u.value32 = flags; ++ parms.cb.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.cb.u.value32 = *buf_len; ++ if (parsed_path) { ++ parms.path.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN; ++ parms.path.u.pointer.size = shfl_string_buf_size(parsed_path); ++ parms.path.u.pointer.u.linear_addr = (uintptr_t)parsed_path; ++ } else { ++ parms.path.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_IN; ++ parms.path.u.pointer.size = 0; ++ parms.path.u.pointer.u.linear_addr = 0; ++ } ++ ++ parms.buffer.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_OUT; ++ parms.buffer.u.pointer.size = *buf_len; ++ parms.buffer.u.pointer.u.linear_addr = (uintptr_t)buf; ++ ++ parms.resume_point.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.resume_point.u.value32 = index; ++ parms.file_count.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.file_count.u.value32 = 0; /* out parameter only */ ++ ++ err = vboxsf_call(SHFL_FN_LIST, &parms, SHFL_CPARMS_LIST, &status); ++ if (err == -ENODATA && status == VERR_NO_MORE_FILES) ++ err = 1; ++ ++ *buf_len = parms.cb.u.value32; ++ *file_count = parms.file_count.u.value32; ++ return err; ++} ++ ++int vboxsf_fsinfo(u32 root, u64 handle, u32 flags, ++ u32 *buf_len, void *buf) ++{ ++ struct shfl_information parms; ++ int err; ++ ++ parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.root.u.value32 = root; ++ ++ parms.handle.type = VMMDEV_HGCM_PARM_TYPE_64BIT; ++ parms.handle.u.value64 = handle; ++ parms.flags.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.flags.u.value32 = flags; ++ parms.cb.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.cb.u.value32 = *buf_len; ++ parms.info.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL; ++ parms.info.u.pointer.size = *buf_len; ++ parms.info.u.pointer.u.linear_addr = (uintptr_t)buf; ++ ++ err = vboxsf_call(SHFL_FN_INFORMATION, &parms, SHFL_CPARMS_INFORMATION, ++ NULL); ++ ++ *buf_len = parms.cb.u.value32; ++ return err; ++} ++ ++int vboxsf_readlink(u32 root, struct shfl_string *parsed_path, ++ u32 buf_len, u8 *buf) ++{ ++ struct shfl_readLink parms; ++ ++ parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.root.u.value32 = root; ++ ++ parms.path.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN; ++ parms.path.u.pointer.size = shfl_string_buf_size(parsed_path); ++ parms.path.u.pointer.u.linear_addr = (uintptr_t)parsed_path; ++ ++ parms.buffer.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_OUT; ++ parms.buffer.u.pointer.size = buf_len; ++ parms.buffer.u.pointer.u.linear_addr = (uintptr_t)buf; ++ ++ return vboxsf_call(SHFL_FN_READLINK, &parms, SHFL_CPARMS_READLINK, ++ NULL); ++} ++ ++int vboxsf_symlink(u32 root, struct shfl_string *new_path, ++ struct shfl_string *old_path, struct shfl_fsobjinfo *buf) ++{ ++ struct shfl_symlink parms; ++ ++ parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.root.u.value32 = root; ++ ++ parms.new_path.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN; ++ parms.new_path.u.pointer.size = shfl_string_buf_size(new_path); ++ parms.new_path.u.pointer.u.linear_addr = (uintptr_t)new_path; ++ ++ parms.old_path.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN; ++ parms.old_path.u.pointer.size = shfl_string_buf_size(old_path); ++ parms.old_path.u.pointer.u.linear_addr = (uintptr_t)old_path; ++ ++ parms.info.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_OUT; ++ parms.info.u.pointer.size = sizeof(struct shfl_fsobjinfo); ++ parms.info.u.pointer.u.linear_addr = (uintptr_t)buf; ++ ++ return vboxsf_call(SHFL_FN_SYMLINK, &parms, SHFL_CPARMS_SYMLINK, NULL); ++} ++ ++int vboxsf_set_utf8(void) ++{ ++ return vboxsf_call(SHFL_FN_SET_UTF8, NULL, 0, NULL); ++} ++ ++int vboxsf_set_symlinks(void) ++{ ++ return vboxsf_call(SHFL_FN_SET_SYMLINKS, NULL, 0, NULL); ++} +diff --git a/drivers/staging/vboxsf/vfsmod.h b/drivers/staging/vboxsf/vfsmod.h +new file mode 100644 +index 000000000000..de650d65fbe4 +--- /dev/null ++++ b/drivers/staging/vboxsf/vfsmod.h +@@ -0,0 +1,138 @@ ++/* SPDX-License-Identifier: MIT */ ++/* ++ * VirtualBox Guest Shared Folders support: module header. ++ * ++ * Copyright (C) 2006-2018 Oracle Corporation ++ */ ++ ++#ifndef VFSMOD_H ++#define VFSMOD_H ++ ++#include ++#include ++#include ++#include "shfl_hostintf.h" ++ ++#define DIR_BUFFER_SIZE SZ_16K ++ ++/* The cast is to prevent assignment of void * to pointers of arbitrary type */ ++#define VBOXSF_SBI(sb) ((struct vboxsf_sbi *)(sb)->s_fs_info) ++#define VBOXSF_I(i) container_of(i, struct vboxsf_inode, vfs_inode) ++ ++struct vboxsf_options { ++ unsigned long ttl; ++ kuid_t uid; ++ kgid_t gid; ++ bool dmode_set; ++ bool fmode_set; ++ umode_t dmode; ++ umode_t fmode; ++ umode_t dmask; ++ umode_t fmask; ++}; ++ ++struct vboxsf_fs_context { ++ struct vboxsf_options o; ++ char *nls_name; ++}; ++ ++/* per-shared folder information */ ++struct vboxsf_sbi { ++ struct vboxsf_options o; ++ struct shfl_fsobjinfo root_info; ++ struct idr ino_idr; ++ spinlock_t ino_idr_lock; /* This protects ino_idr */ ++ struct nls_table *nls; ++ u32 next_generation; ++ u32 root; ++ int bdi_id; ++}; ++ ++/* per-inode information */ ++struct vboxsf_inode { ++ /* some information was changed, update data on next revalidate */ ++ int force_restat; ++ /* list of open handles for this inode + lock protecting it */ ++ struct list_head handle_list; ++ /* This mutex protects handle_list accesses */ ++ struct mutex handle_list_mutex; ++ /* The VFS inode struct */ ++ struct inode vfs_inode; ++}; ++ ++struct vboxsf_dir_info { ++ struct list_head info_list; ++}; ++ ++struct vboxsf_dir_buf { ++ size_t entries; ++ size_t free; ++ size_t used; ++ void *buf; ++ struct list_head head; ++}; ++ ++/* globals */ ++extern const struct inode_operations vboxsf_dir_iops; ++extern const struct inode_operations vboxsf_lnk_iops; ++extern const struct inode_operations vboxsf_reg_iops; ++extern const struct file_operations vboxsf_dir_fops; ++extern const struct file_operations vboxsf_reg_fops; ++extern const struct address_space_operations vboxsf_reg_aops; ++extern const struct dentry_operations vboxsf_dentry_ops; ++ ++/* from utils.c */ ++struct inode *vboxsf_new_inode(struct super_block *sb); ++void vboxsf_init_inode(struct vboxsf_sbi *sbi, struct inode *inode, ++ const struct shfl_fsobjinfo *info); ++int vboxsf_create_at_dentry(struct dentry *dentry, ++ struct shfl_createparms *params); ++int vboxsf_stat(struct vboxsf_sbi *sbi, struct shfl_string *path, ++ struct shfl_fsobjinfo *info); ++int vboxsf_stat_dentry(struct dentry *dentry, struct shfl_fsobjinfo *info); ++int vboxsf_inode_revalidate(struct dentry *dentry); ++int vboxsf_getattr(const struct path *path, struct kstat *kstat, ++ u32 request_mask, unsigned int query_flags); ++int vboxsf_setattr(struct dentry *dentry, struct iattr *iattr); ++struct shfl_string *vboxsf_path_from_dentry(struct vboxsf_sbi *sbi, ++ struct dentry *dentry); ++int vboxsf_nlscpy(struct vboxsf_sbi *sbi, char *name, size_t name_bound_len, ++ const unsigned char *utf8_name, size_t utf8_len); ++struct vboxsf_dir_info *vboxsf_dir_info_alloc(void); ++void vboxsf_dir_info_free(struct vboxsf_dir_info *p); ++int vboxsf_dir_read_all(struct vboxsf_sbi *sbi, struct vboxsf_dir_info *sf_d, ++ u64 handle); ++ ++/* from vboxsf_wrappers.c */ ++int vboxsf_connect(void); ++void vboxsf_disconnect(void); ++ ++int vboxsf_create(u32 root, struct shfl_string *parsed_path, ++ struct shfl_createparms *create_parms); ++ ++int vboxsf_close(u32 root, u64 handle); ++int vboxsf_remove(u32 root, struct shfl_string *parsed_path, u32 flags); ++int vboxsf_rename(u32 root, struct shfl_string *src_path, ++ struct shfl_string *dest_path, u32 flags); ++ ++int vboxsf_read(u32 root, u64 handle, u64 offset, u32 *buf_len, u8 *buf); ++int vboxsf_write(u32 root, u64 handle, u64 offset, u32 *buf_len, u8 *buf); ++ ++int vboxsf_dirinfo(u32 root, u64 handle, ++ struct shfl_string *parsed_path, u32 flags, u32 index, ++ u32 *buf_len, struct shfl_dirinfo *buf, u32 *file_count); ++int vboxsf_fsinfo(u32 root, u64 handle, u32 flags, ++ u32 *buf_len, void *buf); ++ ++int vboxsf_map_folder(struct shfl_string *folder_name, u32 *root); ++int vboxsf_unmap_folder(u32 root); ++ ++int vboxsf_readlink(u32 root, struct shfl_string *parsed_path, ++ u32 buf_len, u8 *buf); ++int vboxsf_symlink(u32 root, struct shfl_string *new_path, ++ struct shfl_string *old_path, struct shfl_fsobjinfo *buf); ++ ++int vboxsf_set_utf8(void); ++int vboxsf_set_symlinks(void); ++ ++#endif +-- +cgit 1.2-0.3.lf.el7 + diff --git a/kernel/kernel/files/patches/pisilinux/kernel-5.4-build-fix.patch b/kernel/kernel/files/patches/pisilinux/kernel-5.4-build-fix.patch new file mode 100644 index 00000000..c1de3106 --- /dev/null +++ b/kernel/kernel/files/patches/pisilinux/kernel-5.4-build-fix.patch @@ -0,0 +1,18 @@ +--- a/Makefile.orig 2019-11-25 03:32:01.000000000 +0300 ++++ b/Makefile 2019-12-11 03:20:12.876664698 +0300 +@@ -509,15 +509,6 @@ + # ignore whole output directory + outputmakefile: + ifdef building_out_of_srctree +- $(Q)if [ -f $(srctree)/.config -o \ +- -d $(srctree)/include/config -o \ +- -d $(srctree)/arch/$(SRCARCH)/include/generated ]; then \ +- echo >&2 "***"; \ +- echo >&2 "*** The source tree is not clean, please run 'make$(if $(findstring command line, $(origin ARCH)), ARCH=$(ARCH)) mrproper'"; \ +- echo >&2 "*** in $(abs_srctree)";\ +- echo >&2 "***"; \ +- false; \ +- fi + $(Q)ln -fsn $(srctree) source + $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile $(srctree) + $(Q)test -e .gitignore || \ diff --git a/kernel/kernel/files/patches/pisilinux/revert-Makefile.patch b/kernel/kernel/files/patches/pisilinux/revert-Makefile.patch new file mode 100644 index 00000000..b4b37d09 --- /dev/null +++ b/kernel/kernel/files/patches/pisilinux/revert-Makefile.patch @@ -0,0 +1,780 @@ +--- a/Makefile.orig 2019-11-25 03:32:01.000000000 +0300 ++++ b/Makefile 2019-12-11 16:59:26.708807035 +0300 +@@ -3,7 +3,7 @@ + PATCHLEVEL = 4 + SUBLEVEL = 0 + EXTRAVERSION = +-NAME = Kleptomaniac Octopus ++NAME = Bobtail Squid + + # *DOCUMENTATION* + # To see a list of typical targets execute "make help" +@@ -206,16 +206,30 @@ + KBUILD_CHECKSRC = 0 + endif + +-# Use make M=dir or set the environment variable KBUILD_EXTMOD to specify the +-# directory of external module to build. Setting M= takes precedence. ++# Use make M=dir to specify directory of external module to build ++# Old syntax make ... SUBDIRS=$PWD is still supported ++# Setting the environment variable KBUILD_EXTMOD take precedence ++ifdef SUBDIRS ++ $(warning ================= WARNING ================) ++ $(warning 'SUBDIRS' will be removed after Linux 5.3) ++ $(warning ) ++ $(warning If you are building an individual subdirectory) ++ $(warning in the kernel tree, you can do like this:) ++ $(warning $$ make path/to/dir/you/want/to/build/) ++ $(warning (Do not forget the trailing slash)) ++ $(warning ) ++ $(warning If you are building an external module,) ++ $(warning Please use 'M=' or 'KBUILD_EXTMOD' instead) ++ $(warning ==========================================) ++ KBUILD_EXTMOD ?= $(SUBDIRS) ++endif ++ + ifeq ("$(origin M)", "command line") + KBUILD_EXTMOD := $(M) + endif + + export KBUILD_CHECKSRC KBUILD_EXTMOD + +-extmod-prefix = $(if $(KBUILD_EXTMOD),$(KBUILD_EXTMOD)/) +- + ifeq ($(abs_srctree),$(abs_objtree)) + # building in the source tree + srctree := . +@@ -257,62 +271,52 @@ + %asm-generic kernelversion %src-pkg + no-sync-config-targets := $(no-dot-config-targets) install %install \ + kernelrelease +-single-targets := %.a %.i %.ko %.lds %.ll %.lst %.mod %.o %.s %.symtypes %/ + +-config-build := +-mixed-build := +-need-config := 1 +-may-sync-config := 1 +-single-build := ++config-targets := 0 ++mixed-targets := 0 ++dot-config := 1 ++may-sync-config := 1 + + ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),) + ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),) +- need-config := ++ dot-config := 0 + endif + endif + + ifneq ($(filter $(no-sync-config-targets), $(MAKECMDGOALS)),) + ifeq ($(filter-out $(no-sync-config-targets), $(MAKECMDGOALS)),) +- may-sync-config := ++ may-sync-config := 0 + endif + endif + + ifneq ($(KBUILD_EXTMOD),) +- may-sync-config := ++ may-sync-config := 0 + endif + + ifeq ($(KBUILD_EXTMOD),) + ifneq ($(filter config %config,$(MAKECMDGOALS)),) +- config-build := 1 ++ config-targets := 1 + ifneq ($(words $(MAKECMDGOALS)),1) +- mixed-build := 1 ++ mixed-targets := 1 + endif + endif + endif + +-# We cannot build single targets and the others at the same time +-ifneq ($(filter $(single-targets), $(MAKECMDGOALS)),) +- single-build := 1 +- ifneq ($(filter-out $(single-targets), $(MAKECMDGOALS)),) +- mixed-build := 1 +- endif +-endif +- + # For "make -j clean all", "make -j mrproper defconfig all", etc. + ifneq ($(filter $(clean-targets),$(MAKECMDGOALS)),) + ifneq ($(filter-out $(clean-targets),$(MAKECMDGOALS)),) +- mixed-build := 1 ++ mixed-targets := 1 + endif + endif + + # install and modules_install need also be processed one by one + ifneq ($(filter install,$(MAKECMDGOALS)),) + ifneq ($(filter modules_install,$(MAKECMDGOALS)),) +- mixed-build := 1 ++ mixed-targets := 1 + endif + endif + +-ifdef mixed-build ++ifeq ($(mixed-targets),1) + # =========================================================================== + # We're called with mixed targets (*config and build targets). + # Handle them one by one. +@@ -328,7 +332,7 @@ + $(MAKE) -f $(srctree)/Makefile $$i; \ + done + +-else # !mixed-build ++else + + include scripts/Kbuild.include + +@@ -388,7 +392,9 @@ + export KCONFIG_CONFIG + + # SHELL used by kbuild +-CONFIG_SHELL := sh ++CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ ++ else if [ -x /bin/bash ]; then echo /bin/bash; \ ++ else echo sh; fi ; fi) + + HOST_LFS_CFLAGS := $(shell getconf LFS_CFLAGS 2>/dev/null) + HOST_LFS_LDFLAGS := $(shell getconf LFS_LDFLAGS 2>/dev/null) +@@ -425,7 +431,6 @@ + PYTHON2 = python2 + PYTHON3 = python3 + CHECK = sparse +-BASH = bash + + CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \ + -Wbitwise -Wno-return-void -Wno-unknown-attribute $(CF) +@@ -465,13 +470,12 @@ + KBUILD_CFLAGS_KERNEL := + KBUILD_AFLAGS_MODULE := -DMODULE + KBUILD_CFLAGS_MODULE := -DMODULE +-KBUILD_LDFLAGS_MODULE := +-export KBUILD_LDS_MODULE := $(srctree)/scripts/module-common.lds ++KBUILD_LDFLAGS_MODULE := -T $(srctree)/scripts/module-common.lds + KBUILD_LDFLAGS := + GCC_PLUGINS_CFLAGS := + CLANG_FLAGS := + +-export ARCH SRCARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE AS LD CC ++export ARCH SRCARCH CONFIG_SHELL HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE AS LD CC + export CPP AR NM STRIP OBJCOPY OBJDUMP OBJSIZE PAHOLE LEX YACC AWK INSTALLKERNEL + export PERL PYTHON PYTHON2 PYTHON3 CHECK CHECKFLAGS MAKE UTS_MACHINE HOSTCXX + export KBUILD_HOSTCXXFLAGS KBUILD_HOSTLDFLAGS KBUILD_HOSTLDLIBS LDFLAGS_MODULE +@@ -482,6 +486,7 @@ + export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE + export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE + export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL ++export KBUILD_ARFLAGS + + # Files to ignore in find ... statements + +@@ -501,7 +506,6 @@ + $(Q)rm -f .tmp_quiet_recordmcount + + PHONY += outputmakefile +-# Before starting out-of-tree build, make sure the source tree is clean. + # outputmakefile generates a Makefile in the output directory, if using a + # separate output directory. This allows convenient use of make in the + # output directory. +@@ -509,15 +513,6 @@ + # ignore whole output directory + outputmakefile: + ifdef building_out_of_srctree +- $(Q)if [ -f $(srctree)/.config -o \ +- -d $(srctree)/include/config -o \ +- -d $(srctree)/arch/$(SRCARCH)/include/generated ]; then \ +- echo >&2 "***"; \ +- echo >&2 "*** The source tree is not clean, please run 'make$(if $(findstring command line, $(origin ARCH)), ARCH=$(ARCH)) mrproper'"; \ +- echo >&2 "*** in $(abs_srctree)";\ +- echo >&2 "***"; \ +- false; \ +- fi + $(Q)ln -fsn $(srctree) source + $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile $(srctree) + $(Q)test -e .gitignore || \ +@@ -549,7 +544,7 @@ + # and from include/config/auto.conf.cmd to detect the compiler upgrade. + CC_VERSION_TEXT = $(shell $(CC) --version 2>/dev/null | head -n 1) + +-ifdef config-build ++ifeq ($(config-targets),1) + # =========================================================================== + # *config targets only - make sure prerequisites are updated, and descend + # in scripts/kconfig to make the *config target +@@ -560,13 +555,13 @@ + include arch/$(SRCARCH)/Makefile + export KBUILD_DEFCONFIG KBUILD_KCONFIG CC_VERSION_TEXT + +-config: outputmakefile scripts_basic FORCE ++config: scripts_basic outputmakefile FORCE + $(Q)$(MAKE) $(build)=scripts/kconfig $@ + +-%config: outputmakefile scripts_basic FORCE ++%config: scripts_basic outputmakefile FORCE + $(Q)$(MAKE) $(build)=scripts/kconfig $@ + +-else #!config-build ++else + # =========================================================================== + # Build targets only - this includes vmlinux, arch specific targets, clean + # targets and others. In general all targets except *config targets. +@@ -599,7 +594,7 @@ + # in addition to whatever we do anyway. + # Just "make" or "make all" shall build modules as well + +-ifneq ($(filter all _all modules nsdeps,$(MAKECMDGOALS)),) ++ifneq ($(filter all _all modules,$(MAKECMDGOALS)),) + KBUILD_MODULES := 1 + endif + +@@ -609,7 +604,7 @@ + + export KBUILD_MODULES KBUILD_BUILTIN + +-ifdef need-config ++ifeq ($(dot-config),1) + include include/config/auto.conf + endif + +@@ -650,10 +645,15 @@ + export RETPOLINE_CFLAGS + export RETPOLINE_VDSO_CFLAGS + ++# The arch Makefile can set ARCH_{CPP,A,C}FLAGS to override the default ++# values of the respective KBUILD_* variables ++ARCH_CPPFLAGS := ++ARCH_AFLAGS := ++ARCH_CFLAGS := + include arch/$(SRCARCH)/Makefile + +-ifdef need-config +-ifdef may-sync-config ++ifeq ($(dot-config),1) ++ifeq ($(may-sync-config),1) + # Read in dependencies to all Kconfig* files, make sure to run syncconfig if + # changes are detected. This should be included after arch/$(SRCARCH)/Makefile + # because some architectures define CROSS_COMPILE there. +@@ -676,7 +676,7 @@ + # The syncconfig should be executed only once to make all the targets. + %/auto.conf %/auto.conf.cmd %/tristate.conf: $(KCONFIG_CONFIG) + $(Q)$(MAKE) -f $(srctree)/Makefile syncconfig +-else # !may-sync-config ++else + # External modules and some install targets need include/generated/autoconf.h + # and include/config/auto.conf but do not care if they are up-to-date. + # Use auto.conf to trigger the test +@@ -692,7 +692,7 @@ + /bin/false) + + endif # may-sync-config +-endif # need-config ++endif # $(dot-config) + + KBUILD_CFLAGS += $(call cc-option,-fno-delete-null-pointer-checks,) + KBUILD_CFLAGS += $(call cc-disable-warning,frame-address,) +@@ -700,12 +700,10 @@ + KBUILD_CFLAGS += $(call cc-disable-warning, format-overflow) + KBUILD_CFLAGS += $(call cc-disable-warning, address-of-packed-member) + +-ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE +-KBUILD_CFLAGS += -O2 +-else ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3 +-KBUILD_CFLAGS += -O3 +-else ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE +-KBUILD_CFLAGS += -Os ++ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE ++KBUILD_CFLAGS += -Os ++else ++KBUILD_CFLAGS += -O2 + endif + + ifdef CONFIG_CC_DISABLE_WARN_MAYBE_UNINITIALIZED +@@ -753,11 +751,6 @@ + # These warnings generated too much noise in a regular build. + # Use make W=1 to enable them (see scripts/Makefile.extrawarn) + KBUILD_CFLAGS += -Wno-unused-but-set-variable +- +-# Warn about unmarked fall-throughs in switch statement. +-# Disabled for clang while comment to attribute conversion happens and +-# https://github.com/ClangBuiltLinux/linux/issues/636 is discussed. +-KBUILD_CFLAGS += $(call cc-option,-Wimplicit-fallthrough,) + endif + + KBUILD_CFLAGS += $(call cc-disable-warning, unused-const-variable) +@@ -852,6 +845,9 @@ + # warn about C99 declaration after statement + KBUILD_CFLAGS += -Wdeclaration-after-statement + ++# Warn about unmarked fall-throughs in switch statement. ++KBUILD_CFLAGS += $(call cc-option,-Wimplicit-fallthrough,) ++ + # Variable Length Arrays (VLAs) should not be used anywhere in the kernel + KBUILD_CFLAGS += -Wvla + +@@ -897,14 +893,18 @@ + KBUILD_CFLAGS += $(call cc-option,-fcf-protection=none) + endif + ++# use the deterministic mode of AR if available ++KBUILD_ARFLAGS := $(call ar-option,D) ++ + include scripts/Makefile.kasan + include scripts/Makefile.extrawarn + include scripts/Makefile.ubsan + +-# Add user supplied CPPFLAGS, AFLAGS and CFLAGS as the last assignments +-KBUILD_CPPFLAGS += $(KCPPFLAGS) +-KBUILD_AFLAGS += $(KAFLAGS) +-KBUILD_CFLAGS += $(KCFLAGS) ++# Add any arch overrides and user supplied CPPFLAGS, AFLAGS and CFLAGS as the ++# last assignments ++KBUILD_CPPFLAGS += $(ARCH_CPPFLAGS) $(KCPPFLAGS) ++KBUILD_AFLAGS += $(ARCH_AFLAGS) $(KAFLAGS) ++KBUILD_CFLAGS += $(ARCH_CFLAGS) $(KCFLAGS) + + KBUILD_LDFLAGS_MODULE += --build-id + LDFLAGS_vmlinux += --build-id +@@ -913,13 +913,6 @@ + LDFLAGS_vmlinux += $(call ld-option, -X,) + endif + +-ifeq ($(CONFIG_RELR),y) +-LDFLAGS_vmlinux += --pack-dyn-relocs=relr +-endif +- +-# make the checker run with the right architecture +-CHECKFLAGS += --arch=$(ARCH) +- + # insure the checker run with the right endianness + CHECKFLAGS += $(if $(CONFIG_CPU_BIG_ENDIAN),-mbig-endian,-mlittle-endian) + +@@ -1010,7 +1003,7 @@ + + PHONY += prepare0 + +-export MODORDER := $(extmod-prefix)modules.order ++export MODORDER := $(if $(KBUILD_EXTMOD),$(KBUILD_EXTMOD)/)modules.order + + ifeq ($(KBUILD_EXTMOD),) + core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/ +@@ -1023,9 +1016,6 @@ + $(patsubst %/,%,$(filter %/, $(init-) $(core-) \ + $(drivers-) $(net-) $(libs-) $(virt-)))) + +-build-dirs := $(vmlinux-dirs) +-clean-dirs := $(vmlinux-alldirs) +- + init-y := $(patsubst %/, %/built-in.a, $(init-y)) + core-y := $(patsubst %/, %/built-in.a, $(core-y)) + drivers-y := $(patsubst %/, %/built-in.a, $(drivers-y)) +@@ -1040,7 +1030,7 @@ + export KBUILD_VMLINUX_LIBS := $(libs-y1) + export KBUILD_LDS := arch/$(SRCARCH)/kernel/vmlinux.lds + export LDFLAGS_vmlinux +-# used by scripts/Makefile.package ++# used by scripts/package/Makefile + export KBUILD_ALLDIRS := $(sort $(filter-out arch/%,$(vmlinux-alldirs)) LICENSES arch include scripts tools) + + vmlinux-deps := $(KBUILD_LDS) $(KBUILD_VMLINUX_OBJS) $(KBUILD_VMLINUX_LIBS) +@@ -1048,7 +1038,7 @@ + # Recurse until adjust_autoksyms.sh is satisfied + PHONY += autoksyms_recursive + ifdef CONFIG_TRIM_UNUSED_KSYMS +-autoksyms_recursive: descend modules.order ++autoksyms_recursive: $(vmlinux-deps) modules.order + $(Q)$(CONFIG_SHELL) $(srctree)/scripts/adjust_autoksyms.sh \ + "$(MAKE) -f $(srctree)/Makefile vmlinux" + endif +@@ -1080,7 +1070,17 @@ + + # The actual objects are generated when descending, + # make sure no implicit rule kicks in +-$(sort $(vmlinux-deps)): descend ; ++$(sort $(vmlinux-deps)): $(vmlinux-dirs) ; ++ ++# Handle descending into subdirectories listed in $(vmlinux-dirs) ++# Preset locale variables to speed up the build process. Limit locale ++# tweaks to this spot to avoid wrong language settings when running ++# make menuconfig etc. ++# Error messages still appears in the original language ++ ++PHONY += $(vmlinux-dirs) ++$(vmlinux-dirs): prepare ++ $(Q)$(MAKE) $(build)=$@ need-builtin=1 need-modorder=1 + + filechk_kernel.release = \ + echo "$(KERNELVERSION)$$($(CONFIG_SHELL) $(srctree)/scripts/setlocalversion $(srctree))" +@@ -1102,9 +1102,24 @@ + # archprepare is used in arch Makefiles and when processed asm symlink, + # version.h and scripts_basic is processed / created. + +-PHONY += prepare archprepare ++PHONY += prepare archprepare prepare3 + +-archprepare: outputmakefile archheaders archscripts scripts include/config/kernel.release \ ++# prepare3 is used to check if we are building in a separate output directory, ++# and if so do: ++# 1) Check that make has not been executed in the kernel src $(srctree) ++prepare3: include/config/kernel.release ++ifdef building_out_of_srctree ++ @$(kecho) ' Using $(srctree) as source for kernel' ++ $(Q)if [ -f $(srctree)/.config -o \ ++ -d $(srctree)/include/config -o \ ++ -d $(srctree)/arch/$(SRCARCH)/include/generated ]; then \ ++ echo >&2 " $(srctree) is not clean, please run 'make ARCH=$(ARCH) mrproper'"; \ ++ echo >&2 " in the '$(srctree)' directory.";\ ++ /bin/false; \ ++ fi; ++endif ++ ++archprepare: archheaders archscripts scripts prepare3 outputmakefile \ + asm-generic $(version_h) $(autoksyms_h) include/generated/utsrelease.h + + prepare0: archprepare +@@ -1220,15 +1235,16 @@ + kselftest: + $(Q)$(MAKE) -C $(srctree)/tools/testing/selftests run_tests + +-kselftest-%: FORCE +- $(Q)$(MAKE) -C $(srctree)/tools/testing/selftests $* ++PHONY += kselftest-clean ++kselftest-clean: ++ $(Q)$(MAKE) -C $(srctree)/tools/testing/selftests clean + + PHONY += kselftest-merge + kselftest-merge: + $(if $(wildcard $(objtree)/.config),, $(error No .config exists, config your kernel first!)) + $(Q)find $(srctree)/tools/testing/selftests -name config | \ + xargs $(srctree)/scripts/kconfig/merge_config.sh -m $(objtree)/.config +- $(Q)$(MAKE) -f $(srctree)/Makefile olddefconfig ++ +$(Q)$(MAKE) -f $(srctree)/Makefile olddefconfig + + # --------------------------------------------------------------------------- + # Devicetree files +@@ -1239,11 +1255,11 @@ + + ifneq ($(dtstree),) + +-%.dtb: include/config/kernel.release scripts_dtc ++%.dtb: prepare3 scripts_dtc + $(Q)$(MAKE) $(build)=$(dtstree) $(dtstree)/$@ + + PHONY += dtbs dtbs_install dt_binding_check +-dtbs dtbs_check: include/config/kernel.release scripts_dtc ++dtbs dtbs_check: prepare3 scripts_dtc + $(Q)$(MAKE) $(build)=$(dtstree) + + dtbs_check: export CHECK_DTBS=1 +@@ -1282,16 +1298,17 @@ + + PHONY += modules + modules: $(if $(KBUILD_BUILTIN),vmlinux) modules.order modules.builtin ++ @$(kecho) ' Building modules, stage 2.'; + $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost + $(Q)$(CONFIG_SHELL) $(srctree)/scripts/modules-check.sh + +-modules.order: descend +- $(Q)$(AWK) '!x[$$0]++' $(addsuffix /$@, $(build-dirs)) > $@ ++modules.order: $(vmlinux-dirs) ++ $(Q)$(AWK) '!x[$$0]++' $(addsuffix /$@, $(vmlinux-dirs)) > $@ + +-modbuiltin-dirs := $(addprefix _modbuiltin_, $(build-dirs)) ++modbuiltin-dirs := $(addprefix _modbuiltin_, $(vmlinux-dirs)) + + modules.builtin: $(modbuiltin-dirs) +- $(Q)$(AWK) '!x[$$0]++' $(addsuffix /$@, $(build-dirs)) > $@ ++ $(Q)$(AWK) '!x[$$0]++' $(addsuffix /$@, $(vmlinux-dirs)) > $@ + + PHONY += $(modbuiltin-dirs) + # tristate.conf is not included from this Makefile. Add it as a prerequisite +@@ -1364,14 +1381,12 @@ + + # Directories & files removed with 'make mrproper' + MRPROPER_DIRS += include/config include/generated \ +- arch/$(SRCARCH)/include/generated .tmp_objdiff \ +- debian/ snap/ tar-install/ ++ arch/$(SRCARCH)/include/generated .tmp_objdiff + MRPROPER_FILES += .config .config.old .version \ + Module.symvers \ + signing_key.pem signing_key.priv signing_key.x509 \ + x509.genkey extra_certificates signing_key.x509.keyid \ +- signing_key.x509.signer vmlinux-gdb.py \ +- *.spec ++ signing_key.x509.signer vmlinux-gdb.py + + # Directories & files removed with 'make distclean' + DISTCLEAN_DIRS += +@@ -1381,8 +1396,11 @@ + # + clean: rm-dirs := $(CLEAN_DIRS) + clean: rm-files := $(CLEAN_FILES) ++clean-dirs := $(addprefix _clean_, . $(vmlinux-alldirs)) + +-PHONY += archclean vmlinuxclean ++PHONY += $(clean-dirs) clean archclean vmlinuxclean ++$(clean-dirs): ++ $(Q)$(MAKE) $(clean)=$(patsubst _clean_%,%,$@) + + vmlinuxclean: + $(Q)$(CONFIG_SHELL) $(srctree)/scripts/link-vmlinux.sh clean +@@ -1423,11 +1441,13 @@ + + # Packaging of the kernel to various formats + # --------------------------------------------------------------------------- ++package-dir := scripts/package + + %src-pkg: FORCE +- $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.package $@ ++ $(Q)$(MAKE) $(build)=$(package-dir) $@ + %pkg: include/config/kernel.release FORCE +- $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.package $@ ++ $(Q)$(MAKE) $(build)=$(package-dir) $@ ++ + + # Brief documentation of the typical targets used + # --------------------------------------------------------------------------- +@@ -1480,9 +1500,6 @@ + @echo ' headerdep - Detect inclusion cycles in headers' + @echo ' coccicheck - Check with Coccinelle' + @echo '' +- @echo 'Tools:' +- @echo ' nsdeps - Generate missing symbol namespace dependencies' +- @echo '' + @echo 'Kernel selftest:' + @echo ' kselftest - Build and run kernel selftest (run as root)' + @echo ' Build, install, and boot kernel before' +@@ -1493,10 +1510,8 @@ + @echo '' + @$(if $(dtstree), \ + echo 'Devicetree:'; \ +- echo '* dtbs - Build device tree blobs for enabled boards'; \ +- echo ' dtbs_install - Install dtbs to $(INSTALL_DTBS_PATH)'; \ +- echo ' dt_binding_check - Validate device tree binding documents'; \ +- echo ' dtbs_check - Validate device tree source files';\ ++ echo '* dtbs - Build device tree blobs for enabled boards'; \ ++ echo ' dtbs_install - Install dtbs to $(INSTALL_DTBS_PATH)'; \ + echo '') + + @echo 'Userspace tools targets:' +@@ -1504,7 +1519,7 @@ + @echo ' or "cd tools; make help"' + @echo '' + @echo 'Kernel packaging:' +- @$(MAKE) -f $(srctree)/scripts/Makefile.package help ++ @$(MAKE) $(build)=$(package-dir) help + @echo '' + @echo 'Documentation targets:' + @$(MAKE) -f $(srctree)/Documentation/Makefile dochelp +@@ -1529,7 +1544,7 @@ + @echo ' make C=1 [targets] Check re-compiled c source with $$CHECK (sparse by default)' + @echo ' make C=2 [targets] Force check of all c source with $$CHECK' + @echo ' make RECORDMCOUNT_WARN=1 [targets] Warn about ignored mcount sections' +- @echo ' make W=n [targets] Enable extra build checks, n=1,2,3 where' ++ @echo ' make W=n [targets] Enable extra gcc checks, n=1,2,3 where' + @echo ' 1: warnings which may be relevant and do not occur too often' + @echo ' 2: warnings which occur quite often but may still be relevant' + @echo ' 3: more obscure warnings, can most likely be ignored' +@@ -1558,7 +1573,7 @@ + DOC_TARGETS := xmldocs latexdocs pdfdocs htmldocs epubdocs cleandocs \ + linkcheckdocs dochelp refcheckdocs + PHONY += $(DOC_TARGETS) +-$(DOC_TARGETS): ++$(DOC_TARGETS): scripts_basic FORCE + $(Q)$(MAKE) $(build)=Documentation $@ + + # Misc +@@ -1603,9 +1618,13 @@ + echo " is missing; modules will have no dependencies and modversions."; \ + echo ) + +-build-dirs := $(KBUILD_EXTMOD) +-PHONY += modules +-modules: descend $(objtree)/Module.symvers ++module-dirs := $(addprefix _module_,$(KBUILD_EXTMOD)) ++PHONY += $(module-dirs) modules ++$(module-dirs): prepare $(objtree)/Module.symvers ++ $(Q)$(MAKE) $(build)=$(patsubst _module_%,%,$@) need-modorder=1 ++ ++modules: $(module-dirs) ++ @$(kecho) ' Building modules, stage 2.'; + $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost + + PHONY += modules_install +@@ -1621,12 +1640,13 @@ + _emodinst_post: _emodinst_ + $(call cmd,depmod) + +-clean-dirs := $(KBUILD_EXTMOD) +-clean: rm-files := $(KBUILD_EXTMOD)/Module.symvers ++clean-dirs := $(addprefix _clean_,$(KBUILD_EXTMOD)) + +-PHONY += / +-/: +- @echo >&2 '"$(MAKE) /" is no longer supported. Please use "$(MAKE) ./" instead.' ++PHONY += $(clean-dirs) clean ++$(clean-dirs): ++ $(Q)$(MAKE) $(clean)=$(patsubst _clean_%,%,$@) ++ ++clean: rm-files := $(KBUILD_EXTMOD)/Module.symvers + + PHONY += help + help: +@@ -1641,21 +1661,6 @@ + PHONY += prepare + endif # KBUILD_EXTMOD + +-# Handle descending into subdirectories listed in $(build-dirs) +-# Preset locale variables to speed up the build process. Limit locale +-# tweaks to this spot to avoid wrong language settings when running +-# make menuconfig etc. +-# Error messages still appears in the original language +-PHONY += descend $(build-dirs) +-descend: $(build-dirs) +-$(build-dirs): prepare +- $(Q)$(MAKE) $(build)=$@ single-build=$(single-build) need-builtin=1 need-modorder=1 +- +-clean-dirs := $(addprefix _clean_, $(clean-dirs)) +-PHONY += $(clean-dirs) clean +-$(clean-dirs): +- $(Q)$(MAKE) $(clean)=$(patsubst _clean_%,%,$@) +- + clean: $(clean-dirs) + $(call cmd,rmdirs) + $(call cmd,rmfiles) +@@ -1664,7 +1669,7 @@ + -o -name '*.ko.*' \ + -o -name '*.dtb' -o -name '*.dtb.S' -o -name '*.dt.yaml' \ + -o -name '*.dwo' -o -name '*.lst' \ +- -o -name '*.su' -o -name '*.mod' -o -name '*.ns_deps' \ ++ -o -name '*.su' -o -name '*.mod' \ + -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \ + -o -name '*.lex.c' -o -name '*.tab.[ch]' \ + -o -name '*.asn1.[ch]' \ +@@ -1677,20 +1682,11 @@ + # Generate tags for editors + # --------------------------------------------------------------------------- + quiet_cmd_tags = GEN $@ +- cmd_tags = $(BASH) $(srctree)/scripts/tags.sh $@ ++ cmd_tags = $(CONFIG_SHELL) $(srctree)/scripts/tags.sh $@ + + tags TAGS cscope gtags: FORCE + $(call cmd,tags) + +-# Script to generate missing namespace dependencies +-# --------------------------------------------------------------------------- +- +-PHONY += nsdeps +- +-nsdeps: modules +- $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost nsdeps +- $(Q)$(CONFIG_SHELL) $(srctree)/scripts/$@ +- + # Scripts to check various things for consistency + # --------------------------------------------------------------------------- + +@@ -1707,7 +1703,7 @@ + | xargs $(PERL) -w $(srctree)/scripts/checkversion.pl + + coccicheck: +- $(Q)$(BASH) $(srctree)/scripts/$@ ++ $(Q)$(CONFIG_SHELL) $(srctree)/scripts/$@ + + namespacecheck: + $(PERL) $(srctree)/scripts/namespace.pl +@@ -1755,47 +1751,45 @@ + + # Single targets + # --------------------------------------------------------------------------- +-# To build individual files in subdirectories, you can do like this: +-# +-# make foo/bar/baz.s +-# +-# The supported suffixes for single-target are listed in 'single-targets' +-# +-# To build only under specific subdirectories, you can do like this: +-# +-# make foo/bar/baz/ +- +-ifdef single-build +- +-single-all := $(filter $(single-targets), $(MAKECMDGOALS)) +- +-# .ko is special because modpost is needed +-single-ko := $(sort $(filter %.ko, $(single-all))) +-single-no-ko := $(sort $(patsubst %.ko,%.mod, $(single-all))) +- +-$(single-ko): single_modpost +- @: +-$(single-no-ko): descend +- @: +- ++# Single targets are compatible with: ++# - build with mixed source and output ++# - build with separate output dir 'make O=...' ++# - external modules ++# ++# target-dir => where to store outputfile ++# build-dir => directory in kernel source tree to use ++ ++build-target = $(if $(KBUILD_EXTMOD), $(KBUILD_EXTMOD)/)$@ ++build-dir = $(patsubst %/,%,$(dir $(build-target))) ++ ++%.i: prepare FORCE ++ $(Q)$(MAKE) $(build)=$(build-dir) $(build-target) ++%.ll: prepare FORCE ++ $(Q)$(MAKE) $(build)=$(build-dir) $(build-target) ++%.lst: prepare FORCE ++ $(Q)$(MAKE) $(build)=$(build-dir) $(build-target) ++%.o: prepare FORCE ++ $(Q)$(MAKE) $(build)=$(build-dir) $(build-target) ++%.s: prepare FORCE ++ $(Q)$(MAKE) $(build)=$(build-dir) $(build-target) ++%.symtypes: prepare FORCE ++ $(Q)$(MAKE) $(build)=$(build-dir) $(build-target) + ifeq ($(KBUILD_EXTMOD),) +-# For the single build of in-tree modules, use a temporary file to avoid ++# For the single build of an in-tree module, use a temporary file to avoid + # the situation of modules_install installing an invalid modules.order. +-MODORDER := .modules.tmp ++%.ko: MODORDER := .modules.tmp + endif +- +-PHONY += single_modpost +-single_modpost: $(single-no-ko) +- $(Q){ $(foreach m, $(single-ko), echo $(extmod-prefix)$m;) } > $(MODORDER) ++%.ko: prepare FORCE ++ $(Q)$(MAKE) $(build)=$(build-dir) $(build-target:.ko=.mod) ++ $(Q)echo $(build-target) > $(MODORDER) + $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost + +-KBUILD_MODULES := 1 +- +-export KBUILD_SINGLE_TARGETS := $(addprefix $(extmod-prefix), $(single-no-ko)) ++# Modules ++PHONY += / ++/: ./ + +-single-build = $(if $(filter-out $@/, $(single-no-ko)),1) +- +-endif ++%/: prepare FORCE ++ $(Q)$(MAKE) KBUILD_MODULES=1 $(build)=$(build-dir) need-modorder=1 + + # FIXME Should go into a make.lib or something + # =========================================================================== +@@ -1816,9 +1810,9 @@ + + -include $(foreach f,$(existing-targets),$(dir $(f)).$(notdir $(f)).cmd) + +-endif # config-targets +-endif # mixed-build +-endif # need-sub-make ++endif # ifeq ($(config-targets),1) ++endif # ifeq ($(mixed-targets),1) ++endif # need-sub-make + + PHONY += FORCE + FORCE: diff --git a/kernel/kernel/files/scripts/generate-module-list b/kernel/kernel/files/scripts/generate-module-list old mode 100644 new mode 100755 diff --git a/kernel/kernel/pspec.xml b/kernel/kernel/pspec.xml index 0f5aa24d..fe719656 100644 --- a/kernel/kernel/pspec.xml +++ b/kernel/kernel/pspec.xml @@ -12,7 +12,7 @@ kernel The Linux kernel (the core of the Linux operating system) for Pisi Linux kernel contains the Linux kernel, the core of any Linux operating system. The kernel handles the basic functions of the operating system: memory allocation, process allocation, device input and output, etc. - https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.19.tar.gz + https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-5.4.tar.gz configs/kernel-i686-config configs/kernel-x86_64-config @@ -29,16 +29,20 @@ zlib-devel xz-devel openssl-devel + rsync - patches/linux/patch-4.19.56.xz - - - - - patches/mageia_4_19/fs-aufs-4.19.patch - patches/mageia_4_19/fs-aufs-4.19-modular.patch + patches/linux/patch-5.4.6.xz + + patches/mageia/fs-aufs-5.4.patch + patches/mageia/fs-aufs-5.4-modular.patch + patches/mageia/fs-vboxsf.patch + patches/mageia/CVE-2019-12379.patch + + + + patches/pisilinux/revert-Makefile.patch @@ -94,6 +98,17 @@ + + 2019-12-27 + 5.4.6 + Version Bump. + security + + systemRestart + + Idris Kalp + idriskalp@gmail.com + 2019-06-25 4.19.56