diff --git a/kernel/kernel/files/configs/kernel-x86_64-config b/kernel/kernel/files/configs/kernel-x86_64-config index 15c6d75d..cfd4c6df 100755 --- a/kernel/kernel/files/configs/kernel-x86_64-config +++ b/kernel/kernel/files/configs/kernel-x86_64-config @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86_64 5.6.19 Kernel Configuration +# Linux/x86_64 5.7.13 Kernel Configuration # # @@ -8,6 +8,7 @@ # CONFIG_CC_IS_GCC=y CONFIG_GCC_VERSION=90201 +CONFIG_LD_VERSION=233010000 CONFIG_CLANG_VERSION=0 CONFIG_CC_CAN_LINK=y CONFIG_CC_HAS_ASM_GOTO=y @@ -56,6 +57,8 @@ 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_INJECTION=y +CONFIG_HARDIRQS_SW_RESEND=y CONFIG_GENERIC_IRQ_CHIP=y CONFIG_IRQ_DOMAIN=y CONFIG_IRQ_SIM=y @@ -71,7 +74,6 @@ CONFIG_SPARSE_IRQ=y # 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 @@ -103,6 +105,7 @@ 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_SCHED_THERMAL_PRESSURE is not set CONFIG_BSD_PROCESS_ACCT=y CONFIG_BSD_PROCESS_ACCT_V3=y CONFIG_TASKSTATS=y @@ -136,6 +139,7 @@ CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y # # Scheduler features # +# CONFIG_UCLAMP_TASK is not set # end of Scheduler features CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y @@ -220,6 +224,7 @@ CONFIG_MEMBARRIER=y CONFIG_KALLSYMS=y CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y CONFIG_KALLSYMS_BASE_RELATIVE=y +# CONFIG_BPF_LSM is not set CONFIG_BPF_SYSCALL=y CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y # CONFIG_BPF_JIT_ALWAYS_ON is not set @@ -253,7 +258,6 @@ 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 @@ -295,7 +299,7 @@ CONFIG_X86_X2APIC=y CONFIG_X86_MPPARSE=y # CONFIG_GOLDFISH is not set CONFIG_RETPOLINE=y -# CONFIG_X86_CPU_RESCTRL is not set +CONFIG_X86_CPU_RESCTRL=y CONFIG_X86_EXTENDED_PLATFORM=y # CONFIG_X86_NUMACHIP is not set # CONFIG_X86_VSMP is not set @@ -330,7 +334,7 @@ CONFIG_PVH=y CONFIG_PARAVIRT_TIME_ACCOUNTING=y CONFIG_PARAVIRT_CLOCK=y # CONFIG_JAILHOUSE_GUEST is not set -# CONFIG_ACRN_GUEST is not set +CONFIG_ACRN_GUEST=y # CONFIG_MK8 is not set # CONFIG_MPSC is not set # CONFIG_MCORE2 is not set @@ -488,7 +492,9 @@ CONFIG_PM_SLEEP_DEBUG=y 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 @@ -567,7 +573,7 @@ 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 +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y # # CPU frequency scaling drivers @@ -593,9 +599,9 @@ CONFIG_X86_SPEEDSTEP_LIB=y CONFIG_CPU_IDLE=y CONFIG_CPU_IDLE_GOV_LADDER=y CONFIG_CPU_IDLE_GOV_MENU=y -# CONFIG_CPU_IDLE_GOV_TEO is not set -# CONFIG_CPU_IDLE_GOV_HALTPOLL is not set -CONFIG_HALTPOLL_CPUIDLE=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 @@ -656,7 +662,7 @@ CONFIG_EFI_CAPSULE_LOADER=m CONFIG_EFI_TEST=m CONFIG_APPLE_PROPERTIES=y # CONFIG_RESET_ATTACK_MITIGATION is not set -# CONFIG_EFI_RCI2_TABLE is not set +CONFIG_EFI_RCI2_TABLE=y # CONFIG_EFI_DISABLE_PCI_DMA is not set # end of EFI (Extensible Firmware Interface) Support @@ -664,6 +670,7 @@ CONFIG_UEFI_CPER=y CONFIG_UEFI_CPER_X86=y CONFIG_EFI_DEV_PATH_PARSER=y CONFIG_EFI_EARLYCON=y +CONFIG_EFI_CUSTOM_SSDT_OVERLAYS=y # # Tegra firmware driver @@ -691,11 +698,9 @@ 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 +CONFIG_AS_AVX512=y +CONFIG_AS_SHA1_NI=y +CONFIG_AS_SHA256_NI=y # # General architecture-dependent options @@ -804,8 +809,8 @@ CONFIG_ARCH_HAS_MEM_ENCRYPT=y CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y # end of GCOV-based kernel profiling -CONFIG_PLUGIN_HOSTCC="" CONFIG_HAVE_GCC_PLUGINS=y +# CONFIG_GCC_PLUGINS is not set # end of General architecture-dependent options CONFIG_RT_MUTEXES=y @@ -923,6 +928,7 @@ CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y CONFIG_SPARSEMEM_VMEMMAP=y CONFIG_HAVE_MEMBLOCK_NODE_MAP=y CONFIG_HAVE_FAST_GUP=y +CONFIG_NUMA_KEEP_MEMINFO=y CONFIG_MEMORY_ISOLATION=y CONFIG_HAVE_BOOTMEM_INFO_NODE=y CONFIG_MEMORY_HOTPLUG=y @@ -933,6 +939,7 @@ CONFIG_SPLIT_PTLOCK_CPUS=4 CONFIG_MEMORY_BALLOON=y CONFIG_BALLOON_COMPACTION=y CONFIG_COMPACTION=y +CONFIG_PAGE_REPORTING=y CONFIG_MIGRATION=y CONFIG_CONTIG_ALLOC=y CONFIG_PHYS_ADDR_T_64BIT=y @@ -948,7 +955,6 @@ 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 @@ -1085,6 +1091,7 @@ 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_IPV6_RPL_LWTUNNEL is not set CONFIG_NETLABEL=y # CONFIG_MPTCP is not set CONFIG_NETWORK_SECMARK=y @@ -1142,8 +1149,8 @@ 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 is not set # CONFIG_NF_TABLES_INET is not set # CONFIG_NF_TABLES_NETDEV is not set # CONFIG_NFT_NUMGEN is not set @@ -1161,11 +1168,11 @@ CONFIG_NFT_QUEUE=m CONFIG_NFT_REJECT=m CONFIG_NFT_COMPAT=m CONFIG_NFT_HASH=m -# CONFIG_NFT_XFRM is not set +CONFIG_NFT_XFRM=m # CONFIG_NFT_SOCKET is not set # CONFIG_NFT_OSF is not set # CONFIG_NFT_TPROXY is not set -# CONFIG_NFT_SYNPROXY is not set +CONFIG_NFT_SYNPROXY=m # CONFIG_NF_FLOW_TABLE is not set CONFIG_NETFILTER_XTABLES=y @@ -1397,7 +1404,7 @@ CONFIG_IP6_NF_TARGET_NPT=m CONFIG_NF_DEFRAG_IPV6=m # CONFIG_NF_TABLES_BRIDGE is not set -# CONFIG_NF_CONNTRACK_BRIDGE is not set +CONFIG_NF_CONNTRACK_BRIDGE=m CONFIG_BRIDGE_NF_EBTABLES=m CONFIG_BRIDGE_EBT_BROUTE=m CONFIG_BRIDGE_EBT_T_FILTER=m @@ -1469,7 +1476,7 @@ CONFIG_NET_DSA=m 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 is not set +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 @@ -1531,7 +1538,7 @@ 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_TAPRIO is not set +CONFIG_NET_SCH_TAPRIO=m CONFIG_NET_SCH_GRED=m CONFIG_NET_SCH_DSMARK=m CONFIG_NET_SCH_NETEM=m @@ -1549,7 +1556,7 @@ CONFIG_NET_SCH_PIE=m # CONFIG_NET_SCH_FQ_PIE is not set CONFIG_NET_SCH_INGRESS=m CONFIG_NET_SCH_PLUG=m -# CONFIG_NET_SCH_ETS is not set +CONFIG_NET_SCH_ETS=m # CONFIG_NET_SCH_DEFAULT is not set # @@ -1591,15 +1598,14 @@ CONFIG_NET_ACT_PEDIT=m CONFIG_NET_ACT_SIMP=m CONFIG_NET_ACT_SKBEDIT=m CONFIG_NET_ACT_CSUM=m -# CONFIG_NET_ACT_MPLS is not set +CONFIG_NET_ACT_MPLS=m # CONFIG_NET_ACT_VLAN is not set CONFIG_NET_ACT_BPF=m CONFIG_NET_ACT_CONNMARK=m -# CONFIG_NET_ACT_CTINFO is not set +CONFIG_NET_ACT_CTINFO=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_ACT_CT is not set # CONFIG_NET_TC_SKB_EXT is not set CONFIG_NET_SCH_FIFO=y CONFIG_DCB=y @@ -1612,7 +1618,7 @@ CONFIG_BATMAN_ADV_DAT=y # CONFIG_BATMAN_ADV_MCAST is not set CONFIG_BATMAN_ADV_DEBUGFS=y # CONFIG_BATMAN_ADV_DEBUG is not set -CONFIG_BATMAN_ADV_SYSFS=y +# CONFIG_BATMAN_ADV_SYSFS is not set # CONFIG_BATMAN_ADV_TRACING is not set CONFIG_OPENVSWITCH=m CONFIG_OPENVSWITCH_GRE=m @@ -1700,7 +1706,7 @@ CONFIG_BT_RTL=m CONFIG_BT_HCIBTUSB=m # CONFIG_BT_HCIBTUSB_AUTOSUSPEND is not set CONFIG_BT_HCIBTUSB_BCM=y -# CONFIG_BT_HCIBTUSB_MTK is not set +CONFIG_BT_HCIBTUSB_MTK=y CONFIG_BT_HCIBTUSB_RTL=y CONFIG_BT_HCIBTSDIO=m CONFIG_BT_HCIUART=m @@ -1719,7 +1725,7 @@ CONFIG_BT_HCIVHCI=m CONFIG_BT_MRVL=m CONFIG_BT_MRVL_SDIO=m CONFIG_BT_ATH3K=m -# CONFIG_BT_MTKSDIO is not set +CONFIG_BT_MTKSDIO=m CONFIG_BT_HCIRSI=m # end of Bluetooth device drivers @@ -1865,8 +1871,8 @@ CONFIG_HOTPLUG_PCI_ACPI_IBM=m # # PCI controller drivers # -# CONFIG_VMD is not set -# CONFIG_PCI_HYPERV_INTERFACE is not set +CONFIG_VMD=m +CONFIG_PCI_HYPERV_INTERFACE=m # # DesignWare PCI Core Support @@ -1875,6 +1881,11 @@ CONFIG_HOTPLUG_PCI_ACPI_IBM=m # CONFIG_PCI_MESON is not set # end of DesignWare PCI Core Support +# +# Mobiveil PCIe Core Support +# +# end of Mobiveil PCIe Core Support + # # Cadence PCIe controllers support # @@ -1930,7 +1941,7 @@ CONFIG_FW_LOADER_PAGED_BUF=y CONFIG_EXTRA_FIRMWARE="" CONFIG_FW_LOADER_USER_HELPER=y CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y -# CONFIG_FW_LOADER_COMPRESS is not set +CONFIG_FW_LOADER_COMPRESS=y CONFIG_FW_CACHE=y # end of Firmware loader @@ -1952,6 +1963,7 @@ CONFIG_DMA_SHARED_BUFFER=y # # Bus devices # +# CONFIG_MHI_BUS is not set # end of Bus devices CONFIG_CONNECTOR=y @@ -2021,8 +2033,33 @@ CONFIG_MTD_CFI_I2=y # CONFIG_MTD_DOCG3 is not set # end of Self-contained MTD device drivers +CONFIG_MTD_NAND_CORE=m # CONFIG_MTD_ONENAND is not set -# CONFIG_MTD_RAW_NAND is not set +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 # # LPDDR & LPDDR2 PCM memory drivers @@ -2089,16 +2126,16 @@ CONFIG_BLK_DEV_RSXX=m CONFIG_NVME_CORE=m CONFIG_BLK_DEV_NVME=m # CONFIG_NVME_MULTIPATH is not set -# CONFIG_NVME_HWMON is not set +CONFIG_NVME_HWMON=y CONFIG_NVME_FABRICS=m CONFIG_NVME_RDMA=m # CONFIG_NVME_FC is not set -# CONFIG_NVME_TCP is not set +CONFIG_NVME_TCP=m CONFIG_NVME_TARGET=m CONFIG_NVME_TARGET_LOOP=m CONFIG_NVME_TARGET_RDMA=m # CONFIG_NVME_TARGET_FC is not set -# CONFIG_NVME_TARGET_TCP is not set +CONFIG_NVME_TARGET_TCP=m # end of NVME Support # @@ -2137,7 +2174,7 @@ CONFIG_EEPROM_LEGACY=m CONFIG_EEPROM_MAX6875=m CONFIG_EEPROM_93CX6=m # CONFIG_EEPROM_IDT_89HPESX is not set -# CONFIG_EEPROM_EE1004 is not set +CONFIG_EEPROM_EE1004=m # end of EEPROM support CONFIG_CB710_CORE=m @@ -2159,7 +2196,7 @@ CONFIG_ALTERA_STAPL=m CONFIG_INTEL_MEI=y CONFIG_INTEL_MEI_ME=m CONFIG_INTEL_MEI_TXE=m -# CONFIG_INTEL_MEI_HDCP is not set +CONFIG_INTEL_MEI_HDCP=m CONFIG_VMWARE_VMCI=m # @@ -2173,10 +2210,11 @@ CONFIG_INTEL_MIC_BUS=m CONFIG_GENWQE=m CONFIG_GENWQE_PLATFORM_ERROR_RECOVERY=1 # CONFIG_ECHO is not set -# CONFIG_MISC_ALCOR_PCI is not set +CONFIG_MISC_ALCOR_PCI=m # CONFIG_MISC_RTSX_PCI is not set # CONFIG_MISC_RTSX_USB is not set # CONFIG_HABANA_AI is not set +# CONFIG_UACCE is not set # end of Misc devices CONFIG_HAVE_IDE=y @@ -2198,7 +2236,6 @@ CONFIG_SCSI_PROC_FS=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=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 @@ -2271,12 +2308,12 @@ CONFIG_SCSI_UFS_DWC_TC_PCI=m CONFIG_SCSI_UFSHCD_PLATFORM=m # CONFIG_SCSI_UFS_CDNS_PLATFORM is not set CONFIG_SCSI_UFS_DWC_TC_PLATFORM=m -# CONFIG_SCSI_UFS_BSG is not set +CONFIG_SCSI_UFS_BSG=y CONFIG_SCSI_HPTIOP=m CONFIG_SCSI_BUSLOGIC=m # CONFIG_SCSI_FLASHPOINT is not set -# CONFIG_SCSI_MYRB is not set -# CONFIG_SCSI_MYRS is not set +CONFIG_SCSI_MYRB=m +CONFIG_SCSI_MYRS=m CONFIG_VMWARE_PVSCSI=m # CONFIG_XEN_SCSI_FRONTEND is not set CONFIG_HYPERV_STORAGE=m @@ -2286,7 +2323,8 @@ CONFIG_FCOE=m CONFIG_FCOE_FNIC=m # CONFIG_SCSI_SNIC is not set # CONFIG_SCSI_DMX3191D is not set -# CONFIG_SCSI_FDOMAIN_PCI is not set +CONFIG_SCSI_FDOMAIN=m +CONFIG_SCSI_FDOMAIN_PCI=m CONFIG_SCSI_GDTH=m CONFIG_SCSI_ISCI=m CONFIG_SCSI_IPS=m @@ -2328,7 +2366,10 @@ CONFIG_SCSI_DH_ALUA=m # end of SCSI device support CONFIG_ATA=y +CONFIG_SATA_HOST=y +CONFIG_PATA_TIMINGS=y CONFIG_ATA_VERBOSE_ERROR=y +CONFIG_ATA_FORCE=y CONFIG_ATA_ACPI=y CONFIG_SATA_ZPODD=y CONFIG_SATA_PMP=y @@ -2450,7 +2491,7 @@ CONFIG_DM_CACHE=m CONFIG_DM_CACHE_SMQ=m # CONFIG_DM_WRITECACHE is not set CONFIG_DM_ERA=m -# CONFIG_DM_CLONE is not set +CONFIG_DM_CLONE=m CONFIG_DM_MIRROR=y CONFIG_DM_LOG_USERSPACE=m CONFIG_DM_RAID=m @@ -2505,7 +2546,8 @@ CONFIG_MII=m CONFIG_NET_CORE=y CONFIG_BONDING=m CONFIG_DUMMY=m -# CONFIG_WIREGUARD is not set +CONFIG_WIREGUARD=m +# CONFIG_WIREGUARD_DEBUG is not set CONFIG_EQUALIZER=m CONFIG_NET_FC=y CONFIG_IFB=m @@ -2522,6 +2564,7 @@ CONFIG_IPVLAN=y # CONFIG_IPVTAP is not set CONFIG_VXLAN=m CONFIG_GENEVE=m +# CONFIG_BAREUDP is not set # CONFIG_GTP is not set # CONFIG_MACSEC is not set CONFIG_NETCONSOLE=m @@ -2566,10 +2609,10 @@ CONFIG_B53=m CONFIG_B53_MDIO_DRIVER=m CONFIG_B53_MMAP_DRIVER=m CONFIG_B53_SRAB_DRIVER=m -# CONFIG_B53_SERDES is not set +CONFIG_B53_SERDES=m # CONFIG_NET_DSA_BCM_SF2 is not set # CONFIG_NET_DSA_LOOP is not set -# CONFIG_NET_DSA_LANTIQ_GSWIP 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 @@ -2717,7 +2760,7 @@ CONFIG_IAVF=m CONFIG_I40EVF=m # CONFIG_ICE is not set # CONFIG_FM10K is not set -# CONFIG_IGC is not set +CONFIG_IGC=m CONFIG_JME=m CONFIG_NET_VENDOR_MARVELL=y CONFIG_MVMDIO=m @@ -2749,7 +2792,7 @@ CONFIG_NET_VENDOR_MICREL=y # CONFIG_KS8851_MLL is not set CONFIG_KSZ884X_PCI=m CONFIG_NET_VENDOR_MICROCHIP=y -# CONFIG_LAN743X is not set +CONFIG_LAN743X=m CONFIG_NET_VENDOR_MICROSEMI=y # CONFIG_MSCC_OCELOT_SWITCH is not set CONFIG_NET_VENDOR_MYRI=y @@ -2766,7 +2809,7 @@ CONFIG_VXGE=m CONFIG_NET_VENDOR_NETRONOME=y # CONFIG_NFP is not set CONFIG_NET_VENDOR_NI=y -# CONFIG_NI_XGE_MANAGEMENT_ENET is not set +CONFIG_NI_XGE_MANAGEMENT_ENET=m CONFIG_NET_VENDOR_8390=y CONFIG_PCMCIA_AXNET=m CONFIG_NE2K_PCI=m @@ -2779,7 +2822,7 @@ CONFIG_NET_VENDOR_PACKET_ENGINES=y CONFIG_HAMACHI=m CONFIG_YELLOWFIN=m CONFIG_NET_VENDOR_PENSANDO=y -# CONFIG_IONIC is not set +CONFIG_IONIC=m CONFIG_NET_VENDOR_QLOGIC=y CONFIG_QLA3XXX=m CONFIG_QLCNIC=m @@ -2835,6 +2878,7 @@ CONFIG_NET_VENDOR_STMICRO=y CONFIG_STMMAC_ETH=m # CONFIG_STMMAC_SELFTESTS is not set # CONFIG_STMMAC_PLATFORM is not set +CONFIG_DWMAC_INTEL=m # CONFIG_STMMAC_PCI is not set CONFIG_NET_VENDOR_SUN=y CONFIG_HAPPYMEAL=m @@ -2859,7 +2903,7 @@ CONFIG_WIZNET_W5300=m # CONFIG_WIZNET_BUS_INDIRECT is not set CONFIG_WIZNET_BUS_ANY=y CONFIG_NET_VENDOR_XILINX=y -# CONFIG_XILINX_AXI_EMAC is not set +CONFIG_XILINX_AXI_EMAC=m # CONFIG_XILINX_LL_TEMAC is not set CONFIG_NET_VENDOR_XIRCOM=y CONFIG_PCMCIA_XIRC2PS=m @@ -2873,7 +2917,9 @@ CONFIG_MDIO_BITBANG=m CONFIG_MDIO_CAVIUM=m CONFIG_MDIO_GPIO=m # CONFIG_MDIO_MSCC_MIIM is not set +# CONFIG_MDIO_MVUSB is not set CONFIG_MDIO_THUNDER=m +CONFIG_MDIO_XPCS=m CONFIG_PHYLINK=m CONFIG_PHYLIB=y CONFIG_SWPHY=y @@ -2883,7 +2929,7 @@ CONFIG_SWPHY=y # MII PHY device drivers # # CONFIG_SFP is not set -# CONFIG_ADIN_PHY is not set +CONFIG_ADIN_PHY=m CONFIG_AMD_PHY=m CONFIG_AQUANTIA_PHY=m # CONFIG_AX88796B_PHY is not set @@ -2899,7 +2945,7 @@ CONFIG_DAVICOM_PHY=m # CONFIG_DP83TC811_PHY is not set CONFIG_DP83848_PHY=m # CONFIG_DP83867_PHY is not set -# CONFIG_DP83869_PHY is not set +CONFIG_DP83869_PHY=m CONFIG_FIXED_PHY=y CONFIG_ICPLUS_PHY=m CONFIG_INTEL_XWAY_PHY=m @@ -2912,7 +2958,7 @@ CONFIG_MICROCHIP_PHY=m # CONFIG_MICROCHIP_T1_PHY is not set CONFIG_MICROSEMI_PHY=m CONFIG_NATIONAL_PHY=m -# CONFIG_NXP_TJA11XX_PHY is not set +CONFIG_NXP_TJA11XX_PHY=m CONFIG_QSEMI_PHY=m CONFIG_REALTEK_PHY=m # CONFIG_RENESAS_PHY is not set @@ -2983,7 +3029,7 @@ CONFIG_USB_IPHETH=m CONFIG_USB_SIERRA_NET=m CONFIG_USB_VL600=m CONFIG_USB_NET_CH9200=m -# CONFIG_USB_NET_AQC111 is not set +CONFIG_USB_NET_AQC111=m CONFIG_WLAN=y CONFIG_WLAN_VENDOR_ADMTEK=y # CONFIG_ADM8211 is not set @@ -3008,7 +3054,7 @@ CONFIG_ATH9K_WOW=y CONFIG_ATH9K_RFKILL=y # CONFIG_ATH9K_CHANNEL_CONTEXT is not set CONFIG_ATH9K_PCOEM=y -# CONFIG_ATH9K_PCI_NO_EEPROM is not set +CONFIG_ATH9K_PCI_NO_EEPROM=m CONFIG_ATH9K_HTC=m # CONFIG_ATH9K_HTC_DEBUGFS is not set CONFIG_ATH9K_HWRNG=y @@ -3124,19 +3170,21 @@ CONFIG_IWLWIFI_DEVICE_TRACING=y CONFIG_WLAN_VENDOR_INTERSIL=y CONFIG_HOSTAP=m -# CONFIG_HOSTAP_FIRMWARE is not set -# CONFIG_HOSTAP_PLX is not set -# CONFIG_HOSTAP_PCI is not set -# CONFIG_HOSTAP_CS is not set +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 is not set +CONFIG_HERMES_PRISM=y CONFIG_HERMES_CACHE_FW_ON_INIT=y -# CONFIG_PLX_HERMES is not set -# CONFIG_TMD_HERMES is not set -# CONFIG_NORTEL_HERMES is not set -# CONFIG_PCMCIA_HERMES is not set -# CONFIG_PCMCIA_SPECTRUM is not set -# CONFIG_ORINOCO_USB is not set +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 @@ -3157,12 +3205,16 @@ CONFIG_MWIFIEX_USB=m CONFIG_MWL8K=m CONFIG_WLAN_VENDOR_MEDIATEK=y CONFIG_MT7601U=m +CONFIG_MT76_CORE=m +CONFIG_MT76_LEDS=y +CONFIG_MT76x02_LIB=m +CONFIG_MT76x0_COMMON=m # CONFIG_MT76x0U is not set -# CONFIG_MT76x0E is not set +CONFIG_MT76x0E=m # CONFIG_MT76x2E is not set # CONFIG_MT76x2U is not set -# CONFIG_MT7603E is not set -# CONFIG_MT7615E is not set +CONFIG_MT7603E=m +CONFIG_MT7615E=m CONFIG_WLAN_VENDOR_RALINK=y CONFIG_RT2X00=m CONFIG_RT2400PCI=m @@ -3216,7 +3268,13 @@ CONFIG_RTL8723_COMMON=m CONFIG_RTLBTCOEXIST=m CONFIG_RTL8XXXU=m # CONFIG_RTL8XXXU_UNTESTED is not set -# CONFIG_RTW88 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 @@ -3236,7 +3294,8 @@ CONFIG_WLAN_VENDOR_ZYDAS=y CONFIG_ZD1211RW=m # CONFIG_ZD1211RW_DEBUG is not set CONFIG_WLAN_VENDOR_QUANTENNA=y -# CONFIG_QTNFMAC_PCIE is not set +CONFIG_QTNFMAC=m +CONFIG_QTNFMAC_PCIE=m # CONFIG_PCMCIA_RAYCS is not set # CONFIG_PCMCIA_WL3501 is not set CONFIG_MAC80211_HWSIM=m @@ -3575,24 +3634,7 @@ 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_NULL_TTY is not set CONFIG_LDISC_AUTOLOAD=y -CONFIG_DEVMEM=y -# CONFIG_DEVKMEM is not set # # Serial drivers @@ -3643,17 +3685,33 @@ CONFIG_SERIAL_RP2=m CONFIG_SERIAL_RP2_NR_UARTS=32 CONFIG_SERIAL_FSL_LPUART=m # CONFIG_SERIAL_FSL_LINFLEXUART is not set +# CONFIG_SERIAL_SPRD is not set # end of Serial drivers CONFIG_SERIAL_MCTRL_GPIO=y -# CONFIG_SERIAL_DEV_BUS is not set -CONFIG_PRINTER=m -CONFIG_LP_CONSOLE=y -CONFIG_PPDEV=m +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_ISI is not set +CONFIG_N_HDLC=m +CONFIG_N_GSM=m +CONFIG_NOZOMI=m +# CONFIG_NULL_TTY is not set +# CONFIG_TRACE_SINK is not set CONFIG_HVC_DRIVER=y CONFIG_HVC_IRQ=y CONFIG_HVC_XEN=y CONFIG_HVC_XEN_FRONTEND=y +# CONFIG_SERIAL_DEV_BUS is not set +CONFIG_PRINTER=m +CONFIG_LP_CONSOLE=y +CONFIG_PPDEV=m CONFIG_VIRTIO_CONSOLE=y CONFIG_IPMI_HANDLER=m CONFIG_IPMI_DMI_DECODE=y @@ -3664,14 +3722,13 @@ CONFIG_IPMI_SI=m # CONFIG_IPMI_SSIF is not set CONFIG_IPMI_WATCHDOG=m CONFIG_IPMI_POWEROFF=m -# CONFIG_IPMB_DEVICE_INTERFACE is not set +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=y # CONFIG_APPLICOM is not set # @@ -3685,8 +3742,12 @@ CONFIG_IPWIRELESS=m # end of PCMCIA character devices CONFIG_MWAVE=m +CONFIG_DEVMEM=y +# CONFIG_DEVKMEM is not set +CONFIG_NVRAM=y CONFIG_RAW_DRIVER=y CONFIG_MAX_RAW_DEVS=8192 +CONFIG_DEVPORT=y CONFIG_HPET=y # CONFIG_HPET_MMAP is not set CONFIG_HANGCHECK_TIMER=m @@ -3706,13 +3767,12 @@ 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 # end of Character devices # CONFIG_RANDOM_TRUST_CPU is not set -# CONFIG_RANDOM_TRUST_BOOTLOADER is not set +CONFIG_RANDOM_TRUST_BOOTLOADER=y # # I2C support @@ -3752,14 +3812,14 @@ CONFIG_I2C_ALGOPCA=m CONFIG_I2C_AMD756=m CONFIG_I2C_AMD756_S4882=m CONFIG_I2C_AMD8111=m -# CONFIG_I2C_AMD_MP2 is not set +CONFIG_I2C_AMD_MP2=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_NVIDIA_GPU is not set +CONFIG_I2C_NVIDIA_GPU=m # CONFIG_I2C_SIS5595 is not set # CONFIG_I2C_SIS630 is not set CONFIG_I2C_SIS96X=m @@ -3813,7 +3873,9 @@ CONFIG_I2C_SLAVE=y # CONFIG_I2C_DEBUG_BUS is not set # end of I2C support -# CONFIG_I3C is not set +CONFIG_I3C=m +CONFIG_CDNS_I3C_MASTER=m +CONFIG_DW_I3C_MASTER=m # CONFIG_SPI is not set CONFIG_SPMI=m # CONFIG_HSI is not set @@ -3839,7 +3901,9 @@ CONFIG_PTP_1588_CLOCK=y CONFIG_DP83640_PHY=m # CONFIG_PTP_1588_CLOCK_INES is not set CONFIG_PTP_1588_CLOCK_KVM=m +# CONFIG_PTP_1588_CLOCK_IDT82P33 is not set # CONFIG_PTP_1588_CLOCK_IDTCM is not set +# CONFIG_PTP_1588_CLOCK_VMW is not set # end of PTP clock support CONFIG_PINCTRL=y @@ -3850,7 +3914,7 @@ CONFIG_PINCTRL_AMD=y # CONFIG_PINCTRL_MCP23S08 is not set CONFIG_PINCTRL_BAYTRAIL=y CONFIG_PINCTRL_CHERRYVIEW=m -# CONFIG_PINCTRL_LYNXPOINT is not set +CONFIG_PINCTRL_LYNXPOINT=m CONFIG_PINCTRL_INTEL=m CONFIG_PINCTRL_BROXTON=m # CONFIG_PINCTRL_CANNONLAKE is not set @@ -3860,7 +3924,7 @@ CONFIG_PINCTRL_BROXTON=m # CONFIG_PINCTRL_ICELAKE is not set # CONFIG_PINCTRL_LEWISBURG is not set CONFIG_PINCTRL_SUNRISEPOINT=m -# CONFIG_PINCTRL_TIGERLAKE is not set +CONFIG_PINCTRL_TIGERLAKE=m CONFIG_GPIOLIB=y CONFIG_GPIOLIB_FASTPATH_LIMIT=512 CONFIG_GPIO_ACPI=y @@ -3879,8 +3943,8 @@ CONFIG_GPIO_GENERIC_PLATFORM=y CONFIG_GPIO_ICH=m # CONFIG_GPIO_MB86S7X is not set CONFIG_GPIO_VX855=m -# CONFIG_GPIO_XILINX is not set -# CONFIG_GPIO_AMD_FCH is not set +CONFIG_GPIO_XILINX=m +CONFIG_GPIO_AMD_FCH=m # end of Memory mapped GPIO drivers # @@ -3941,7 +4005,7 @@ CONFIG_W1_MASTER_DS2490=m CONFIG_W1_MASTER_DS2482=m CONFIG_W1_MASTER_DS1WM=m CONFIG_W1_MASTER_GPIO=m -# CONFIG_W1_MASTER_SGI is not set +CONFIG_W1_MASTER_SGI=m # end of 1-wire Bus Masters # @@ -3956,7 +4020,7 @@ 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_DS2430 is not set +CONFIG_W1_SLAVE_DS2430=m CONFIG_W1_SLAVE_DS2431=m CONFIG_W1_SLAVE_DS2433=m CONFIG_W1_SLAVE_DS2433_CRC=y @@ -3995,7 +4059,7 @@ CONFIG_BATTERY_BQ27XXX_HDQ=m # CONFIG_CHARGER_MAX8903 is not set # CONFIG_CHARGER_LP8727 is not set CONFIG_CHARGER_GPIO=m -# CONFIG_CHARGER_LT3651 is not set +CONFIG_CHARGER_LT3651=m CONFIG_CHARGER_MAX14577=m CONFIG_CHARGER_BQ2415X=m CONFIG_CHARGER_BQ24190=m @@ -4022,7 +4086,7 @@ CONFIG_SENSORS_ADM1025=m CONFIG_SENSORS_ADM1026=m CONFIG_SENSORS_ADM1029=m CONFIG_SENSORS_ADM1031=m -# CONFIG_SENSORS_ADM1177 is not set +CONFIG_SENSORS_ADM1177=m CONFIG_SENSORS_ADM9240=m CONFIG_SENSORS_ADT7X10=m CONFIG_SENSORS_ADT7410=m @@ -4030,8 +4094,9 @@ CONFIG_SENSORS_ADT7411=m CONFIG_SENSORS_ADT7462=m CONFIG_SENSORS_ADT7470=m CONFIG_SENSORS_ADT7475=m -# CONFIG_SENSORS_AS370 is not set +CONFIG_SENSORS_AS370=m CONFIG_SENSORS_ASC7621=m +# CONFIG_SENSORS_AXI_FAN_CONTROL is not set CONFIG_SENSORS_K8TEMP=m CONFIG_SENSORS_K10TEMP=m CONFIG_SENSORS_FAM15H_POWER=m @@ -4039,7 +4104,7 @@ CONFIG_SENSORS_APPLESMC=m CONFIG_SENSORS_ASB100=m # CONFIG_SENSORS_ASPEED is not set CONFIG_SENSORS_ATXP1=m -# CONFIG_SENSORS_DRIVETEMP is not set +CONFIG_SENSORS_DRIVETEMP=m CONFIG_SENSORS_DS620=m CONFIG_SENSORS_DS1621=m CONFIG_SENSORS_DELL_SMM=m @@ -4063,7 +4128,8 @@ CONFIG_SENSORS_IT87=m CONFIG_SENSORS_POWR1220=m CONFIG_SENSORS_LINEAGE=m CONFIG_SENSORS_LTC2945=m -# CONFIG_SENSORS_LTC2947_I2C is not set +CONFIG_SENSORS_LTC2947=m +CONFIG_SENSORS_LTC2947_I2C=m # CONFIG_SENSORS_LTC2990 is not set CONFIG_SENSORS_LTC4151=m CONFIG_SENSORS_LTC4215=m @@ -4075,7 +4141,7 @@ CONFIG_SENSORS_MAX16065=m CONFIG_SENSORS_MAX1619=m CONFIG_SENSORS_MAX1668=m CONFIG_SENSORS_MAX197=m -# CONFIG_SENSORS_MAX31730 is not set +CONFIG_SENSORS_MAX31730=m # CONFIG_SENSORS_MAX6621 is not set CONFIG_SENSORS_MAX6639=m CONFIG_SENSORS_MAX6642=m @@ -4113,26 +4179,26 @@ CONFIG_SENSORS_PMBUS=m CONFIG_SENSORS_ADM1275=m # CONFIG_SENSORS_BEL_PFE is not set # CONFIG_SENSORS_IBM_CFFPS is not set -# CONFIG_SENSORS_INSPUR_IPSPS is not set +CONFIG_SENSORS_INSPUR_IPSPS=m # CONFIG_SENSORS_IR35221 is not set -# CONFIG_SENSORS_IR38064 is not set -# CONFIG_SENSORS_IRPS5401 is not set -# CONFIG_SENSORS_ISL68137 is not set +CONFIG_SENSORS_IR38064=m +CONFIG_SENSORS_IRPS5401=m +CONFIG_SENSORS_ISL68137=m CONFIG_SENSORS_LM25066=m CONFIG_SENSORS_LTC2978=m # CONFIG_SENSORS_LTC3815 is not set CONFIG_SENSORS_MAX16064=m -# CONFIG_SENSORS_MAX20730 is not set +CONFIG_SENSORS_MAX20730=m CONFIG_SENSORS_MAX20751=m # CONFIG_SENSORS_MAX31785 is not set CONFIG_SENSORS_MAX34440=m CONFIG_SENSORS_MAX8688=m -# CONFIG_SENSORS_PXE1610 is not set +CONFIG_SENSORS_PXE1610=m CONFIG_SENSORS_TPS40422=m # CONFIG_SENSORS_TPS53679 is not set CONFIG_SENSORS_UCD9000=m CONFIG_SENSORS_UCD9200=m -# CONFIG_SENSORS_XDPE122 is not set +CONFIG_SENSORS_XDPE122=m CONFIG_SENSORS_ZL6100=m CONFIG_SENSORS_SHT15=m CONFIG_SENSORS_SHT21=m @@ -4164,7 +4230,7 @@ CONFIG_SENSORS_TMP103=m # CONFIG_SENSORS_TMP108 is not set CONFIG_SENSORS_TMP401=m CONFIG_SENSORS_TMP421=m -# CONFIG_SENSORS_TMP513 is not set +CONFIG_SENSORS_TMP513=m CONFIG_SENSORS_VIA_CPUTEMP=m CONFIG_SENSORS_VIA686A=m CONFIG_SENSORS_VT1211=m @@ -4346,6 +4412,7 @@ CONFIG_LPC_SCH=m CONFIG_MFD_INTEL_LPSS=m CONFIG_MFD_INTEL_LPSS_ACPI=m CONFIG_MFD_INTEL_LPSS_PCI=m +# CONFIG_MFD_IQS62X is not set # CONFIG_MFD_JANZ_CMODIO is not set # CONFIG_MFD_KEMPLD is not set # CONFIG_MFD_88PM800 is not set @@ -4399,7 +4466,7 @@ CONFIG_IR_SHARP_DECODER=m CONFIG_IR_MCE_KBD_DECODER=m CONFIG_IR_XMP_DECODER=m # CONFIG_IR_IMON_DECODER is not set -# CONFIG_IR_RCMM_DECODER is not set +CONFIG_IR_RCMM_DECODER=m CONFIG_RC_DEVICES=y CONFIG_RC_ATI_REMOTE=m CONFIG_IR_ENE=m @@ -4418,7 +4485,7 @@ CONFIG_IR_TTUSBIR=m CONFIG_RC_LOOPBACK=m # CONFIG_IR_SERIAL is not set # CONFIG_IR_SIR is not set -# CONFIG_RC_XBOX_DVD is not set +CONFIG_RC_XBOX_DVD=m CONFIG_MEDIA_SUPPORT=m # @@ -4432,7 +4499,7 @@ CONFIG_MEDIA_SDR_SUPPORT=y # CONFIG_MEDIA_CEC_SUPPORT is not set CONFIG_MEDIA_CONTROLLER=y CONFIG_MEDIA_CONTROLLER_DVB=y -# CONFIG_MEDIA_CONTROLLER_REQUEST_API is not set +CONFIG_MEDIA_CONTROLLER_REQUEST_API=y CONFIG_VIDEO_DEV=m CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_VIDEO_V4L2=m @@ -4532,7 +4599,6 @@ 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 @@ -5099,7 +5165,7 @@ CONFIG_DRM_AMDGPU_USERPTR=y # # ACP (Audio CoProcessor) Configuration # -# CONFIG_DRM_AMD_ACP is not set +CONFIG_DRM_AMD_ACP=y # end of ACP (Audio CoProcessor) Configuration # @@ -5107,11 +5173,11 @@ CONFIG_DRM_AMDGPU_USERPTR=y # CONFIG_DRM_AMD_DC=y CONFIG_DRM_AMD_DC_DCN=y -# CONFIG_DRM_AMD_DC_HDCP is not set +CONFIG_DRM_AMD_DC_HDCP=y # CONFIG_DEBUG_KERNEL_DC is not set # end of Display Engine Configuration -# CONFIG_HSA_AMD is not set +CONFIG_HSA_AMD=y CONFIG_DRM_NOUVEAU=m CONFIG_NOUVEAU_LEGACY_CTX_SUPPORT=y CONFIG_NOUVEAU_DEBUG=5 @@ -5119,8 +5185,7 @@ 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_FORCE_PROBE="" +CONFIG_DRM_I915_FORCE_PROBE="*" CONFIG_DRM_I915_CAPTURE_ERROR=y CONFIG_DRM_I915_COMPRESS_ERROR=y CONFIG_DRM_I915_USERPTR=y @@ -5128,7 +5193,7 @@ CONFIG_DRM_I915_GVT=y CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND=250 CONFIG_DRM_I915_HEARTBEAT_INTERVAL=2500 CONFIG_DRM_I915_PREEMPT_TIMEOUT=640 -CONFIG_DRM_I915_SPIN_REQUEST=5 +CONFIG_DRM_I915_MAX_REQUEST_BUSYWAIT=8000 CONFIG_DRM_I915_STOP_TIMEOUT=100 CONFIG_DRM_I915_TIMESLICE_DURATION=1 CONFIG_DRM_VGEM=m @@ -5163,17 +5228,17 @@ CONFIG_DRM_PANEL_BRIDGE=y # end of Display Interface Bridges # CONFIG_DRM_ETNAVIV is not set -# CONFIG_DRM_GM12U320 is not set +CONFIG_DRM_GM12U320=m # CONFIG_DRM_XEN is not set # CONFIG_DRM_VBOXVIDEO is not set CONFIG_DRM_LEGACY=y -# CONFIG_DRM_TDFX is not set -# CONFIG_DRM_R128 is not set -# CONFIG_DRM_I810 is not set -# CONFIG_DRM_MGA is not set -# CONFIG_DRM_SIS is not set +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 is not set +CONFIG_DRM_SAVAGE=m CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y # @@ -5511,16 +5576,16 @@ CONFIG_HID_APPLEIR=m CONFIG_HID_AUREAL=m CONFIG_HID_BELKIN=y CONFIG_HID_BETOP_FF=m -# CONFIG_HID_BIGBEN_FF is not set +CONFIG_HID_BIGBEN_FF=m CONFIG_HID_CHERRY=y CONFIG_HID_CHICONY=y CONFIG_HID_CORSAIR=m # CONFIG_HID_COUGAR is not set -# CONFIG_HID_MACALLY is not set +CONFIG_HID_MACALLY=m CONFIG_HID_PRODIKEYS=m # CONFIG_HID_CMEDIA is not set CONFIG_HID_CP2112=m -# CONFIG_HID_CREATIVE_SB0540 is not set +CONFIG_HID_CREATIVE_SB0540=m CONFIG_HID_CYPRESS=y CONFIG_HID_DRAGONRISE=m CONFIG_DRAGONRISE_FF=y @@ -5531,6 +5596,7 @@ CONFIG_HID_ELO=m CONFIG_HID_EZKEY=y CONFIG_HID_GEMBIRD=m CONFIG_HID_GFRM=m +# CONFIG_HID_GLORIOUS is not set CONFIG_HID_HOLTEK=m CONFIG_HOLTEK_FF=y # CONFIG_HID_GOOGLE_HAMMER is not set @@ -5610,6 +5676,7 @@ CONFIG_HID_ZYDACRON=m CONFIG_HID_SENSOR_HUB=m CONFIG_HID_SENSOR_CUSTOM_SENSOR=m CONFIG_HID_ALPS=m +# CONFIG_HID_MCP2221 is not set # end of Special HID drivers # @@ -5630,7 +5697,7 @@ CONFIG_I2C_HID=m # Intel ISH HID support # CONFIG_INTEL_ISH_HID=m -# CONFIG_INTEL_ISH_FIRMWARE_DOWNLOADER is not set +CONFIG_INTEL_ISH_FIRMWARE_DOWNLOADER=m # end of Intel ISH HID support # end of HID support @@ -5727,7 +5794,9 @@ CONFIG_USB_UAS=m CONFIG_USB_MDC800=m CONFIG_USB_MICROTEK=m # CONFIG_USBIP_CORE is not set -# CONFIG_USB_CDNS3 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 @@ -5837,6 +5906,7 @@ CONFIG_USB_LCD=m CONFIG_USB_IDMOUSE=m CONFIG_USB_FTDI_ELAN=m CONFIG_USB_APPLEDISPLAY=m +# CONFIG_APPLE_MFI_FASTCHARGE is not set CONFIG_USB_SISUSBVGA=m CONFIG_USB_SISUSBVGA_CON=y CONFIG_USB_LD=m @@ -5870,7 +5940,8 @@ CONFIG_USB_ISP1301=m # CONFIG_USB_GADGET is not set # CONFIG_TYPEC is not set -# CONFIG_USB_ROLE_SWITCH is not set +CONFIG_USB_ROLE_SWITCH=m +CONFIG_USB_ROLES_INTEL_XHCI=m CONFIG_MMC=m CONFIG_MMC_BLOCK=m CONFIG_MMC_BLOCK_MINORS=8 @@ -5889,6 +5960,7 @@ CONFIG_MMC_SDHCI_ACPI=m CONFIG_MMC_SDHCI_PLTFM=m # CONFIG_MMC_SDHCI_F_SDH30 is not set CONFIG_MMC_WBSD=m +CONFIG_MMC_ALCOR=m CONFIG_MMC_TIFM_SD=m CONFIG_MMC_SDRICOH_CS=m CONFIG_MMC_CB710=m @@ -5897,6 +5969,7 @@ CONFIG_MMC_VUB300=m CONFIG_MMC_USHC=m CONFIG_MMC_USDHI6ROL0=m CONFIG_MMC_CQHCI=m +# CONFIG_MMC_HSQ is not set # CONFIG_MMC_TOSHIBA_PCI is not set # CONFIG_MMC_MTK is not set # CONFIG_MMC_SDHCI_XENON is not set @@ -5984,7 +6057,7 @@ 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_LEDS_TRIGGER_PATTERN is not set +CONFIG_LEDS_TRIGGER_PATTERN=m CONFIG_LEDS_TRIGGER_AUDIO=m CONFIG_ACCESSIBILITY=y CONFIG_A11Y_BRAILLE_CONSOLE=y @@ -6001,7 +6074,7 @@ CONFIG_INFINIBAND_MTHCA_DEBUG=y CONFIG_INFINIBAND_QIB=m CONFIG_INFINIBAND_QIB_DCA=y CONFIG_INFINIBAND_CXGB4=m -# CONFIG_INFINIBAND_EFA is not set +CONFIG_INFINIBAND_EFA=m # CONFIG_INFINIBAND_I40IW is not set CONFIG_MLX4_INFINIBAND=m # CONFIG_INFINIBAND_OCRDMA is not set @@ -6169,7 +6242,7 @@ CONFIG_INTEL_MIC_X100_DMA=m CONFIG_DW_DMAC_CORE=y # CONFIG_DW_DMAC is not set # CONFIG_DW_DMAC_PCI is not set -# CONFIG_DW_EDMA is not set +CONFIG_DW_EDMA=m # CONFIG_DW_EDMA_PCIE is not set CONFIG_HSU_DMA=y # CONFIG_SF_PDMA is not set @@ -6187,6 +6260,7 @@ CONFIG_DMA_ENGINE_RAID=y CONFIG_SYNC_FILE=y # CONFIG_SW_SYNC is not set # CONFIG_UDMABUF is not set +# CONFIG_DMABUF_MOVE_NOTIFY is not set # CONFIG_DMABUF_SELFTESTS is not set # CONFIG_DMABUF_HEAPS is not set # end of DMABUF options @@ -6236,6 +6310,15 @@ CONFIG_VIRTIO_BALLOON=m CONFIG_VIRTIO_INPUT=m CONFIG_VIRTIO_MMIO=m # CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES is not set +# CONFIG_VDPA is not set +CONFIG_VHOST_IOTLB=m +CONFIG_VHOST_DPN=y +CONFIG_VHOST=m +CONFIG_VHOST_MENU=y +CONFIG_VHOST_NET=m +CONFIG_VHOST_SCSI=m +CONFIG_VHOST_VSOCK=m +# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set # # Microsoft Hyper-V guest support @@ -6305,6 +6388,7 @@ CONFIG_STAGING_MEDIA=y # # soc_camera sensor drivers # +CONFIG_VIDEO_USBVISION=m # # Android @@ -6320,13 +6404,7 @@ CONFIG_FWTTY_MAX_CARD_PORTS=32 # 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_MOST_COMPONENTS is not set CONFIG_KS7010=m CONFIG_GREYBUS_AUDIO=m CONFIG_GREYBUS_BOOTROM=m @@ -6353,45 +6431,44 @@ CONFIG_GREYBUS_USB=m # CONFIG_FIELDBUS_DEV is not set # CONFIG_KPC2000 is not set -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_QLGE=m -# CONFIG_NET_VENDOR_HP is not set # CONFIG_WFX is not set CONFIG_X86_PLATFORM_DEVICES=y -CONFIG_ACER_WMI=m -# CONFIG_ACER_WIRELESS is not set -CONFIG_ACERHDF=m +CONFIG_ACPI_WMI=m +CONFIG_WMI_BMOF=m CONFIG_ALIENWARE_WMI=m +# CONFIG_HUAWEI_WMI is not set +# CONFIG_INTEL_WMI_THUNDERBOLT is not set +CONFIG_MXM_WMI=m +# CONFIG_PEAQ_WMI is not set +# CONFIG_XIAOMI_WMI is not set +CONFIG_ACERHDF=m +# CONFIG_ACER_WIRELESS is not set +CONFIG_ACER_WMI=m +CONFIG_APPLE_GMUX=m CONFIG_ASUS_LAPTOP=m +# CONFIG_ASUS_WIRELESS is not set +CONFIG_ASUS_WMI=m +CONFIG_ASUS_NB_WMI=m +CONFIG_EEEPC_LAPTOP=m +CONFIG_EEEPC_WMI=m CONFIG_DCDBAS=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_DELL_RBU=m +CONFIG_DELL_SMO8800=m +CONFIG_DELL_WMI_AIO=m +# CONFIG_DELL_WMI_LED is not set +CONFIG_AMILO_RFKILL=m 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_LG_LAPTOP is not set -CONFIG_MSI_LAPTOP=m -CONFIG_PANASONIC_LAPTOP=m -CONFIG_COMPAL_LAPTOP=m -CONFIG_SONY_LAPTOP=m -CONFIG_SONYPI_COMPAT=y +# CONFIG_IBM_RTL is not set CONFIG_IDEAPAD_LAPTOP=m +CONFIG_SENSORS_HDAPS=m CONFIG_THINKPAD_ACPI=m CONFIG_THINKPAD_ACPI_ALSA_SUPPORT=y # CONFIG_THINKPAD_ACPI_DEBUGFACILITIES is not set @@ -6399,48 +6476,36 @@ CONFIG_THINKPAD_ACPI_ALSA_SUPPORT=y # 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_ATOMISP2_PM is not set +# CONFIG_INTEL_HID_EVENT is not set +# CONFIG_INTEL_INT0002_VGPIO is not set 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_XIAOMI_WMI is not set +CONFIG_INTEL_OAKTRAIL=m +CONFIG_INTEL_VBTN=m +# CONFIG_SURFACE_3_BUTTON is not set +# CONFIG_SURFACE_3_POWER_OPREGION is not set +CONFIG_SURFACE_PRO3_BUTTON=m +CONFIG_MSI_LAPTOP=m CONFIG_MSI_WMI=m -# CONFIG_PEAQ_WMI is not set -CONFIG_TOPSTAR_LAPTOP=m +# CONFIG_PCENGINES_APU2 is not set +CONFIG_SAMSUNG_LAPTOP=m +CONFIG_SAMSUNG_Q10=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_COMPAL_LAPTOP=m +# CONFIG_LG_LAPTOP is not set +CONFIG_PANASONIC_LAPTOP=m +CONFIG_SONY_LAPTOP=m +CONFIG_SONYPI_COMPAT=y +# CONFIG_SYSTEM76_ACPI is not set +CONFIG_TOPSTAR_LAPTOP=m +# CONFIG_I2C_MULTI_INSTANTIATE is not set +# CONFIG_MLX_PLATFORM is not set 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_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_HUAWEI_WMI is not set -# CONFIG_PCENGINES_APU2 is not set -# CONFIG_INTEL_UNCORE_FREQ_CONTROL is not set # # Intel Speed Select Technology interface support @@ -6448,7 +6513,11 @@ CONFIG_SURFACE_PRO3_BUTTON=m # CONFIG_INTEL_SPEED_SELECT_INTERFACE is not set # end of Intel Speed Select Technology interface support -# CONFIG_SYSTEM76_ACPI is not set +# CONFIG_INTEL_TURBO_MAX_3 is not set +# CONFIG_INTEL_UNCORE_FREQ_CONTROL is not set +# CONFIG_INTEL_PMC_CORE is not set +# CONFIG_INTEL_PMC_IPC is not set +# CONFIG_INTEL_PUNIT_IPC is not set CONFIG_PMC_ATOM=y CONFIG_MFD_CROS_EC=m CONFIG_CHROME_PLATFORMS=y @@ -6466,6 +6535,7 @@ CONFIG_CROS_EC_LIGHTBAR=m CONFIG_CROS_EC_DEBUGFS=m CONFIG_CROS_EC_SENSORHUB=m CONFIG_CROS_EC_SYSFS=m +CONFIG_CROS_USBPD_NOTIFY=m # CONFIG_WILCO_EC is not set # CONFIG_MELLANOX_PLATFORM is not set CONFIG_CLKDEV_LOOKUP=y @@ -6708,13 +6778,21 @@ CONFIG_FPGA=m # CONFIG_FPGA_MGR_ALTERA_CVP is not set # CONFIG_FPGA_BRIDGE is not set # CONFIG_FPGA_DFL is not set -# CONFIG_TEE is not set +CONFIG_TEE=m + +# +# TEE drivers +# +CONFIG_AMDTEE=m +# end of TEE drivers + CONFIG_PM_OPP=y # CONFIG_UNISYS_VISORBUS is not set # CONFIG_SIOX is not set # CONFIG_SLIMBUS is not set # CONFIG_INTERCONNECT is not set # CONFIG_COUNTER is not set +CONFIG_MOST=m # end of Device Drivers # @@ -6884,6 +6962,7 @@ CONFIG_PROC_SYSCTL=y CONFIG_PROC_PAGE_MONITOR=y # CONFIG_PROC_CHILDREN is not set CONFIG_PROC_PID_ARCH_STATUS=y +CONFIG_PROC_CPU_RESCTRL=y CONFIG_KERNFS=y CONFIG_SYSFS=y CONFIG_TMPFS=y @@ -7124,10 +7203,11 @@ CONFIG_INTEGRITY=y # CONFIG_INTEGRITY_SIGNATURE is not set CONFIG_INTEGRITY_AUDIT=y # CONFIG_IMA is not set +# CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT is not set # CONFIG_EVM is not set CONFIG_DEFAULT_SECURITY_APPARMOR=y # CONFIG_DEFAULT_SECURITY_DAC is not set -CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo" +CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo,bpf" # # Kernel hardening options @@ -7137,7 +7217,7 @@ CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tom # Memory initialization # CONFIG_INIT_STACK_NONE=y -CONFIG_INIT_ON_ALLOC_DEFAULT_ON=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 @@ -7194,7 +7274,7 @@ CONFIG_CRYPTO_ECC=m CONFIG_CRYPTO_ECDH=m # CONFIG_CRYPTO_ECRDSA is not set # CONFIG_CRYPTO_CURVE25519 is not set -# CONFIG_CRYPTO_CURVE25519_X86 is not set +CONFIG_CRYPTO_CURVE25519_X86=m # # Authenticated Encryption with Associated Data @@ -7243,7 +7323,7 @@ CONFIG_CRYPTO_CRC32_PCLMUL=m CONFIG_CRYPTO_XXHASH=m CONFIG_CRYPTO_BLAKE2B=m # CONFIG_CRYPTO_BLAKE2S is not set -# CONFIG_CRYPTO_BLAKE2S_X86 is not set +CONFIG_CRYPTO_BLAKE2S_X86=m CONFIG_CRYPTO_CRCT10DIF=y # CONFIG_CRYPTO_CRCT10DIF_PCLMUL is not set CONFIG_CRYPTO_GHASH=m @@ -7342,17 +7422,21 @@ CONFIG_CRYPTO_HASH_INFO=y # CONFIG_CRYPTO_LIB_AES=y CONFIG_CRYPTO_LIB_ARC4=m -# CONFIG_CRYPTO_LIB_BLAKE2S is not set +CONFIG_CRYPTO_ARCH_HAVE_LIB_BLAKE2S=m +CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=m +CONFIG_CRYPTO_LIB_BLAKE2S=m CONFIG_CRYPTO_ARCH_HAVE_LIB_CHACHA=m CONFIG_CRYPTO_LIB_CHACHA_GENERIC=m -# CONFIG_CRYPTO_LIB_CHACHA is not set -# CONFIG_CRYPTO_LIB_CURVE25519 is not set +CONFIG_CRYPTO_LIB_CHACHA=m +CONFIG_CRYPTO_ARCH_HAVE_LIB_CURVE25519=m +CONFIG_CRYPTO_LIB_CURVE25519_GENERIC=m +CONFIG_CRYPTO_LIB_CURVE25519=m CONFIG_CRYPTO_LIB_DES=m CONFIG_CRYPTO_LIB_POLY1305_RSIZE=11 CONFIG_CRYPTO_ARCH_HAVE_LIB_POLY1305=m CONFIG_CRYPTO_LIB_POLY1305_GENERIC=m -# CONFIG_CRYPTO_LIB_POLY1305 is not set -# CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set +CONFIG_CRYPTO_LIB_POLY1305=m +CONFIG_CRYPTO_LIB_CHACHA20POLY1305=m CONFIG_CRYPTO_LIB_SHA256=y CONFIG_CRYPTO_HW=y CONFIG_CRYPTO_DEV_PADLOCK=m @@ -7461,6 +7545,8 @@ 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 @@ -7535,7 +7621,6 @@ CONFIG_ENABLE_MUST_CHECK=y CONFIG_FRAME_WARN=2048 CONFIG_STRIP_ASM_SYMS=y # CONFIG_HEADERS_INSTALL is not set -CONFIG_OPTIMIZE_INLINING=y CONFIG_DEBUG_SECTION_MISMATCH=y CONFIG_SECTION_MISMATCH_WARN_ONLY=y CONFIG_STACK_VALIDATION=y @@ -7547,11 +7632,11 @@ CONFIG_STACK_VALIDATION=y CONFIG_MAGIC_SYSRQ=y CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 CONFIG_MAGIC_SYSRQ_SERIAL=y +CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE="" CONFIG_DEBUG_FS=y CONFIG_HAVE_ARCH_KGDB=y CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y # CONFIG_UBSAN is not set -CONFIG_UBSAN_ALIGNMENT=y # end of Generic Kernel Debugging Instruments # CONFIG_DEBUG_KERNEL is not set @@ -7580,6 +7665,7 @@ CONFIG_KASAN_STACK=1 CONFIG_PANIC_ON_OOPS_VALUE=0 CONFIG_PANIC_TIMEOUT=0 CONFIG_HARDLOCKUP_CHECK_TIMESTAMP=y +# CONFIG_TEST_LOCKUP is not set # end of Debug Oops, Lockups and Hangs # @@ -7709,6 +7795,7 @@ CONFIG_CC_HAS_SANCOV_TRACE_PC=y CONFIG_RUNTIME_TESTING_MENU=y # CONFIG_LKDTM is not set # CONFIG_TEST_LIST_SORT is not set +# CONFIG_TEST_MIN_HEAP is not set # CONFIG_TEST_SORT is not set # CONFIG_REED_SOLOMON_TEST is not set CONFIG_ATOMIC64_SELFTEST=y diff --git a/kernel/kernel/files/patches/linux/patch-5.7.13.xz b/kernel/kernel/files/patches/linux/patch-5.7.13.xz new file mode 100644 index 00000000..001389b1 Binary files /dev/null and b/kernel/kernel/files/patches/linux/patch-5.7.13.xz differ diff --git a/kernel/kernel/files/patches/mageia/fs-MAINTAINERS-add-exfat-filesystem.patch b/kernel/kernel/files/patches/mageia/fs-MAINTAINERS-add-exfat-filesystem.patch deleted file mode 100644 index 750af057..00000000 --- a/kernel/kernel/files/patches/mageia/fs-MAINTAINERS-add-exfat-filesystem.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 88ab55f16aae90e2e974eb67cc2380edb92b0661 Mon Sep 17 00:00:00 2001 -From: Namjae Jeon -Date: Mon, 2 Mar 2020 15:21:43 +0900 -Subject: [PATCH 12/14] MAINTAINERS: add exfat filesystem -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Add myself and Sungjong Seo as exfat maintainer. - -Signed-off-by: Namjae Jeon -Signed-off-by: Sungjong Seo -Reviewed-by: Pali Rohár -Reviewed-by: Christoph Hellwig -Signed-off-by: Al Viro ---- - MAINTAINERS | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/MAINTAINERS b/MAINTAINERS -index 38fe2f3f7b6f..27d912bc5ae2 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -6240,6 +6240,13 @@ F: include/trace/events/mdio.h - F: include/uapi/linux/mdio.h - F: include/uapi/linux/mii.h - -+EXFAT FILE SYSTEM -+M: Namjae Jeon -+M: Sungjong Seo -+L: linux-fsdevel@vger.kernel.org -+S: Maintained -+F: fs/exfat/ -+ - EXT2 FILE SYSTEM - M: Jan Kara - L: linux-ext4@vger.kernel.org --- -2.25.1 diff --git a/kernel/kernel/files/patches/mageia/fs-exfat-add-Kconfig-and-Makefile.patch b/kernel/kernel/files/patches/mageia/fs-exfat-add-Kconfig-and-Makefile.patch deleted file mode 100644 index 674116ff..00000000 --- a/kernel/kernel/files/patches/mageia/fs-exfat-add-Kconfig-and-Makefile.patch +++ /dev/null @@ -1,96 +0,0 @@ -From b9d1e2e6265f5dc25e9f5dbfbde3e53d8a4958ac Mon Sep 17 00:00:00 2001 -From: Namjae Jeon -Date: Mon, 2 Mar 2020 15:21:42 +0900 -Subject: [PATCH 11/14] exfat: add Kconfig and Makefile -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This adds the Kconfig and Makefile for exfat. - -Signed-off-by: Namjae Jeon -Signed-off-by: Sungjong Seo -Reviewed-by: Pali Rohár -Reviewed-by: Christoph Hellwig -Signed-off-by: Al Viro ---- - fs/Kconfig | 3 ++- - fs/Makefile | 1 + - fs/exfat/Kconfig | 21 +++++++++++++++++++++ - fs/exfat/Makefile | 8 ++++++++ - 4 files changed, 32 insertions(+), 1 deletion(-) - create mode 100644 fs/exfat/Kconfig - create mode 100644 fs/exfat/Makefile - -diff --git a/fs/Kconfig b/fs/Kconfig -index 708ba336e689..f08fbbfafd9a 100644 ---- a/fs/Kconfig -+++ b/fs/Kconfig -@@ -140,9 +140,10 @@ endmenu - endif # BLOCK - - if BLOCK --menu "DOS/FAT/NT Filesystems" -+menu "DOS/FAT/EXFAT/NT Filesystems" - - source "fs/fat/Kconfig" -+source "fs/exfat/Kconfig" - source "fs/ntfs/Kconfig" - - endmenu -diff --git a/fs/Makefile b/fs/Makefile -index 505e51166973..2ce5112b02c8 100644 ---- a/fs/Makefile -+++ b/fs/Makefile -@@ -83,6 +83,7 @@ obj-$(CONFIG_HUGETLBFS) += hugetlbfs/ - obj-$(CONFIG_CODA_FS) += coda/ - obj-$(CONFIG_MINIX_FS) += minix/ - obj-$(CONFIG_FAT_FS) += fat/ -+obj-$(CONFIG_EXFAT_FS) += exfat/ - obj-$(CONFIG_BFS_FS) += bfs/ - obj-$(CONFIG_ISO9660_FS) += isofs/ - obj-$(CONFIG_HFSPLUS_FS) += hfsplus/ # Before hfs to find wrapped HFS+ -diff --git a/fs/exfat/Kconfig b/fs/exfat/Kconfig -new file mode 100644 -index 000000000000..2d3636dc5b8c ---- /dev/null -+++ b/fs/exfat/Kconfig -@@ -0,0 +1,21 @@ -+# SPDX-License-Identifier: GPL-2.0-or-later -+ -+config EXFAT_FS -+ tristate "exFAT filesystem support" -+ select NLS -+ help -+ This allows you to mount devices formatted with the exFAT file system. -+ exFAT is typically used on SD-Cards or USB sticks. -+ -+ To compile this as a module, choose M here: the module will be called -+ exfat. -+ -+config EXFAT_DEFAULT_IOCHARSET -+ string "Default iocharset for exFAT" -+ default "utf8" -+ depends on EXFAT_FS -+ help -+ Set this to the default input/output character set to use for -+ converting between the encoding is used for user visible filename and -+ UTF-16 character that exfat filesystem use, and can be overridden with -+ the "iocharset" mount option for exFAT filesystems. -diff --git a/fs/exfat/Makefile b/fs/exfat/Makefile -new file mode 100644 -index 000000000000..ed51926a4971 ---- /dev/null -+++ b/fs/exfat/Makefile -@@ -0,0 +1,8 @@ -+# SPDX-License-Identifier: GPL-2.0-or-later -+# -+# Makefile for the linux exFAT filesystem support. -+# -+obj-$(CONFIG_EXFAT_FS) += exfat.o -+ -+exfat-y := inode.o namei.o dir.o super.o fatent.o cache.o nls.o misc.o \ -+ file.o balloc.o --- -2.25.1 - diff --git a/kernel/kernel/files/patches/mageia/fs-exfat-add-bitmap-operations.patch b/kernel/kernel/files/patches/mageia/fs-exfat-add-bitmap-operations.patch deleted file mode 100644 index 5505b308..00000000 --- a/kernel/kernel/files/patches/mageia/fs-exfat-add-bitmap-operations.patch +++ /dev/null @@ -1,309 +0,0 @@ -From 1e49a94cf707204b66a3fb242f2814712c941f52 Mon Sep 17 00:00:00 2001 -From: Namjae Jeon -Date: Mon, 2 Mar 2020 15:21:38 +0900 -Subject: [PATCH 07/14] exfat: add bitmap operations -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This adds the implementation of bitmap operations for exfat. - -Signed-off-by: Namjae Jeon -Signed-off-by: Sungjong Seo -Reviewed-by: Pali Rohár -Reviewed-by: Christoph Hellwig -Signed-off-by: Al Viro ---- - fs/exfat/balloc.c | 280 ++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 280 insertions(+) - create mode 100644 fs/exfat/balloc.c - -diff --git a/fs/exfat/balloc.c b/fs/exfat/balloc.c -new file mode 100644 -index 000000000000..6a04cc02565a ---- /dev/null -+++ b/fs/exfat/balloc.c -@@ -0,0 +1,280 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -+ */ -+ -+#include -+#include -+#include -+ -+#include "exfat_raw.h" -+#include "exfat_fs.h" -+ -+static const unsigned char free_bit[] = { -+ 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2,/* 0 ~ 19*/ -+ 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3,/* 20 ~ 39*/ -+ 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,/* 40 ~ 59*/ -+ 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,/* 60 ~ 79*/ -+ 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2,/* 80 ~ 99*/ -+ 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3,/*100 ~ 119*/ -+ 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,/*120 ~ 139*/ -+ 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5,/*140 ~ 159*/ -+ 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2,/*160 ~ 179*/ -+ 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3,/*180 ~ 199*/ -+ 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,/*200 ~ 219*/ -+ 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,/*220 ~ 239*/ -+ 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 /*240 ~ 254*/ -+}; -+ -+static const unsigned char used_bit[] = { -+ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3,/* 0 ~ 19*/ -+ 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4,/* 20 ~ 39*/ -+ 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5,/* 40 ~ 59*/ -+ 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,/* 60 ~ 79*/ -+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4,/* 80 ~ 99*/ -+ 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6,/*100 ~ 119*/ -+ 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4,/*120 ~ 139*/ -+ 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,/*140 ~ 159*/ -+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5,/*160 ~ 179*/ -+ 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5,/*180 ~ 199*/ -+ 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6,/*200 ~ 219*/ -+ 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,/*220 ~ 239*/ -+ 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 /*240 ~ 255*/ -+}; -+ -+/* -+ * Allocation Bitmap Management Functions -+ */ -+static int exfat_allocate_bitmap(struct super_block *sb, -+ struct exfat_dentry *ep) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ long long map_size; -+ unsigned int i, need_map_size; -+ sector_t sector; -+ -+ sbi->map_clu = le32_to_cpu(ep->dentry.bitmap.start_clu); -+ map_size = le64_to_cpu(ep->dentry.bitmap.size); -+ need_map_size = ((EXFAT_DATA_CLUSTER_COUNT(sbi) - 1) / BITS_PER_BYTE) -+ + 1; -+ if (need_map_size != map_size) { -+ exfat_msg(sb, KERN_ERR, -+ "bogus allocation bitmap size(need : %u, cur : %lld)", -+ need_map_size, map_size); -+ /* -+ * Only allowed when bogus allocation -+ * bitmap size is large -+ */ -+ if (need_map_size > map_size) -+ return -EIO; -+ } -+ sbi->map_sectors = ((need_map_size - 1) >> -+ (sb->s_blocksize_bits)) + 1; -+ sbi->vol_amap = kmalloc_array(sbi->map_sectors, -+ sizeof(struct buffer_head *), GFP_KERNEL); -+ if (!sbi->vol_amap) -+ return -ENOMEM; -+ -+ sector = exfat_cluster_to_sector(sbi, sbi->map_clu); -+ for (i = 0; i < sbi->map_sectors; i++) { -+ sbi->vol_amap[i] = sb_bread(sb, sector + i); -+ if (!sbi->vol_amap[i]) { -+ /* release all buffers and free vol_amap */ -+ int j = 0; -+ -+ while (j < i) -+ brelse(sbi->vol_amap[j++]); -+ -+ kfree(sbi->vol_amap); -+ sbi->vol_amap = NULL; -+ return -EIO; -+ } -+ } -+ -+ sbi->pbr_bh = NULL; -+ return 0; -+} -+ -+int exfat_load_bitmap(struct super_block *sb) -+{ -+ unsigned int i, type; -+ struct exfat_chain clu; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ -+ exfat_chain_set(&clu, sbi->root_dir, 0, ALLOC_FAT_CHAIN); -+ while (clu.dir != EXFAT_EOF_CLUSTER) { -+ for (i = 0; i < sbi->dentries_per_clu; i++) { -+ struct exfat_dentry *ep; -+ struct buffer_head *bh; -+ -+ ep = exfat_get_dentry(sb, &clu, i, &bh, NULL); -+ if (!ep) -+ return -EIO; -+ -+ type = exfat_get_entry_type(ep); -+ if (type == TYPE_UNUSED) -+ break; -+ if (type != TYPE_BITMAP) -+ continue; -+ if (ep->dentry.bitmap.flags == 0x0) { -+ int err; -+ -+ err = exfat_allocate_bitmap(sb, ep); -+ brelse(bh); -+ return err; -+ } -+ brelse(bh); -+ } -+ -+ if (exfat_get_next_cluster(sb, &clu.dir)) -+ return -EIO; -+ } -+ -+ return -EINVAL; -+} -+ -+void exfat_free_bitmap(struct exfat_sb_info *sbi) -+{ -+ int i; -+ -+ brelse(sbi->pbr_bh); -+ -+ for (i = 0; i < sbi->map_sectors; i++) -+ __brelse(sbi->vol_amap[i]); -+ -+ kfree(sbi->vol_amap); -+} -+ -+/* -+ * If the value of "clu" is 0, it means cluster 2 which is the first cluster of -+ * the cluster heap. -+ */ -+int exfat_set_bitmap(struct inode *inode, unsigned int clu) -+{ -+ int i, b; -+ unsigned int ent_idx; -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ -+ WARN_ON(clu < EXFAT_FIRST_CLUSTER); -+ ent_idx = CLUSTER_TO_BITMAP_ENT(clu); -+ i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx); -+ b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx); -+ -+ set_bit_le(b, sbi->vol_amap[i]->b_data); -+ exfat_update_bh(sb, sbi->vol_amap[i], IS_DIRSYNC(inode)); -+ return 0; -+} -+ -+/* -+ * If the value of "clu" is 0, it means cluster 2 which is the first cluster of -+ * the cluster heap. -+ */ -+void exfat_clear_bitmap(struct inode *inode, unsigned int clu) -+{ -+ int i, b; -+ unsigned int ent_idx; -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct exfat_mount_options *opts = &sbi->options; -+ -+ WARN_ON(clu < EXFAT_FIRST_CLUSTER); -+ ent_idx = CLUSTER_TO_BITMAP_ENT(clu); -+ i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx); -+ b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx); -+ -+ clear_bit_le(b, sbi->vol_amap[i]->b_data); -+ exfat_update_bh(sb, sbi->vol_amap[i], IS_DIRSYNC(inode)); -+ -+ if (opts->discard) { -+ int ret_discard; -+ -+ ret_discard = sb_issue_discard(sb, -+ exfat_cluster_to_sector(sbi, clu + -+ EXFAT_RESERVED_CLUSTERS), -+ (1 << sbi->sect_per_clus_bits), GFP_NOFS, 0); -+ -+ if (ret_discard == -EOPNOTSUPP) { -+ exfat_msg(sb, KERN_ERR, -+ "discard not supported by device, disabling"); -+ opts->discard = 0; -+ } -+ } -+} -+ -+/* -+ * If the value of "clu" is 0, it means cluster 2 which is the first cluster of -+ * the cluster heap. -+ */ -+unsigned int exfat_find_free_bitmap(struct super_block *sb, unsigned int clu) -+{ -+ unsigned int i, map_i, map_b, ent_idx; -+ unsigned int clu_base, clu_free; -+ unsigned char k, clu_mask; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ -+ WARN_ON(clu < EXFAT_FIRST_CLUSTER); -+ ent_idx = CLUSTER_TO_BITMAP_ENT(clu); -+ clu_base = BITMAP_ENT_TO_CLUSTER(ent_idx & ~(BITS_PER_BYTE_MASK)); -+ clu_mask = IGNORED_BITS_REMAINED(clu, clu_base); -+ -+ map_i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx); -+ map_b = BITMAP_OFFSET_BYTE_IN_SECTOR(sb, ent_idx); -+ -+ for (i = EXFAT_FIRST_CLUSTER; i < sbi->num_clusters; -+ i += BITS_PER_BYTE) { -+ k = *(sbi->vol_amap[map_i]->b_data + map_b); -+ if (clu_mask > 0) { -+ k |= clu_mask; -+ clu_mask = 0; -+ } -+ if (k < 0xFF) { -+ clu_free = clu_base + free_bit[k]; -+ if (clu_free < sbi->num_clusters) -+ return clu_free; -+ } -+ clu_base += BITS_PER_BYTE; -+ -+ if (++map_b >= sb->s_blocksize || -+ clu_base >= sbi->num_clusters) { -+ if (++map_i >= sbi->map_sectors) { -+ clu_base = EXFAT_FIRST_CLUSTER; -+ map_i = 0; -+ } -+ map_b = 0; -+ } -+ } -+ -+ return EXFAT_EOF_CLUSTER; -+} -+ -+int exfat_count_used_clusters(struct super_block *sb, unsigned int *ret_count) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ unsigned int count = 0; -+ unsigned int i, map_i = 0, map_b = 0; -+ unsigned int total_clus = EXFAT_DATA_CLUSTER_COUNT(sbi); -+ unsigned int last_mask = total_clus & BITS_PER_BYTE_MASK; -+ unsigned char clu_bits; -+ const unsigned char last_bit_mask[] = {0, 0b00000001, 0b00000011, -+ 0b00000111, 0b00001111, 0b00011111, 0b00111111, 0b01111111}; -+ -+ total_clus &= ~last_mask; -+ for (i = 0; i < total_clus; i += BITS_PER_BYTE) { -+ clu_bits = *(sbi->vol_amap[map_i]->b_data + map_b); -+ count += used_bit[clu_bits]; -+ if (++map_b >= (unsigned int)sb->s_blocksize) { -+ map_i++; -+ map_b = 0; -+ } -+ } -+ -+ if (last_mask) { -+ clu_bits = *(sbi->vol_amap[map_i]->b_data + map_b); -+ clu_bits &= last_bit_mask[last_mask]; -+ count += used_bit[clu_bits]; -+ } -+ -+ *ret_count = count; -+ return 0; -+} --- -2.25.1 - diff --git a/kernel/kernel/files/patches/mageia/fs-exfat-add-directory-operations.patch b/kernel/kernel/files/patches/mageia/fs-exfat-add-directory-operations.patch deleted file mode 100644 index 857c1dbb..00000000 --- a/kernel/kernel/files/patches/mageia/fs-exfat-add-directory-operations.patch +++ /dev/null @@ -1,1267 +0,0 @@ -From ca06197382bde0a3bc20215595d1c9ce20c6e341 Mon Sep 17 00:00:00 2001 -From: Namjae Jeon -Date: Mon, 2 Mar 2020 15:21:35 +0900 -Subject: [PATCH 04/14] exfat: add directory operations -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This adds the implementation of directory operations for exfat. - -Signed-off-by: Namjae Jeon -Signed-off-by: Sungjong Seo -Reviewed-by: Pali Rohár -Reviewed-by: Christoph Hellwig -Signed-off-by: Al Viro ---- - fs/exfat/dir.c | 1238 ++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 1238 insertions(+) - create mode 100644 fs/exfat/dir.c - -diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c -new file mode 100644 -index 000000000000..4b91afb0f051 ---- /dev/null -+++ b/fs/exfat/dir.c -@@ -0,0 +1,1238 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -+ */ -+ -+#include -+#include -+#include -+ -+#include "exfat_raw.h" -+#include "exfat_fs.h" -+ -+static int exfat_extract_uni_name(struct exfat_dentry *ep, -+ unsigned short *uniname) -+{ -+ int i, len = 0; -+ -+ for (i = 0; i < EXFAT_FILE_NAME_LEN; i++) { -+ *uniname = le16_to_cpu(ep->dentry.name.unicode_0_14[i]); -+ if (*uniname == 0x0) -+ return len; -+ uniname++; -+ len++; -+ } -+ -+ *uniname = 0x0; -+ return len; -+ -+} -+ -+static void exfat_get_uniname_from_ext_entry(struct super_block *sb, -+ struct exfat_chain *p_dir, int entry, unsigned short *uniname) -+{ -+ int i; -+ struct exfat_dentry *ep; -+ struct exfat_entry_set_cache *es; -+ -+ es = exfat_get_dentry_set(sb, p_dir, entry, ES_ALL_ENTRIES, &ep); -+ if (!es) -+ return; -+ -+ if (es->num_entries < 3) -+ goto free_es; -+ -+ ep += 2; -+ -+ /* -+ * First entry : file entry -+ * Second entry : stream-extension entry -+ * Third entry : first file-name entry -+ * So, the index of first file-name dentry should start from 2. -+ */ -+ for (i = 2; i < es->num_entries; i++, ep++) { -+ /* end of name entry */ -+ if (exfat_get_entry_type(ep) != TYPE_EXTEND) -+ goto free_es; -+ -+ exfat_extract_uni_name(ep, uniname); -+ uniname += EXFAT_FILE_NAME_LEN; -+ } -+ -+free_es: -+ kfree(es); -+} -+ -+/* read a directory entry from the opened directory */ -+static int exfat_readdir(struct inode *inode, struct exfat_dir_entry *dir_entry) -+{ -+ int i, dentries_per_clu, dentries_per_clu_bits = 0; -+ unsigned int type, clu_offset; -+ sector_t sector; -+ struct exfat_chain dir, clu; -+ struct exfat_uni_name uni_name; -+ struct exfat_dentry *ep; -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ unsigned int dentry = ei->rwoffset & 0xFFFFFFFF; -+ struct buffer_head *bh; -+ -+ /* check if the given file ID is opened */ -+ if (ei->type != TYPE_DIR) -+ return -EPERM; -+ -+ if (ei->entry == -1) -+ exfat_chain_set(&dir, sbi->root_dir, 0, ALLOC_FAT_CHAIN); -+ else -+ exfat_chain_set(&dir, ei->start_clu, -+ EXFAT_B_TO_CLU(i_size_read(inode), sbi), ei->flags); -+ -+ dentries_per_clu = sbi->dentries_per_clu; -+ dentries_per_clu_bits = ilog2(dentries_per_clu); -+ -+ clu_offset = dentry >> dentries_per_clu_bits; -+ exfat_chain_dup(&clu, &dir); -+ -+ if (clu.flags == ALLOC_NO_FAT_CHAIN) { -+ clu.dir += clu_offset; -+ clu.size -= clu_offset; -+ } else { -+ /* hint_information */ -+ if (clu_offset > 0 && ei->hint_bmap.off != EXFAT_EOF_CLUSTER && -+ ei->hint_bmap.off > 0 && clu_offset >= ei->hint_bmap.off) { -+ clu_offset -= ei->hint_bmap.off; -+ clu.dir = ei->hint_bmap.clu; -+ } -+ -+ while (clu_offset > 0) { -+ if (exfat_get_next_cluster(sb, &(clu.dir))) -+ return -EIO; -+ -+ clu_offset--; -+ } -+ } -+ -+ while (clu.dir != EXFAT_EOF_CLUSTER) { -+ i = dentry & (dentries_per_clu - 1); -+ -+ for ( ; i < dentries_per_clu; i++, dentry++) { -+ ep = exfat_get_dentry(sb, &clu, i, &bh, §or); -+ if (!ep) -+ return -EIO; -+ -+ type = exfat_get_entry_type(ep); -+ if (type == TYPE_UNUSED) { -+ brelse(bh); -+ break; -+ } -+ -+ if (type != TYPE_FILE && type != TYPE_DIR) { -+ brelse(bh); -+ continue; -+ } -+ -+ dir_entry->attr = le16_to_cpu(ep->dentry.file.attr); -+ exfat_get_entry_time(sbi, &dir_entry->crtime, -+ ep->dentry.file.create_tz, -+ ep->dentry.file.create_time, -+ ep->dentry.file.create_date, -+ ep->dentry.file.create_time_ms); -+ exfat_get_entry_time(sbi, &dir_entry->mtime, -+ ep->dentry.file.modify_tz, -+ ep->dentry.file.modify_time, -+ ep->dentry.file.modify_date, -+ ep->dentry.file.modify_time_ms); -+ exfat_get_entry_time(sbi, &dir_entry->atime, -+ ep->dentry.file.access_tz, -+ ep->dentry.file.access_time, -+ ep->dentry.file.access_date, -+ 0); -+ -+ *uni_name.name = 0x0; -+ exfat_get_uniname_from_ext_entry(sb, &dir, dentry, -+ uni_name.name); -+ exfat_utf16_to_nls(sb, &uni_name, -+ dir_entry->namebuf.lfn, -+ dir_entry->namebuf.lfnbuf_len); -+ brelse(bh); -+ -+ ep = exfat_get_dentry(sb, &clu, i + 1, &bh, NULL); -+ if (!ep) -+ return -EIO; -+ dir_entry->size = -+ le64_to_cpu(ep->dentry.stream.valid_size); -+ brelse(bh); -+ -+ ei->hint_bmap.off = dentry >> dentries_per_clu_bits; -+ ei->hint_bmap.clu = clu.dir; -+ -+ ei->rwoffset = ++dentry; -+ return 0; -+ } -+ -+ if (clu.flags == ALLOC_NO_FAT_CHAIN) { -+ if (--clu.size > 0) -+ clu.dir++; -+ else -+ clu.dir = EXFAT_EOF_CLUSTER; -+ } else { -+ if (exfat_get_next_cluster(sb, &(clu.dir))) -+ return -EIO; -+ } -+ } -+ -+ dir_entry->namebuf.lfn[0] = '\0'; -+ ei->rwoffset = dentry; -+ return 0; -+} -+ -+static void exfat_init_namebuf(struct exfat_dentry_namebuf *nb) -+{ -+ nb->lfn = NULL; -+ nb->lfnbuf_len = 0; -+} -+ -+static int exfat_alloc_namebuf(struct exfat_dentry_namebuf *nb) -+{ -+ nb->lfn = __getname(); -+ if (!nb->lfn) -+ return -ENOMEM; -+ nb->lfnbuf_len = MAX_VFSNAME_BUF_SIZE; -+ return 0; -+} -+ -+static void exfat_free_namebuf(struct exfat_dentry_namebuf *nb) -+{ -+ if (!nb->lfn) -+ return; -+ -+ __putname(nb->lfn); -+ exfat_init_namebuf(nb); -+} -+ -+/* skip iterating emit_dots when dir is empty */ -+#define ITER_POS_FILLED_DOTS (2) -+static int exfat_iterate(struct file *filp, struct dir_context *ctx) -+{ -+ struct inode *inode = filp->f_path.dentry->d_inode; -+ struct super_block *sb = inode->i_sb; -+ struct inode *tmp; -+ struct exfat_dir_entry de; -+ struct exfat_dentry_namebuf *nb = &(de.namebuf); -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ unsigned long inum; -+ loff_t cpos, i_pos; -+ int err = 0, fake_offset = 0; -+ -+ exfat_init_namebuf(nb); -+ mutex_lock(&EXFAT_SB(sb)->s_lock); -+ -+ cpos = ctx->pos; -+ if (!dir_emit_dots(filp, ctx)) -+ goto unlock; -+ -+ if (ctx->pos == ITER_POS_FILLED_DOTS) { -+ cpos = 0; -+ fake_offset = 1; -+ } -+ -+ if (cpos & (DENTRY_SIZE - 1)) { -+ err = -ENOENT; -+ goto unlock; -+ } -+ -+ /* name buffer should be allocated before use */ -+ err = exfat_alloc_namebuf(nb); -+ if (err) -+ goto unlock; -+get_new: -+ ei->rwoffset = EXFAT_B_TO_DEN(cpos); -+ -+ if (cpos >= i_size_read(inode)) -+ goto end_of_dir; -+ -+ err = exfat_readdir(inode, &de); -+ if (err) { -+ /* -+ * At least we tried to read a sector. Move cpos to next sector -+ * position (should be aligned). -+ */ -+ if (err == -EIO) { -+ cpos += 1 << (sb->s_blocksize_bits); -+ cpos &= ~(sb->s_blocksize - 1); -+ } -+ -+ err = -EIO; -+ goto end_of_dir; -+ } -+ -+ cpos = EXFAT_DEN_TO_B(ei->rwoffset); -+ -+ if (!nb->lfn[0]) -+ goto end_of_dir; -+ -+ i_pos = ((loff_t)ei->start_clu << 32) | -+ ((ei->rwoffset - 1) & 0xffffffff); -+ tmp = exfat_iget(sb, i_pos); -+ if (tmp) { -+ inum = tmp->i_ino; -+ iput(tmp); -+ } else { -+ inum = iunique(sb, EXFAT_ROOT_INO); -+ } -+ -+ /* -+ * Before calling dir_emit(), sb_lock should be released. -+ * Because page fault can occur in dir_emit() when the size -+ * of buffer given from user is larger than one page size. -+ */ -+ mutex_unlock(&EXFAT_SB(sb)->s_lock); -+ if (!dir_emit(ctx, nb->lfn, strlen(nb->lfn), inum, -+ (de.attr & ATTR_SUBDIR) ? DT_DIR : DT_REG)) -+ goto out_unlocked; -+ mutex_lock(&EXFAT_SB(sb)->s_lock); -+ ctx->pos = cpos; -+ goto get_new; -+ -+end_of_dir: -+ if (!cpos && fake_offset) -+ cpos = ITER_POS_FILLED_DOTS; -+ ctx->pos = cpos; -+unlock: -+ mutex_unlock(&EXFAT_SB(sb)->s_lock); -+out_unlocked: -+ /* -+ * To improve performance, free namebuf after unlock sb_lock. -+ * If namebuf is not allocated, this function do nothing -+ */ -+ exfat_free_namebuf(nb); -+ return err; -+} -+ -+const struct file_operations exfat_dir_operations = { -+ .llseek = generic_file_llseek, -+ .read = generic_read_dir, -+ .iterate = exfat_iterate, -+ .fsync = generic_file_fsync, -+}; -+ -+int exfat_alloc_new_dir(struct inode *inode, struct exfat_chain *clu) -+{ -+ int ret; -+ -+ exfat_chain_set(clu, EXFAT_EOF_CLUSTER, 0, ALLOC_NO_FAT_CHAIN); -+ -+ ret = exfat_alloc_cluster(inode, 1, clu); -+ if (ret) -+ return ret; -+ -+ return exfat_zeroed_cluster(inode, clu->dir); -+} -+ -+int exfat_calc_num_entries(struct exfat_uni_name *p_uniname) -+{ -+ int len; -+ -+ len = p_uniname->name_len; -+ if (len == 0) -+ return -EINVAL; -+ -+ /* 1 file entry + 1 stream entry + name entries */ -+ return ((len - 1) / EXFAT_FILE_NAME_LEN + 3); -+} -+ -+unsigned int exfat_get_entry_type(struct exfat_dentry *ep) -+{ -+ if (ep->type == EXFAT_UNUSED) -+ return TYPE_UNUSED; -+ if (IS_EXFAT_DELETED(ep->type)) -+ return TYPE_DELETED; -+ if (ep->type == EXFAT_INVAL) -+ return TYPE_INVALID; -+ if (IS_EXFAT_CRITICAL_PRI(ep->type)) { -+ if (ep->type == EXFAT_BITMAP) -+ return TYPE_BITMAP; -+ if (ep->type == EXFAT_UPCASE) -+ return TYPE_UPCASE; -+ if (ep->type == EXFAT_VOLUME) -+ return TYPE_VOLUME; -+ if (ep->type == EXFAT_FILE) { -+ if (le16_to_cpu(ep->dentry.file.attr) & ATTR_SUBDIR) -+ return TYPE_DIR; -+ return TYPE_FILE; -+ } -+ return TYPE_CRITICAL_PRI; -+ } -+ if (IS_EXFAT_BENIGN_PRI(ep->type)) { -+ if (ep->type == EXFAT_GUID) -+ return TYPE_GUID; -+ if (ep->type == EXFAT_PADDING) -+ return TYPE_PADDING; -+ if (ep->type == EXFAT_ACLTAB) -+ return TYPE_ACLTAB; -+ return TYPE_BENIGN_PRI; -+ } -+ if (IS_EXFAT_CRITICAL_SEC(ep->type)) { -+ if (ep->type == EXFAT_STREAM) -+ return TYPE_STREAM; -+ if (ep->type == EXFAT_NAME) -+ return TYPE_EXTEND; -+ if (ep->type == EXFAT_ACL) -+ return TYPE_ACL; -+ return TYPE_CRITICAL_SEC; -+ } -+ return TYPE_BENIGN_SEC; -+} -+ -+static void exfat_set_entry_type(struct exfat_dentry *ep, unsigned int type) -+{ -+ if (type == TYPE_UNUSED) { -+ ep->type = EXFAT_UNUSED; -+ } else if (type == TYPE_DELETED) { -+ ep->type &= EXFAT_DELETE; -+ } else if (type == TYPE_STREAM) { -+ ep->type = EXFAT_STREAM; -+ } else if (type == TYPE_EXTEND) { -+ ep->type = EXFAT_NAME; -+ } else if (type == TYPE_BITMAP) { -+ ep->type = EXFAT_BITMAP; -+ } else if (type == TYPE_UPCASE) { -+ ep->type = EXFAT_UPCASE; -+ } else if (type == TYPE_VOLUME) { -+ ep->type = EXFAT_VOLUME; -+ } else if (type == TYPE_DIR) { -+ ep->type = EXFAT_FILE; -+ ep->dentry.file.attr = cpu_to_le16(ATTR_SUBDIR); -+ } else if (type == TYPE_FILE) { -+ ep->type = EXFAT_FILE; -+ ep->dentry.file.attr = cpu_to_le16(ATTR_ARCHIVE); -+ } -+} -+ -+static void exfat_init_stream_entry(struct exfat_dentry *ep, -+ unsigned char flags, unsigned int start_clu, -+ unsigned long long size) -+{ -+ exfat_set_entry_type(ep, TYPE_STREAM); -+ ep->dentry.stream.flags = flags; -+ ep->dentry.stream.start_clu = cpu_to_le32(start_clu); -+ ep->dentry.stream.valid_size = cpu_to_le64(size); -+ ep->dentry.stream.size = cpu_to_le64(size); -+} -+ -+static void exfat_init_name_entry(struct exfat_dentry *ep, -+ unsigned short *uniname) -+{ -+ int i; -+ -+ exfat_set_entry_type(ep, TYPE_EXTEND); -+ ep->dentry.name.flags = 0x0; -+ -+ for (i = 0; i < EXFAT_FILE_NAME_LEN; i++) { -+ ep->dentry.name.unicode_0_14[i] = cpu_to_le16(*uniname); -+ if (*uniname == 0x0) -+ break; -+ uniname++; -+ } -+} -+ -+int exfat_init_dir_entry(struct inode *inode, struct exfat_chain *p_dir, -+ int entry, unsigned int type, unsigned int start_clu, -+ unsigned long long size) -+{ -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct timespec64 ts = current_time(inode); -+ sector_t sector; -+ struct exfat_dentry *ep; -+ struct buffer_head *bh; -+ -+ /* -+ * We cannot use exfat_get_dentry_set here because file ep is not -+ * initialized yet. -+ */ -+ ep = exfat_get_dentry(sb, p_dir, entry, &bh, §or); -+ if (!ep) -+ return -EIO; -+ -+ exfat_set_entry_type(ep, type); -+ exfat_set_entry_time(sbi, &ts, -+ &ep->dentry.file.create_tz, -+ &ep->dentry.file.create_time, -+ &ep->dentry.file.create_date, -+ &ep->dentry.file.create_time_ms); -+ exfat_set_entry_time(sbi, &ts, -+ &ep->dentry.file.modify_tz, -+ &ep->dentry.file.modify_time, -+ &ep->dentry.file.modify_date, -+ &ep->dentry.file.modify_time_ms); -+ exfat_set_entry_time(sbi, &ts, -+ &ep->dentry.file.access_tz, -+ &ep->dentry.file.access_time, -+ &ep->dentry.file.access_date, -+ NULL); -+ -+ exfat_update_bh(sb, bh, IS_DIRSYNC(inode)); -+ brelse(bh); -+ -+ ep = exfat_get_dentry(sb, p_dir, entry + 1, &bh, §or); -+ if (!ep) -+ return -EIO; -+ -+ exfat_init_stream_entry(ep, -+ (type == TYPE_FILE) ? ALLOC_FAT_CHAIN : ALLOC_NO_FAT_CHAIN, -+ start_clu, size); -+ exfat_update_bh(sb, bh, IS_DIRSYNC(inode)); -+ brelse(bh); -+ -+ return 0; -+} -+ -+int exfat_update_dir_chksum(struct inode *inode, struct exfat_chain *p_dir, -+ int entry) -+{ -+ struct super_block *sb = inode->i_sb; -+ int ret = 0; -+ int i, num_entries; -+ sector_t sector; -+ unsigned short chksum; -+ struct exfat_dentry *ep, *fep; -+ struct buffer_head *fbh, *bh; -+ -+ fep = exfat_get_dentry(sb, p_dir, entry, &fbh, §or); -+ if (!fep) -+ return -EIO; -+ -+ num_entries = fep->dentry.file.num_ext + 1; -+ chksum = exfat_calc_chksum_2byte(fep, DENTRY_SIZE, 0, CS_DIR_ENTRY); -+ -+ for (i = 1; i < num_entries; i++) { -+ ep = exfat_get_dentry(sb, p_dir, entry + i, &bh, NULL); -+ if (!ep) { -+ ret = -EIO; -+ goto release_fbh; -+ } -+ chksum = exfat_calc_chksum_2byte(ep, DENTRY_SIZE, chksum, -+ CS_DEFAULT); -+ brelse(bh); -+ } -+ -+ fep->dentry.file.checksum = cpu_to_le16(chksum); -+ exfat_update_bh(sb, fbh, IS_DIRSYNC(inode)); -+release_fbh: -+ brelse(fbh); -+ return ret; -+} -+ -+int exfat_init_ext_entry(struct inode *inode, struct exfat_chain *p_dir, -+ int entry, int num_entries, struct exfat_uni_name *p_uniname) -+{ -+ struct super_block *sb = inode->i_sb; -+ int i; -+ sector_t sector; -+ unsigned short *uniname = p_uniname->name; -+ struct exfat_dentry *ep; -+ struct buffer_head *bh; -+ int sync = IS_DIRSYNC(inode); -+ -+ ep = exfat_get_dentry(sb, p_dir, entry, &bh, §or); -+ if (!ep) -+ return -EIO; -+ -+ ep->dentry.file.num_ext = (unsigned char)(num_entries - 1); -+ exfat_update_bh(sb, bh, sync); -+ brelse(bh); -+ -+ ep = exfat_get_dentry(sb, p_dir, entry + 1, &bh, §or); -+ if (!ep) -+ return -EIO; -+ -+ ep->dentry.stream.name_len = p_uniname->name_len; -+ ep->dentry.stream.name_hash = cpu_to_le16(p_uniname->name_hash); -+ exfat_update_bh(sb, bh, sync); -+ brelse(bh); -+ -+ for (i = EXFAT_FIRST_CLUSTER; i < num_entries; i++) { -+ ep = exfat_get_dentry(sb, p_dir, entry + i, &bh, §or); -+ if (!ep) -+ return -EIO; -+ -+ exfat_init_name_entry(ep, uniname); -+ exfat_update_bh(sb, bh, sync); -+ brelse(bh); -+ uniname += EXFAT_FILE_NAME_LEN; -+ } -+ -+ exfat_update_dir_chksum(inode, p_dir, entry); -+ return 0; -+} -+ -+int exfat_remove_entries(struct inode *inode, struct exfat_chain *p_dir, -+ int entry, int order, int num_entries) -+{ -+ struct super_block *sb = inode->i_sb; -+ int i; -+ sector_t sector; -+ struct exfat_dentry *ep; -+ struct buffer_head *bh; -+ -+ for (i = order; i < num_entries; i++) { -+ ep = exfat_get_dentry(sb, p_dir, entry + i, &bh, §or); -+ if (!ep) -+ return -EIO; -+ -+ exfat_set_entry_type(ep, TYPE_DELETED); -+ exfat_update_bh(sb, bh, IS_DIRSYNC(inode)); -+ brelse(bh); -+ } -+ -+ return 0; -+} -+ -+int exfat_update_dir_chksum_with_entry_set(struct super_block *sb, -+ struct exfat_entry_set_cache *es, int sync) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct buffer_head *bh; -+ sector_t sec = es->sector; -+ unsigned int off = es->offset; -+ int chksum_type = CS_DIR_ENTRY, i, num_entries = es->num_entries; -+ unsigned int buf_off = (off - es->offset); -+ unsigned int remaining_byte_in_sector, copy_entries, clu; -+ unsigned short chksum = 0; -+ -+ for (i = 0; i < num_entries; i++) { -+ chksum = exfat_calc_chksum_2byte(&es->entries[i], DENTRY_SIZE, -+ chksum, chksum_type); -+ chksum_type = CS_DEFAULT; -+ } -+ -+ es->entries[0].dentry.file.checksum = cpu_to_le16(chksum); -+ -+ while (num_entries) { -+ /* write per sector base */ -+ remaining_byte_in_sector = (1 << sb->s_blocksize_bits) - off; -+ copy_entries = min_t(int, -+ EXFAT_B_TO_DEN(remaining_byte_in_sector), -+ num_entries); -+ bh = sb_bread(sb, sec); -+ if (!bh) -+ goto err_out; -+ memcpy(bh->b_data + off, -+ (unsigned char *)&es->entries[0] + buf_off, -+ EXFAT_DEN_TO_B(copy_entries)); -+ exfat_update_bh(sb, bh, sync); -+ brelse(bh); -+ num_entries -= copy_entries; -+ -+ if (num_entries) { -+ /* get next sector */ -+ if (exfat_is_last_sector_in_cluster(sbi, sec)) { -+ clu = exfat_sector_to_cluster(sbi, sec); -+ if (es->alloc_flag == ALLOC_NO_FAT_CHAIN) -+ clu++; -+ else if (exfat_get_next_cluster(sb, &clu)) -+ goto err_out; -+ sec = exfat_cluster_to_sector(sbi, clu); -+ } else { -+ sec++; -+ } -+ off = 0; -+ buf_off += EXFAT_DEN_TO_B(copy_entries); -+ } -+ } -+ -+ return 0; -+err_out: -+ return -EIO; -+} -+ -+static int exfat_walk_fat_chain(struct super_block *sb, -+ struct exfat_chain *p_dir, unsigned int byte_offset, -+ unsigned int *clu) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ unsigned int clu_offset; -+ unsigned int cur_clu; -+ -+ clu_offset = EXFAT_B_TO_CLU(byte_offset, sbi); -+ cur_clu = p_dir->dir; -+ -+ if (p_dir->flags == ALLOC_NO_FAT_CHAIN) { -+ cur_clu += clu_offset; -+ } else { -+ while (clu_offset > 0) { -+ if (exfat_get_next_cluster(sb, &cur_clu)) -+ return -EIO; -+ if (cur_clu == EXFAT_EOF_CLUSTER) { -+ exfat_fs_error(sb, -+ "invalid dentry access beyond EOF (clu : %u, eidx : %d)", -+ p_dir->dir, -+ EXFAT_B_TO_DEN(byte_offset)); -+ return -EIO; -+ } -+ clu_offset--; -+ } -+ } -+ -+ *clu = cur_clu; -+ return 0; -+} -+ -+int exfat_find_location(struct super_block *sb, struct exfat_chain *p_dir, -+ int entry, sector_t *sector, int *offset) -+{ -+ int ret; -+ unsigned int off, clu = 0; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ -+ off = EXFAT_DEN_TO_B(entry); -+ -+ ret = exfat_walk_fat_chain(sb, p_dir, off, &clu); -+ if (ret) -+ return ret; -+ -+ /* byte offset in cluster */ -+ off = EXFAT_CLU_OFFSET(off, sbi); -+ -+ /* byte offset in sector */ -+ *offset = EXFAT_BLK_OFFSET(off, sb); -+ -+ /* sector offset in cluster */ -+ *sector = EXFAT_B_TO_BLK(off, sb); -+ *sector += exfat_cluster_to_sector(sbi, clu); -+ return 0; -+} -+ -+#define EXFAT_MAX_RA_SIZE (128*1024) -+static int exfat_dir_readahead(struct super_block *sb, sector_t sec) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct buffer_head *bh; -+ unsigned int max_ra_count = EXFAT_MAX_RA_SIZE >> sb->s_blocksize_bits; -+ unsigned int page_ra_count = PAGE_SIZE >> sb->s_blocksize_bits; -+ unsigned int adj_ra_count = max(sbi->sect_per_clus, page_ra_count); -+ unsigned int ra_count = min(adj_ra_count, max_ra_count); -+ -+ /* Read-ahead is not required */ -+ if (sbi->sect_per_clus == 1) -+ return 0; -+ -+ if (sec < sbi->data_start_sector) { -+ exfat_msg(sb, KERN_ERR, -+ "requested sector is invalid(sect:%llu, root:%llu)", -+ (unsigned long long)sec, sbi->data_start_sector); -+ return -EIO; -+ } -+ -+ /* Not sector aligned with ra_count, resize ra_count to page size */ -+ if ((sec - sbi->data_start_sector) & (ra_count - 1)) -+ ra_count = page_ra_count; -+ -+ bh = sb_find_get_block(sb, sec); -+ if (!bh || !buffer_uptodate(bh)) { -+ unsigned int i; -+ -+ for (i = 0; i < ra_count; i++) -+ sb_breadahead(sb, (sector_t)(sec + i)); -+ } -+ brelse(bh); -+ return 0; -+} -+ -+struct exfat_dentry *exfat_get_dentry(struct super_block *sb, -+ struct exfat_chain *p_dir, int entry, struct buffer_head **bh, -+ sector_t *sector) -+{ -+ unsigned int dentries_per_page = EXFAT_B_TO_DEN(PAGE_SIZE); -+ int off; -+ sector_t sec; -+ -+ if (p_dir->dir == DIR_DELETED) { -+ exfat_msg(sb, KERN_ERR, "abnormal access to deleted dentry\n"); -+ return NULL; -+ } -+ -+ if (exfat_find_location(sb, p_dir, entry, &sec, &off)) -+ return NULL; -+ -+ if (p_dir->dir != EXFAT_FREE_CLUSTER && -+ !(entry & (dentries_per_page - 1))) -+ exfat_dir_readahead(sb, sec); -+ -+ *bh = sb_bread(sb, sec); -+ if (!*bh) -+ return NULL; -+ -+ if (sector) -+ *sector = sec; -+ return (struct exfat_dentry *)((*bh)->b_data + off); -+} -+ -+enum exfat_validate_dentry_mode { -+ ES_MODE_STARTED, -+ ES_MODE_GET_FILE_ENTRY, -+ ES_MODE_GET_STRM_ENTRY, -+ ES_MODE_GET_NAME_ENTRY, -+ ES_MODE_GET_CRITICAL_SEC_ENTRY, -+}; -+ -+static bool exfat_validate_entry(unsigned int type, -+ enum exfat_validate_dentry_mode *mode) -+{ -+ if (type == TYPE_UNUSED || type == TYPE_DELETED) -+ return false; -+ -+ switch (*mode) { -+ case ES_MODE_STARTED: -+ if (type != TYPE_FILE && type != TYPE_DIR) -+ return false; -+ *mode = ES_MODE_GET_FILE_ENTRY; -+ return true; -+ case ES_MODE_GET_FILE_ENTRY: -+ if (type != TYPE_STREAM) -+ return false; -+ *mode = ES_MODE_GET_STRM_ENTRY; -+ return true; -+ case ES_MODE_GET_STRM_ENTRY: -+ if (type != TYPE_EXTEND) -+ return false; -+ *mode = ES_MODE_GET_NAME_ENTRY; -+ return true; -+ case ES_MODE_GET_NAME_ENTRY: -+ if (type == TYPE_STREAM) -+ return false; -+ if (type != TYPE_EXTEND) { -+ if (!(type & TYPE_CRITICAL_SEC)) -+ return false; -+ *mode = ES_MODE_GET_CRITICAL_SEC_ENTRY; -+ } -+ return true; -+ case ES_MODE_GET_CRITICAL_SEC_ENTRY: -+ if (type == TYPE_EXTEND || type == TYPE_STREAM) -+ return false; -+ if ((type & TYPE_CRITICAL_SEC) != TYPE_CRITICAL_SEC) -+ return false; -+ return true; -+ default: -+ WARN_ON_ONCE(1); -+ return false; -+ } -+} -+ -+/* -+ * Returns a set of dentries for a file or dir. -+ * -+ * Note that this is a copy (dump) of dentries so that user should -+ * call write_entry_set() to apply changes made in this entry set -+ * to the real device. -+ * -+ * in: -+ * sb+p_dir+entry: indicates a file/dir -+ * type: specifies how many dentries should be included. -+ * out: -+ * file_ep: will point the first dentry(= file dentry) on success -+ * return: -+ * pointer of entry set on success, -+ * NULL on failure. -+ */ -+struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb, -+ struct exfat_chain *p_dir, int entry, unsigned int type, -+ struct exfat_dentry **file_ep) -+{ -+ int ret; -+ unsigned int off, byte_offset, clu = 0; -+ unsigned int entry_type; -+ sector_t sec; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct exfat_entry_set_cache *es; -+ struct exfat_dentry *ep, *pos; -+ unsigned char num_entries; -+ enum exfat_validate_dentry_mode mode = ES_MODE_STARTED; -+ struct buffer_head *bh; -+ -+ if (p_dir->dir == DIR_DELETED) { -+ exfat_msg(sb, KERN_ERR, "access to deleted dentry\n"); -+ return NULL; -+ } -+ -+ byte_offset = EXFAT_DEN_TO_B(entry); -+ ret = exfat_walk_fat_chain(sb, p_dir, byte_offset, &clu); -+ if (ret) -+ return NULL; -+ -+ /* byte offset in cluster */ -+ byte_offset = EXFAT_CLU_OFFSET(byte_offset, sbi); -+ -+ /* byte offset in sector */ -+ off = EXFAT_BLK_OFFSET(byte_offset, sb); -+ -+ /* sector offset in cluster */ -+ sec = EXFAT_B_TO_BLK(byte_offset, sb); -+ sec += exfat_cluster_to_sector(sbi, clu); -+ -+ bh = sb_bread(sb, sec); -+ if (!bh) -+ return NULL; -+ -+ ep = (struct exfat_dentry *)(bh->b_data + off); -+ entry_type = exfat_get_entry_type(ep); -+ -+ if (entry_type != TYPE_FILE && entry_type != TYPE_DIR) -+ goto release_bh; -+ -+ num_entries = type == ES_ALL_ENTRIES ? -+ ep->dentry.file.num_ext + 1 : type; -+ es = kmalloc(struct_size(es, entries, num_entries), GFP_KERNEL); -+ if (!es) -+ goto release_bh; -+ -+ es->num_entries = num_entries; -+ es->sector = sec; -+ es->offset = off; -+ es->alloc_flag = p_dir->flags; -+ -+ pos = &es->entries[0]; -+ -+ while (num_entries) { -+ if (!exfat_validate_entry(exfat_get_entry_type(ep), &mode)) -+ goto free_es; -+ -+ /* copy dentry */ -+ memcpy(pos, ep, sizeof(struct exfat_dentry)); -+ -+ if (--num_entries == 0) -+ break; -+ -+ if (((off + DENTRY_SIZE) & (sb->s_blocksize - 1)) < -+ (off & (sb->s_blocksize - 1))) { -+ /* get the next sector */ -+ if (exfat_is_last_sector_in_cluster(sbi, sec)) { -+ if (es->alloc_flag == ALLOC_NO_FAT_CHAIN) -+ clu++; -+ else if (exfat_get_next_cluster(sb, &clu)) -+ goto free_es; -+ sec = exfat_cluster_to_sector(sbi, clu); -+ } else { -+ sec++; -+ } -+ -+ brelse(bh); -+ bh = sb_bread(sb, sec); -+ if (!bh) -+ goto free_es; -+ off = 0; -+ ep = (struct exfat_dentry *)bh->b_data; -+ } else { -+ ep++; -+ off += DENTRY_SIZE; -+ } -+ pos++; -+ } -+ -+ if (file_ep) -+ *file_ep = &es->entries[0]; -+ brelse(bh); -+ return es; -+ -+free_es: -+ kfree(es); -+release_bh: -+ brelse(bh); -+ return NULL; -+} -+ -+enum { -+ DIRENT_STEP_FILE, -+ DIRENT_STEP_STRM, -+ DIRENT_STEP_NAME, -+ DIRENT_STEP_SECD, -+}; -+ -+/* -+ * return values: -+ * >= 0 : return dir entiry position with the name in dir -+ * -EEXIST : (root dir, ".") it is the root dir itself -+ * -ENOENT : entry with the name does not exist -+ * -EIO : I/O error -+ */ -+int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei, -+ struct exfat_chain *p_dir, struct exfat_uni_name *p_uniname, -+ int num_entries, unsigned int type) -+{ -+ int i, rewind = 0, dentry = 0, end_eidx = 0, num_ext = 0, len; -+ int order, step, name_len = 0; -+ int dentries_per_clu, num_empty = 0; -+ unsigned int entry_type; -+ unsigned short *uniname = NULL; -+ struct exfat_chain clu; -+ struct exfat_hint *hint_stat = &ei->hint_stat; -+ struct exfat_hint_femp candi_empty; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ -+ dentries_per_clu = sbi->dentries_per_clu; -+ -+ exfat_chain_dup(&clu, p_dir); -+ -+ if (hint_stat->eidx) { -+ clu.dir = hint_stat->clu; -+ dentry = hint_stat->eidx; -+ end_eidx = dentry; -+ } -+ -+ candi_empty.eidx = EXFAT_HINT_NONE; -+rewind: -+ order = 0; -+ step = DIRENT_STEP_FILE; -+ while (clu.dir != EXFAT_EOF_CLUSTER) { -+ i = dentry & (dentries_per_clu - 1); -+ for (; i < dentries_per_clu; i++, dentry++) { -+ struct exfat_dentry *ep; -+ struct buffer_head *bh; -+ -+ if (rewind && dentry == end_eidx) -+ goto not_found; -+ -+ ep = exfat_get_dentry(sb, &clu, i, &bh, NULL); -+ if (!ep) -+ return -EIO; -+ -+ entry_type = exfat_get_entry_type(ep); -+ -+ if (entry_type == TYPE_UNUSED || -+ entry_type == TYPE_DELETED) { -+ step = DIRENT_STEP_FILE; -+ -+ num_empty++; -+ if (candi_empty.eidx == EXFAT_HINT_NONE && -+ num_empty == 1) { -+ exfat_chain_set(&candi_empty.cur, -+ clu.dir, clu.size, clu.flags); -+ } -+ -+ if (candi_empty.eidx == EXFAT_HINT_NONE && -+ num_empty >= num_entries) { -+ candi_empty.eidx = -+ dentry - (num_empty - 1); -+ WARN_ON(candi_empty.eidx < 0); -+ candi_empty.count = num_empty; -+ -+ if (ei->hint_femp.eidx == -+ EXFAT_HINT_NONE || -+ candi_empty.eidx <= -+ ei->hint_femp.eidx) { -+ memcpy(&ei->hint_femp, -+ &candi_empty, -+ sizeof(candi_empty)); -+ } -+ } -+ -+ brelse(bh); -+ if (entry_type == TYPE_UNUSED) -+ goto not_found; -+ continue; -+ } -+ -+ num_empty = 0; -+ candi_empty.eidx = EXFAT_HINT_NONE; -+ -+ if (entry_type == TYPE_FILE || entry_type == TYPE_DIR) { -+ step = DIRENT_STEP_FILE; -+ if (type == TYPE_ALL || type == entry_type) { -+ num_ext = ep->dentry.file.num_ext; -+ step = DIRENT_STEP_STRM; -+ } -+ brelse(bh); -+ continue; -+ } -+ -+ if (entry_type == TYPE_STREAM) { -+ unsigned short name_hash; -+ -+ if (step != DIRENT_STEP_STRM) { -+ step = DIRENT_STEP_FILE; -+ brelse(bh); -+ continue; -+ } -+ step = DIRENT_STEP_FILE; -+ name_hash = le16_to_cpu( -+ ep->dentry.stream.name_hash); -+ if (p_uniname->name_hash == name_hash && -+ p_uniname->name_len == -+ ep->dentry.stream.name_len) { -+ step = DIRENT_STEP_NAME; -+ order = 1; -+ name_len = 0; -+ } -+ brelse(bh); -+ continue; -+ } -+ -+ brelse(bh); -+ if (entry_type == TYPE_EXTEND) { -+ unsigned short entry_uniname[16], unichar; -+ -+ if (step != DIRENT_STEP_NAME) { -+ step = DIRENT_STEP_FILE; -+ continue; -+ } -+ -+ if (++order == 2) -+ uniname = p_uniname->name; -+ else -+ uniname += EXFAT_FILE_NAME_LEN; -+ -+ len = exfat_extract_uni_name(ep, entry_uniname); -+ name_len += len; -+ -+ unichar = *(uniname+len); -+ *(uniname+len) = 0x0; -+ -+ if (exfat_uniname_ncmp(sb, uniname, -+ entry_uniname, len)) { -+ step = DIRENT_STEP_FILE; -+ } else if (p_uniname->name_len == name_len) { -+ if (order == num_ext) -+ goto found; -+ step = DIRENT_STEP_SECD; -+ } -+ -+ *(uniname+len) = unichar; -+ continue; -+ } -+ -+ if (entry_type & -+ (TYPE_CRITICAL_SEC | TYPE_BENIGN_SEC)) { -+ if (step == DIRENT_STEP_SECD) { -+ if (++order == num_ext) -+ goto found; -+ continue; -+ } -+ } -+ step = DIRENT_STEP_FILE; -+ } -+ -+ if (clu.flags == ALLOC_NO_FAT_CHAIN) { -+ if (--clu.size > 0) -+ clu.dir++; -+ else -+ clu.dir = EXFAT_EOF_CLUSTER; -+ } else { -+ if (exfat_get_next_cluster(sb, &clu.dir)) -+ return -EIO; -+ } -+ } -+ -+not_found: -+ /* -+ * We started at not 0 index,so we should try to find target -+ * from 0 index to the index we started at. -+ */ -+ if (!rewind && end_eidx) { -+ rewind = 1; -+ dentry = 0; -+ clu.dir = p_dir->dir; -+ /* reset empty hint */ -+ num_empty = 0; -+ candi_empty.eidx = EXFAT_HINT_NONE; -+ goto rewind; -+ } -+ -+ /* initialized hint_stat */ -+ hint_stat->clu = p_dir->dir; -+ hint_stat->eidx = 0; -+ return -ENOENT; -+ -+found: -+ /* next dentry we'll find is out of this cluster */ -+ if (!((dentry + 1) & (dentries_per_clu - 1))) { -+ int ret = 0; -+ -+ if (clu.flags == ALLOC_NO_FAT_CHAIN) { -+ if (--clu.size > 0) -+ clu.dir++; -+ else -+ clu.dir = EXFAT_EOF_CLUSTER; -+ } else { -+ ret = exfat_get_next_cluster(sb, &clu.dir); -+ } -+ -+ if (ret || clu.dir != EXFAT_EOF_CLUSTER) { -+ /* just initialized hint_stat */ -+ hint_stat->clu = p_dir->dir; -+ hint_stat->eidx = 0; -+ return (dentry - num_ext); -+ } -+ } -+ -+ hint_stat->clu = clu.dir; -+ hint_stat->eidx = dentry + 1; -+ return dentry - num_ext; -+} -+ -+int exfat_count_ext_entries(struct super_block *sb, struct exfat_chain *p_dir, -+ int entry, struct exfat_dentry *ep) -+{ -+ int i, count = 0; -+ unsigned int type; -+ struct exfat_dentry *ext_ep; -+ struct buffer_head *bh; -+ -+ for (i = 0, entry++; i < ep->dentry.file.num_ext; i++, entry++) { -+ ext_ep = exfat_get_dentry(sb, p_dir, entry, &bh, NULL); -+ if (!ext_ep) -+ return -EIO; -+ -+ type = exfat_get_entry_type(ext_ep); -+ brelse(bh); -+ if (type == TYPE_EXTEND || type == TYPE_STREAM) -+ count++; -+ else -+ break; -+ } -+ return count; -+} -+ -+int exfat_count_dir_entries(struct super_block *sb, struct exfat_chain *p_dir) -+{ -+ int i, count = 0; -+ int dentries_per_clu; -+ unsigned int entry_type; -+ struct exfat_chain clu; -+ struct exfat_dentry *ep; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct buffer_head *bh; -+ -+ dentries_per_clu = sbi->dentries_per_clu; -+ -+ exfat_chain_dup(&clu, p_dir); -+ -+ while (clu.dir != EXFAT_EOF_CLUSTER) { -+ for (i = 0; i < dentries_per_clu; i++) { -+ ep = exfat_get_dentry(sb, &clu, i, &bh, NULL); -+ if (!ep) -+ return -EIO; -+ entry_type = exfat_get_entry_type(ep); -+ brelse(bh); -+ -+ if (entry_type == TYPE_UNUSED) -+ return count; -+ if (entry_type != TYPE_DIR) -+ continue; -+ count++; -+ } -+ -+ if (clu.flags == ALLOC_NO_FAT_CHAIN) { -+ if (--clu.size > 0) -+ clu.dir++; -+ else -+ clu.dir = EXFAT_EOF_CLUSTER; -+ } else { -+ if (exfat_get_next_cluster(sb, &(clu.dir))) -+ return -EIO; -+ } -+ } -+ -+ return count; -+} --- -2.25.1 - diff --git a/kernel/kernel/files/patches/mageia/fs-exfat-add-exfat-cache.patch b/kernel/kernel/files/patches/mageia/fs-exfat-add-exfat-cache.patch deleted file mode 100644 index 179a1226..00000000 --- a/kernel/kernel/files/patches/mageia/fs-exfat-add-exfat-cache.patch +++ /dev/null @@ -1,354 +0,0 @@ -From c35b6810c4952ae5776607e2c1d6a587425d5834 Mon Sep 17 00:00:00 2001 -From: Namjae Jeon -Date: Mon, 2 Mar 2020 15:21:39 +0900 -Subject: [PATCH 08/14] exfat: add exfat cache -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This adds the implementation of exfat cache. - -Signed-off-by: Namjae Jeon -Signed-off-by: Sungjong Seo -Reviewed-by: Pali Rohár -Reviewed-by: Christoph Hellwig -Signed-off-by: Al Viro ---- - fs/exfat/cache.c | 325 +++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 325 insertions(+) - create mode 100644 fs/exfat/cache.c - -diff --git a/fs/exfat/cache.c b/fs/exfat/cache.c -new file mode 100644 -index 000000000000..03d0824fc368 ---- /dev/null -+++ b/fs/exfat/cache.c -@@ -0,0 +1,325 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * linux/fs/fat/cache.c -+ * -+ * Written 1992,1993 by Werner Almesberger -+ * -+ * Mar 1999. AV. Changed cache, so that it uses the starting cluster instead -+ * of inode number. -+ * May 1999. AV. Fixed the bogosity with FAT32 (read "FAT28"). Fscking lusers. -+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -+ */ -+ -+#include -+#include -+#include -+ -+#include "exfat_raw.h" -+#include "exfat_fs.h" -+ -+#define EXFAT_CACHE_VALID 0 -+#define EXFAT_MAX_CACHE 16 -+ -+struct exfat_cache { -+ struct list_head cache_list; -+ unsigned int nr_contig; /* number of contiguous clusters */ -+ unsigned int fcluster; /* cluster number in the file. */ -+ unsigned int dcluster; /* cluster number on disk. */ -+}; -+ -+struct exfat_cache_id { -+ unsigned int id; -+ unsigned int nr_contig; -+ unsigned int fcluster; -+ unsigned int dcluster; -+}; -+ -+static struct kmem_cache *exfat_cachep; -+ -+static void exfat_cache_init_once(void *c) -+{ -+ struct exfat_cache *cache = (struct exfat_cache *)c; -+ -+ INIT_LIST_HEAD(&cache->cache_list); -+} -+ -+int exfat_cache_init(void) -+{ -+ exfat_cachep = kmem_cache_create("exfat_cache", -+ sizeof(struct exfat_cache), -+ 0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, -+ exfat_cache_init_once); -+ if (!exfat_cachep) -+ return -ENOMEM; -+ return 0; -+} -+ -+void exfat_cache_shutdown(void) -+{ -+ if (!exfat_cachep) -+ return; -+ kmem_cache_destroy(exfat_cachep); -+} -+ -+void exfat_cache_init_inode(struct inode *inode) -+{ -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ -+ spin_lock_init(&ei->cache_lru_lock); -+ ei->nr_caches = 0; -+ ei->cache_valid_id = EXFAT_CACHE_VALID + 1; -+ INIT_LIST_HEAD(&ei->cache_lru); -+} -+ -+static inline struct exfat_cache *exfat_cache_alloc(void) -+{ -+ return kmem_cache_alloc(exfat_cachep, GFP_NOFS); -+} -+ -+static inline void exfat_cache_free(struct exfat_cache *cache) -+{ -+ WARN_ON(!list_empty(&cache->cache_list)); -+ kmem_cache_free(exfat_cachep, cache); -+} -+ -+static inline void exfat_cache_update_lru(struct inode *inode, -+ struct exfat_cache *cache) -+{ -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ -+ if (ei->cache_lru.next != &cache->cache_list) -+ list_move(&cache->cache_list, &ei->cache_lru); -+} -+ -+static unsigned int exfat_cache_lookup(struct inode *inode, -+ unsigned int fclus, struct exfat_cache_id *cid, -+ unsigned int *cached_fclus, unsigned int *cached_dclus) -+{ -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ static struct exfat_cache nohit = { .fcluster = 0, }; -+ struct exfat_cache *hit = &nohit, *p; -+ unsigned int offset = EXFAT_EOF_CLUSTER; -+ -+ spin_lock(&ei->cache_lru_lock); -+ list_for_each_entry(p, &ei->cache_lru, cache_list) { -+ /* Find the cache of "fclus" or nearest cache. */ -+ if (p->fcluster <= fclus && hit->fcluster < p->fcluster) { -+ hit = p; -+ if (hit->fcluster + hit->nr_contig < fclus) { -+ offset = hit->nr_contig; -+ } else { -+ offset = fclus - hit->fcluster; -+ break; -+ } -+ } -+ } -+ if (hit != &nohit) { -+ exfat_cache_update_lru(inode, hit); -+ -+ cid->id = ei->cache_valid_id; -+ cid->nr_contig = hit->nr_contig; -+ cid->fcluster = hit->fcluster; -+ cid->dcluster = hit->dcluster; -+ *cached_fclus = cid->fcluster + offset; -+ *cached_dclus = cid->dcluster + offset; -+ } -+ spin_unlock(&ei->cache_lru_lock); -+ -+ return offset; -+} -+ -+static struct exfat_cache *exfat_cache_merge(struct inode *inode, -+ struct exfat_cache_id *new) -+{ -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ struct exfat_cache *p; -+ -+ list_for_each_entry(p, &ei->cache_lru, cache_list) { -+ /* Find the same part as "new" in cluster-chain. */ -+ if (p->fcluster == new->fcluster) { -+ if (new->nr_contig > p->nr_contig) -+ p->nr_contig = new->nr_contig; -+ return p; -+ } -+ } -+ return NULL; -+} -+ -+static void exfat_cache_add(struct inode *inode, -+ struct exfat_cache_id *new) -+{ -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ struct exfat_cache *cache, *tmp; -+ -+ if (new->fcluster == EXFAT_EOF_CLUSTER) /* dummy cache */ -+ return; -+ -+ spin_lock(&ei->cache_lru_lock); -+ if (new->id != EXFAT_CACHE_VALID && -+ new->id != ei->cache_valid_id) -+ goto unlock; /* this cache was invalidated */ -+ -+ cache = exfat_cache_merge(inode, new); -+ if (cache == NULL) { -+ if (ei->nr_caches < EXFAT_MAX_CACHE) { -+ ei->nr_caches++; -+ spin_unlock(&ei->cache_lru_lock); -+ -+ tmp = exfat_cache_alloc(); -+ if (!tmp) { -+ spin_lock(&ei->cache_lru_lock); -+ ei->nr_caches--; -+ spin_unlock(&ei->cache_lru_lock); -+ return; -+ } -+ -+ spin_lock(&ei->cache_lru_lock); -+ cache = exfat_cache_merge(inode, new); -+ if (cache != NULL) { -+ ei->nr_caches--; -+ exfat_cache_free(tmp); -+ goto out_update_lru; -+ } -+ cache = tmp; -+ } else { -+ struct list_head *p = ei->cache_lru.prev; -+ -+ cache = list_entry(p, -+ struct exfat_cache, cache_list); -+ } -+ cache->fcluster = new->fcluster; -+ cache->dcluster = new->dcluster; -+ cache->nr_contig = new->nr_contig; -+ } -+out_update_lru: -+ exfat_cache_update_lru(inode, cache); -+unlock: -+ spin_unlock(&ei->cache_lru_lock); -+} -+ -+/* -+ * Cache invalidation occurs rarely, thus the LRU chain is not updated. It -+ * fixes itself after a while. -+ */ -+static void __exfat_cache_inval_inode(struct inode *inode) -+{ -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ struct exfat_cache *cache; -+ -+ while (!list_empty(&ei->cache_lru)) { -+ cache = list_entry(ei->cache_lru.next, -+ struct exfat_cache, cache_list); -+ list_del_init(&cache->cache_list); -+ ei->nr_caches--; -+ exfat_cache_free(cache); -+ } -+ /* Update. The copy of caches before this id is discarded. */ -+ ei->cache_valid_id++; -+ if (ei->cache_valid_id == EXFAT_CACHE_VALID) -+ ei->cache_valid_id++; -+} -+ -+void exfat_cache_inval_inode(struct inode *inode) -+{ -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ -+ spin_lock(&ei->cache_lru_lock); -+ __exfat_cache_inval_inode(inode); -+ spin_unlock(&ei->cache_lru_lock); -+} -+ -+static inline int cache_contiguous(struct exfat_cache_id *cid, -+ unsigned int dclus) -+{ -+ cid->nr_contig++; -+ return cid->dcluster + cid->nr_contig == dclus; -+} -+ -+static inline void cache_init(struct exfat_cache_id *cid, -+ unsigned int fclus, unsigned int dclus) -+{ -+ cid->id = EXFAT_CACHE_VALID; -+ cid->fcluster = fclus; -+ cid->dcluster = dclus; -+ cid->nr_contig = 0; -+} -+ -+int exfat_get_cluster(struct inode *inode, unsigned int cluster, -+ unsigned int *fclus, unsigned int *dclus, -+ unsigned int *last_dclus, int allow_eof) -+{ -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ unsigned int limit = sbi->num_clusters; -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ struct exfat_cache_id cid; -+ unsigned int content; -+ -+ if (ei->start_clu == EXFAT_FREE_CLUSTER) { -+ exfat_fs_error(sb, -+ "invalid access to exfat cache (entry 0x%08x)", -+ ei->start_clu); -+ return -EIO; -+ } -+ -+ *fclus = 0; -+ *dclus = ei->start_clu; -+ *last_dclus = *dclus; -+ -+ /* -+ * Don`t use exfat_cache if zero offset or non-cluster allocation -+ */ -+ if (cluster == 0 || *dclus == EXFAT_EOF_CLUSTER) -+ return 0; -+ -+ cache_init(&cid, EXFAT_EOF_CLUSTER, EXFAT_EOF_CLUSTER); -+ -+ if (exfat_cache_lookup(inode, cluster, &cid, fclus, dclus) == -+ EXFAT_EOF_CLUSTER) { -+ /* -+ * dummy, always not contiguous -+ * This is reinitialized by cache_init(), later. -+ */ -+ WARN_ON(cid.id != EXFAT_CACHE_VALID || -+ cid.fcluster != EXFAT_EOF_CLUSTER || -+ cid.dcluster != EXFAT_EOF_CLUSTER || -+ cid.nr_contig != 0); -+ } -+ -+ if (*fclus == cluster) -+ return 0; -+ -+ while (*fclus < cluster) { -+ /* prevent the infinite loop of cluster chain */ -+ if (*fclus > limit) { -+ exfat_fs_error(sb, -+ "detected the cluster chain loop (i_pos %u)", -+ (*fclus)); -+ return -EIO; -+ } -+ -+ if (exfat_ent_get(sb, *dclus, &content)) -+ return -EIO; -+ -+ *last_dclus = *dclus; -+ *dclus = content; -+ (*fclus)++; -+ -+ if (content == EXFAT_EOF_CLUSTER) { -+ if (!allow_eof) { -+ exfat_fs_error(sb, -+ "invalid cluster chain (i_pos %u, last_clus 0x%08x is EOF)", -+ *fclus, (*last_dclus)); -+ return -EIO; -+ } -+ -+ break; -+ } -+ -+ if (!cache_contiguous(&cid, *dclus)) -+ cache_init(&cid, *fclus, *dclus); -+ } -+ -+ exfat_cache_add(inode, &cid); -+ return 0; -+} --- -2.25.1 - diff --git a/kernel/kernel/files/patches/mageia/fs-exfat-add-fat-entry-operations.patch b/kernel/kernel/files/patches/mageia/fs-exfat-add-fat-entry-operations.patch deleted file mode 100644 index 5d0f4f35..00000000 --- a/kernel/kernel/files/patches/mageia/fs-exfat-add-fat-entry-operations.patch +++ /dev/null @@ -1,492 +0,0 @@ -From 31023864e67a5f390cefbe92f72343027dc3aa33 Mon Sep 17 00:00:00 2001 -From: Namjae Jeon -Date: Mon, 2 Mar 2020 15:21:37 +0900 -Subject: [PATCH 06/14] exfat: add fat entry operations -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This adds the implementation of fat entry operations for exfat. - -Signed-off-by: Namjae Jeon -Signed-off-by: Sungjong Seo -Reviewed-by: Pali Rohár -Reviewed-by: Christoph Hellwig -Signed-off-by: Al Viro ---- - fs/exfat/fatent.c | 463 ++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 463 insertions(+) - create mode 100644 fs/exfat/fatent.c - -diff --git a/fs/exfat/fatent.c b/fs/exfat/fatent.c -new file mode 100644 -index 000000000000..a855b1769a96 ---- /dev/null -+++ b/fs/exfat/fatent.c -@@ -0,0 +1,463 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -+ */ -+ -+#include -+#include -+#include -+ -+#include "exfat_raw.h" -+#include "exfat_fs.h" -+ -+static int exfat_mirror_bh(struct super_block *sb, sector_t sec, -+ struct buffer_head *bh) -+{ -+ struct buffer_head *c_bh; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ sector_t sec2; -+ int err = 0; -+ -+ if (sbi->FAT2_start_sector != sbi->FAT1_start_sector) { -+ sec2 = sec - sbi->FAT1_start_sector + sbi->FAT2_start_sector; -+ c_bh = sb_getblk(sb, sec2); -+ if (!c_bh) -+ return -ENOMEM; -+ memcpy(c_bh->b_data, bh->b_data, sb->s_blocksize); -+ set_buffer_uptodate(c_bh); -+ mark_buffer_dirty(c_bh); -+ if (sb->s_flags & SB_SYNCHRONOUS) -+ err = sync_dirty_buffer(c_bh); -+ brelse(c_bh); -+ } -+ -+ return err; -+} -+ -+static int __exfat_ent_get(struct super_block *sb, unsigned int loc, -+ unsigned int *content) -+{ -+ unsigned int off; -+ sector_t sec; -+ struct buffer_head *bh; -+ -+ sec = FAT_ENT_OFFSET_SECTOR(sb, loc); -+ off = FAT_ENT_OFFSET_BYTE_IN_SECTOR(sb, loc); -+ -+ bh = sb_bread(sb, sec); -+ if (!bh) -+ return -EIO; -+ -+ *content = le32_to_cpu(*(__le32 *)(&bh->b_data[off])); -+ -+ /* remap reserved clusters to simplify code */ -+ if (*content > EXFAT_BAD_CLUSTER) -+ *content = EXFAT_EOF_CLUSTER; -+ -+ brelse(bh); -+ return 0; -+} -+ -+int exfat_ent_set(struct super_block *sb, unsigned int loc, -+ unsigned int content) -+{ -+ unsigned int off; -+ sector_t sec; -+ __le32 *fat_entry; -+ struct buffer_head *bh; -+ -+ sec = FAT_ENT_OFFSET_SECTOR(sb, loc); -+ off = FAT_ENT_OFFSET_BYTE_IN_SECTOR(sb, loc); -+ -+ bh = sb_bread(sb, sec); -+ if (!bh) -+ return -EIO; -+ -+ fat_entry = (__le32 *)&(bh->b_data[off]); -+ *fat_entry = cpu_to_le32(content); -+ exfat_update_bh(sb, bh, sb->s_flags & SB_SYNCHRONOUS); -+ exfat_mirror_bh(sb, sec, bh); -+ brelse(bh); -+ return 0; -+} -+ -+static inline bool is_valid_cluster(struct exfat_sb_info *sbi, -+ unsigned int clus) -+{ -+ if (clus < EXFAT_FIRST_CLUSTER || sbi->num_clusters <= clus) -+ return false; -+ return true; -+} -+ -+int exfat_ent_get(struct super_block *sb, unsigned int loc, -+ unsigned int *content) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ int err; -+ -+ if (!is_valid_cluster(sbi, loc)) { -+ exfat_fs_error(sb, "invalid access to FAT (entry 0x%08x)", -+ loc); -+ return -EIO; -+ } -+ -+ err = __exfat_ent_get(sb, loc, content); -+ if (err) { -+ exfat_fs_error(sb, -+ "failed to access to FAT (entry 0x%08x, err:%d)", -+ loc, err); -+ return err; -+ } -+ -+ if (*content == EXFAT_FREE_CLUSTER) { -+ exfat_fs_error(sb, -+ "invalid access to FAT free cluster (entry 0x%08x)", -+ loc); -+ return -EIO; -+ } -+ -+ if (*content == EXFAT_BAD_CLUSTER) { -+ exfat_fs_error(sb, -+ "invalid access to FAT bad cluster (entry 0x%08x)", -+ loc); -+ return -EIO; -+ } -+ -+ if (*content != EXFAT_EOF_CLUSTER && !is_valid_cluster(sbi, *content)) { -+ exfat_fs_error(sb, -+ "invalid access to FAT (entry 0x%08x) bogus content (0x%08x)", -+ loc, *content); -+ return -EIO; -+ } -+ -+ return 0; -+} -+ -+int exfat_chain_cont_cluster(struct super_block *sb, unsigned int chain, -+ unsigned int len) -+{ -+ if (!len) -+ return 0; -+ -+ while (len > 1) { -+ if (exfat_ent_set(sb, chain, chain + 1)) -+ return -EIO; -+ chain++; -+ len--; -+ } -+ -+ if (exfat_ent_set(sb, chain, EXFAT_EOF_CLUSTER)) -+ return -EIO; -+ return 0; -+} -+ -+int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain) -+{ -+ unsigned int num_clusters = 0; -+ unsigned int clu; -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ -+ /* invalid cluster number */ -+ if (p_chain->dir == EXFAT_FREE_CLUSTER || -+ p_chain->dir == EXFAT_EOF_CLUSTER || -+ p_chain->dir < EXFAT_FIRST_CLUSTER) -+ return 0; -+ -+ /* no cluster to truncate */ -+ if (p_chain->size == 0) -+ return 0; -+ -+ /* check cluster validation */ -+ if (p_chain->dir < 2 && p_chain->dir >= sbi->num_clusters) { -+ exfat_msg(sb, KERN_ERR, "invalid start cluster (%u)", -+ p_chain->dir); -+ return -EIO; -+ } -+ -+ set_bit(EXFAT_SB_DIRTY, &sbi->s_state); -+ clu = p_chain->dir; -+ -+ if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { -+ do { -+ exfat_clear_bitmap(inode, clu); -+ clu++; -+ -+ num_clusters++; -+ } while (num_clusters < p_chain->size); -+ } else { -+ do { -+ exfat_clear_bitmap(inode, clu); -+ -+ if (exfat_get_next_cluster(sb, &clu)) -+ goto dec_used_clus; -+ -+ num_clusters++; -+ } while (clu != EXFAT_EOF_CLUSTER); -+ } -+ -+dec_used_clus: -+ sbi->used_clusters -= num_clusters; -+ return 0; -+} -+ -+int exfat_find_last_cluster(struct super_block *sb, struct exfat_chain *p_chain, -+ unsigned int *ret_clu) -+{ -+ unsigned int clu, next; -+ unsigned int count = 0; -+ -+ next = p_chain->dir; -+ if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { -+ *ret_clu = next + p_chain->size - 1; -+ return 0; -+ } -+ -+ do { -+ count++; -+ clu = next; -+ if (exfat_ent_get(sb, clu, &next)) -+ return -EIO; -+ } while (next != EXFAT_EOF_CLUSTER); -+ -+ if (p_chain->size != count) { -+ exfat_fs_error(sb, -+ "bogus directory size (clus : ondisk(%d) != counted(%d))", -+ p_chain->size, count); -+ return -EIO; -+ } -+ -+ *ret_clu = clu; -+ return 0; -+} -+ -+static inline int exfat_sync_bhs(struct buffer_head **bhs, int nr_bhs) -+{ -+ int i, err = 0; -+ -+ for (i = 0; i < nr_bhs; i++) -+ write_dirty_buffer(bhs[i], 0); -+ -+ for (i = 0; i < nr_bhs; i++) { -+ wait_on_buffer(bhs[i]); -+ if (!err && !buffer_uptodate(bhs[i])) -+ err = -EIO; -+ } -+ return err; -+} -+ -+int exfat_zeroed_cluster(struct inode *dir, unsigned int clu) -+{ -+ struct super_block *sb = dir->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct buffer_head *bhs[MAX_BUF_PER_PAGE]; -+ int nr_bhs = MAX_BUF_PER_PAGE; -+ sector_t blknr, last_blknr; -+ int err, i, n; -+ -+ blknr = exfat_cluster_to_sector(sbi, clu); -+ last_blknr = blknr + sbi->sect_per_clus; -+ -+ if (last_blknr > sbi->num_sectors && sbi->num_sectors > 0) { -+ exfat_fs_error_ratelimit(sb, -+ "%s: out of range(sect:%llu len:%u)", -+ __func__, (unsigned long long)blknr, -+ sbi->sect_per_clus); -+ return -EIO; -+ } -+ -+ /* Zeroing the unused blocks on this cluster */ -+ n = 0; -+ while (blknr < last_blknr) { -+ bhs[n] = sb_getblk(sb, blknr); -+ if (!bhs[n]) { -+ err = -ENOMEM; -+ goto release_bhs; -+ } -+ memset(bhs[n]->b_data, 0, sb->s_blocksize); -+ exfat_update_bh(sb, bhs[n], 0); -+ -+ n++; -+ blknr++; -+ -+ if (n == nr_bhs) { -+ if (IS_DIRSYNC(dir)) { -+ err = exfat_sync_bhs(bhs, n); -+ if (err) -+ goto release_bhs; -+ } -+ -+ for (i = 0; i < n; i++) -+ brelse(bhs[i]); -+ n = 0; -+ } -+ } -+ -+ if (IS_DIRSYNC(dir)) { -+ err = exfat_sync_bhs(bhs, n); -+ if (err) -+ goto release_bhs; -+ } -+ -+ for (i = 0; i < n; i++) -+ brelse(bhs[i]); -+ -+ return 0; -+ -+release_bhs: -+ exfat_msg(sb, KERN_ERR, "failed zeroed sect %llu\n", -+ (unsigned long long)blknr); -+ for (i = 0; i < n; i++) -+ bforget(bhs[i]); -+ return err; -+} -+ -+int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc, -+ struct exfat_chain *p_chain) -+{ -+ int ret = -ENOSPC; -+ unsigned int num_clusters = 0, total_cnt; -+ unsigned int hint_clu, new_clu, last_clu = EXFAT_EOF_CLUSTER; -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ -+ total_cnt = EXFAT_DATA_CLUSTER_COUNT(sbi); -+ -+ if (unlikely(total_cnt < sbi->used_clusters)) { -+ exfat_fs_error_ratelimit(sb, -+ "%s: invalid used clusters(t:%u,u:%u)\n", -+ __func__, total_cnt, sbi->used_clusters); -+ return -EIO; -+ } -+ -+ if (num_alloc > total_cnt - sbi->used_clusters) -+ return -ENOSPC; -+ -+ hint_clu = p_chain->dir; -+ /* find new cluster */ -+ if (hint_clu == EXFAT_EOF_CLUSTER) { -+ if (sbi->clu_srch_ptr < EXFAT_FIRST_CLUSTER) { -+ exfat_msg(sb, KERN_ERR, -+ "sbi->clu_srch_ptr is invalid (%u)\n", -+ sbi->clu_srch_ptr); -+ sbi->clu_srch_ptr = EXFAT_FIRST_CLUSTER; -+ } -+ -+ hint_clu = exfat_find_free_bitmap(sb, sbi->clu_srch_ptr); -+ if (hint_clu == EXFAT_EOF_CLUSTER) -+ return -ENOSPC; -+ } -+ -+ /* check cluster validation */ -+ if (hint_clu < EXFAT_FIRST_CLUSTER && hint_clu >= sbi->num_clusters) { -+ exfat_msg(sb, KERN_ERR, "hint_cluster is invalid (%u)\n", -+ hint_clu); -+ hint_clu = EXFAT_FIRST_CLUSTER; -+ if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { -+ if (exfat_chain_cont_cluster(sb, p_chain->dir, -+ num_clusters)) -+ return -EIO; -+ p_chain->flags = ALLOC_FAT_CHAIN; -+ } -+ } -+ -+ set_bit(EXFAT_SB_DIRTY, &sbi->s_state); -+ -+ p_chain->dir = EXFAT_EOF_CLUSTER; -+ -+ while ((new_clu = exfat_find_free_bitmap(sb, hint_clu)) != -+ EXFAT_EOF_CLUSTER) { -+ if (new_clu != hint_clu && -+ p_chain->flags == ALLOC_NO_FAT_CHAIN) { -+ if (exfat_chain_cont_cluster(sb, p_chain->dir, -+ num_clusters)) { -+ ret = -EIO; -+ goto free_cluster; -+ } -+ p_chain->flags = ALLOC_FAT_CHAIN; -+ } -+ -+ /* update allocation bitmap */ -+ if (exfat_set_bitmap(inode, new_clu)) { -+ ret = -EIO; -+ goto free_cluster; -+ } -+ -+ num_clusters++; -+ -+ /* update FAT table */ -+ if (p_chain->flags == ALLOC_FAT_CHAIN) { -+ if (exfat_ent_set(sb, new_clu, EXFAT_EOF_CLUSTER)) { -+ ret = -EIO; -+ goto free_cluster; -+ } -+ } -+ -+ if (p_chain->dir == EXFAT_EOF_CLUSTER) { -+ p_chain->dir = new_clu; -+ } else if (p_chain->flags == ALLOC_FAT_CHAIN) { -+ if (exfat_ent_set(sb, last_clu, new_clu)) { -+ ret = -EIO; -+ goto free_cluster; -+ } -+ } -+ last_clu = new_clu; -+ -+ if (--num_alloc == 0) { -+ sbi->clu_srch_ptr = hint_clu; -+ sbi->used_clusters += num_clusters; -+ -+ p_chain->size += num_clusters; -+ return 0; -+ } -+ -+ hint_clu = new_clu + 1; -+ if (hint_clu >= sbi->num_clusters) { -+ hint_clu = EXFAT_FIRST_CLUSTER; -+ -+ if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { -+ if (exfat_chain_cont_cluster(sb, p_chain->dir, -+ num_clusters)) { -+ ret = -EIO; -+ goto free_cluster; -+ } -+ p_chain->flags = ALLOC_FAT_CHAIN; -+ } -+ } -+ } -+free_cluster: -+ if (num_clusters) -+ exfat_free_cluster(inode, p_chain); -+ return ret; -+} -+ -+int exfat_count_num_clusters(struct super_block *sb, -+ struct exfat_chain *p_chain, unsigned int *ret_count) -+{ -+ unsigned int i, count; -+ unsigned int clu; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ -+ if (!p_chain->dir || p_chain->dir == EXFAT_EOF_CLUSTER) { -+ *ret_count = 0; -+ return 0; -+ } -+ -+ if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { -+ *ret_count = p_chain->size; -+ return 0; -+ } -+ -+ clu = p_chain->dir; -+ count = 0; -+ for (i = EXFAT_FIRST_CLUSTER; i < sbi->num_clusters; i++) { -+ count++; -+ if (exfat_ent_get(sb, clu, &clu)) -+ return -EIO; -+ if (clu == EXFAT_EOF_CLUSTER) -+ break; -+ } -+ -+ *ret_count = count; -+ return 0; -+} --- -2.25.1 - diff --git a/kernel/kernel/files/patches/mageia/fs-exfat-add-file-operations.patch b/kernel/kernel/files/patches/mageia/fs-exfat-add-file-operations.patch deleted file mode 100644 index 49fd0d83..00000000 --- a/kernel/kernel/files/patches/mageia/fs-exfat-add-file-operations.patch +++ /dev/null @@ -1,390 +0,0 @@ -From 98d917047e8b7f4bb2ff61d81b0ccd94a00444f9 Mon Sep 17 00:00:00 2001 -From: Namjae Jeon -Date: Mon, 2 Mar 2020 15:21:36 +0900 -Subject: [PATCH 05/14] exfat: add file operations -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This adds the implementation of file operations for exfat. - -Signed-off-by: Namjae Jeon -Signed-off-by: Sungjong Seo -Reviewed-by: Pali Rohár -Reviewed-by: Christoph Hellwig -Reviewed-by: Arnd Bergmann -Signed-off-by: Al Viro ---- - fs/exfat/file.c | 360 ++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 360 insertions(+) - create mode 100644 fs/exfat/file.c - -diff --git a/fs/exfat/file.c b/fs/exfat/file.c -new file mode 100644 -index 000000000000..483f683757aa ---- /dev/null -+++ b/fs/exfat/file.c -@@ -0,0 +1,360 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -+ */ -+ -+#include -+#include -+#include -+ -+#include "exfat_raw.h" -+#include "exfat_fs.h" -+ -+static int exfat_cont_expand(struct inode *inode, loff_t size) -+{ -+ struct address_space *mapping = inode->i_mapping; -+ loff_t start = i_size_read(inode), count = size - i_size_read(inode); -+ int err, err2; -+ -+ err = generic_cont_expand_simple(inode, size); -+ if (err) -+ return err; -+ -+ inode->i_ctime = inode->i_mtime = current_time(inode); -+ mark_inode_dirty(inode); -+ -+ if (!IS_SYNC(inode)) -+ return 0; -+ -+ err = filemap_fdatawrite_range(mapping, start, start + count - 1); -+ err2 = sync_mapping_buffers(mapping); -+ if (!err) -+ err = err2; -+ err2 = write_inode_now(inode, 1); -+ if (!err) -+ err = err2; -+ if (err) -+ return err; -+ -+ return filemap_fdatawait_range(mapping, start, start + count - 1); -+} -+ -+static bool exfat_allow_set_time(struct exfat_sb_info *sbi, struct inode *inode) -+{ -+ mode_t allow_utime = sbi->options.allow_utime; -+ -+ if (!uid_eq(current_fsuid(), inode->i_uid)) { -+ if (in_group_p(inode->i_gid)) -+ allow_utime >>= 3; -+ if (allow_utime & MAY_WRITE) -+ return true; -+ } -+ -+ /* use a default check */ -+ return false; -+} -+ -+static int exfat_sanitize_mode(const struct exfat_sb_info *sbi, -+ struct inode *inode, umode_t *mode_ptr) -+{ -+ mode_t i_mode, mask, perm; -+ -+ i_mode = inode->i_mode; -+ -+ mask = (S_ISREG(i_mode) || S_ISLNK(i_mode)) ? -+ sbi->options.fs_fmask : sbi->options.fs_dmask; -+ perm = *mode_ptr & ~(S_IFMT | mask); -+ -+ /* Of the r and x bits, all (subject to umask) must be present.*/ -+ if ((perm & 0555) != (i_mode & 0555)) -+ return -EPERM; -+ -+ if (exfat_mode_can_hold_ro(inode)) { -+ /* -+ * Of the w bits, either all (subject to umask) or none must -+ * be present. -+ */ -+ if ((perm & 0222) && ((perm & 0222) != (0222 & ~mask))) -+ return -EPERM; -+ } else { -+ /* -+ * If exfat_mode_can_hold_ro(inode) is false, can't change -+ * w bits. -+ */ -+ if ((perm & 0222) != (0222 & ~mask)) -+ return -EPERM; -+ } -+ -+ *mode_ptr &= S_IFMT | perm; -+ -+ return 0; -+} -+ -+/* resize the file length */ -+int __exfat_truncate(struct inode *inode, loff_t new_size) -+{ -+ unsigned int num_clusters_new, num_clusters_phys; -+ unsigned int last_clu = EXFAT_FREE_CLUSTER; -+ struct exfat_chain clu; -+ struct exfat_dentry *ep, *ep2; -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ struct exfat_entry_set_cache *es = NULL; -+ int evict = (ei->dir.dir == DIR_DELETED) ? 1 : 0; -+ -+ /* check if the given file ID is opened */ -+ if (ei->type != TYPE_FILE && ei->type != TYPE_DIR) -+ return -EPERM; -+ -+ exfat_set_vol_flags(sb, VOL_DIRTY); -+ -+ num_clusters_new = EXFAT_B_TO_CLU_ROUND_UP(i_size_read(inode), sbi); -+ num_clusters_phys = -+ EXFAT_B_TO_CLU_ROUND_UP(EXFAT_I(inode)->i_size_ondisk, sbi); -+ -+ exfat_chain_set(&clu, ei->start_clu, num_clusters_phys, ei->flags); -+ -+ if (new_size > 0) { -+ /* -+ * Truncate FAT chain num_clusters after the first cluster -+ * num_clusters = min(new, phys); -+ */ -+ unsigned int num_clusters = -+ min(num_clusters_new, num_clusters_phys); -+ -+ /* -+ * Follow FAT chain -+ * (defensive coding - works fine even with corrupted FAT table -+ */ -+ if (clu.flags == ALLOC_NO_FAT_CHAIN) { -+ clu.dir += num_clusters; -+ clu.size -= num_clusters; -+ } else { -+ while (num_clusters > 0) { -+ last_clu = clu.dir; -+ if (exfat_get_next_cluster(sb, &(clu.dir))) -+ return -EIO; -+ -+ num_clusters--; -+ clu.size--; -+ } -+ } -+ } else { -+ ei->flags = ALLOC_NO_FAT_CHAIN; -+ ei->start_clu = EXFAT_EOF_CLUSTER; -+ } -+ -+ i_size_write(inode, new_size); -+ -+ if (ei->type == TYPE_FILE) -+ ei->attr |= ATTR_ARCHIVE; -+ -+ /* update the directory entry */ -+ if (!evict) { -+ struct timespec64 ts; -+ -+ es = exfat_get_dentry_set(sb, &(ei->dir), ei->entry, -+ ES_ALL_ENTRIES, &ep); -+ if (!es) -+ return -EIO; -+ ep2 = ep + 1; -+ -+ ts = current_time(inode); -+ exfat_set_entry_time(sbi, &ts, -+ &ep->dentry.file.modify_tz, -+ &ep->dentry.file.modify_time, -+ &ep->dentry.file.modify_date, -+ &ep->dentry.file.modify_time_ms); -+ ep->dentry.file.attr = cpu_to_le16(ei->attr); -+ -+ /* File size should be zero if there is no cluster allocated */ -+ if (ei->start_clu == EXFAT_EOF_CLUSTER) { -+ ep->dentry.stream.valid_size = 0; -+ ep->dentry.stream.size = 0; -+ } else { -+ ep->dentry.stream.valid_size = cpu_to_le64(new_size); -+ ep->dentry.stream.size = ep->dentry.stream.valid_size; -+ } -+ -+ if (new_size == 0) { -+ /* Any directory can not be truncated to zero */ -+ WARN_ON(ei->type != TYPE_FILE); -+ -+ ep2->dentry.stream.flags = ALLOC_FAT_CHAIN; -+ ep2->dentry.stream.start_clu = EXFAT_FREE_CLUSTER; -+ } -+ -+ if (exfat_update_dir_chksum_with_entry_set(sb, es, -+ inode_needs_sync(inode))) -+ return -EIO; -+ kfree(es); -+ } -+ -+ /* cut off from the FAT chain */ -+ if (ei->flags == ALLOC_FAT_CHAIN && last_clu != EXFAT_FREE_CLUSTER && -+ last_clu != EXFAT_EOF_CLUSTER) { -+ if (exfat_ent_set(sb, last_clu, EXFAT_EOF_CLUSTER)) -+ return -EIO; -+ } -+ -+ /* invalidate cache and free the clusters */ -+ /* clear exfat cache */ -+ exfat_cache_inval_inode(inode); -+ -+ /* hint information */ -+ ei->hint_bmap.off = EXFAT_EOF_CLUSTER; -+ ei->hint_bmap.clu = EXFAT_EOF_CLUSTER; -+ if (ei->rwoffset > new_size) -+ ei->rwoffset = new_size; -+ -+ /* hint_stat will be used if this is directory. */ -+ ei->hint_stat.eidx = 0; -+ ei->hint_stat.clu = ei->start_clu; -+ ei->hint_femp.eidx = EXFAT_HINT_NONE; -+ -+ /* free the clusters */ -+ if (exfat_free_cluster(inode, &clu)) -+ return -EIO; -+ -+ exfat_set_vol_flags(sb, VOL_CLEAN); -+ -+ return 0; -+} -+ -+void exfat_truncate(struct inode *inode, loff_t size) -+{ -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ unsigned int blocksize = 1 << inode->i_blkbits; -+ loff_t aligned_size; -+ int err; -+ -+ mutex_lock(&sbi->s_lock); -+ if (EXFAT_I(inode)->start_clu == 0) { -+ /* -+ * Empty start_clu != ~0 (not allocated) -+ */ -+ exfat_fs_error(sb, "tried to truncate zeroed cluster."); -+ goto write_size; -+ } -+ -+ err = __exfat_truncate(inode, i_size_read(inode)); -+ if (err) -+ goto write_size; -+ -+ inode->i_ctime = inode->i_mtime = current_time(inode); -+ if (IS_DIRSYNC(inode)) -+ exfat_sync_inode(inode); -+ else -+ mark_inode_dirty(inode); -+ -+ inode->i_blocks = ((i_size_read(inode) + (sbi->cluster_size - 1)) & -+ ~(sbi->cluster_size - 1)) >> inode->i_blkbits; -+write_size: -+ aligned_size = i_size_read(inode); -+ if (aligned_size & (blocksize - 1)) { -+ aligned_size |= (blocksize - 1); -+ aligned_size++; -+ } -+ -+ if (EXFAT_I(inode)->i_size_ondisk > i_size_read(inode)) -+ EXFAT_I(inode)->i_size_ondisk = aligned_size; -+ -+ if (EXFAT_I(inode)->i_size_aligned > i_size_read(inode)) -+ EXFAT_I(inode)->i_size_aligned = aligned_size; -+ mutex_unlock(&sbi->s_lock); -+} -+ -+int exfat_getattr(const struct path *path, struct kstat *stat, -+ unsigned int request_mask, unsigned int query_flags) -+{ -+ struct inode *inode = d_backing_inode(path->dentry); -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ -+ generic_fillattr(inode, stat); -+ stat->result_mask |= STATX_BTIME; -+ stat->btime.tv_sec = ei->i_crtime.tv_sec; -+ stat->btime.tv_nsec = ei->i_crtime.tv_nsec; -+ stat->blksize = EXFAT_SB(inode->i_sb)->cluster_size; -+ return 0; -+} -+ -+int exfat_setattr(struct dentry *dentry, struct iattr *attr) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(dentry->d_sb); -+ struct inode *inode = dentry->d_inode; -+ unsigned int ia_valid; -+ int error; -+ -+ if ((attr->ia_valid & ATTR_SIZE) && -+ attr->ia_size > i_size_read(inode)) { -+ error = exfat_cont_expand(inode, attr->ia_size); -+ if (error || attr->ia_valid == ATTR_SIZE) -+ return error; -+ attr->ia_valid &= ~ATTR_SIZE; -+ } -+ -+ /* Check for setting the inode time. */ -+ ia_valid = attr->ia_valid; -+ if ((ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) && -+ exfat_allow_set_time(sbi, inode)) { -+ attr->ia_valid &= ~(ATTR_MTIME_SET | ATTR_ATIME_SET | -+ ATTR_TIMES_SET); -+ } -+ -+ error = setattr_prepare(dentry, attr); -+ attr->ia_valid = ia_valid; -+ if (error) -+ goto out; -+ -+ if (((attr->ia_valid & ATTR_UID) && -+ !uid_eq(attr->ia_uid, sbi->options.fs_uid)) || -+ ((attr->ia_valid & ATTR_GID) && -+ !gid_eq(attr->ia_gid, sbi->options.fs_gid)) || -+ ((attr->ia_valid & ATTR_MODE) && -+ (attr->ia_mode & ~(S_IFREG | S_IFLNK | S_IFDIR | 0777)))) { -+ error = -EPERM; -+ goto out; -+ } -+ -+ /* -+ * We don't return -EPERM here. Yes, strange, but this is too -+ * old behavior. -+ */ -+ if (attr->ia_valid & ATTR_MODE) { -+ if (exfat_sanitize_mode(sbi, inode, &attr->ia_mode) < 0) -+ attr->ia_valid &= ~ATTR_MODE; -+ } -+ -+ if (attr->ia_valid & ATTR_SIZE) { -+ error = exfat_block_truncate_page(inode, attr->ia_size); -+ if (error) -+ goto out; -+ -+ down_write(&EXFAT_I(inode)->truncate_lock); -+ truncate_setsize(inode, attr->ia_size); -+ exfat_truncate(inode, attr->ia_size); -+ up_write(&EXFAT_I(inode)->truncate_lock); -+ } -+ -+ setattr_copy(inode, attr); -+ mark_inode_dirty(inode); -+ -+out: -+ return error; -+} -+ -+const struct file_operations exfat_file_operations = { -+ .llseek = generic_file_llseek, -+ .read_iter = generic_file_read_iter, -+ .write_iter = generic_file_write_iter, -+ .mmap = generic_file_mmap, -+ .fsync = generic_file_fsync, -+ .splice_read = generic_file_splice_read, -+}; -+ -+const struct inode_operations exfat_file_inode_operations = { -+ .setattr = exfat_setattr, -+ .getattr = exfat_getattr, -+}; --- -2.25.1 - diff --git a/kernel/kernel/files/patches/mageia/fs-exfat-add-in-memory-and-on-disk-structures-and-heade.patch b/kernel/kernel/files/patches/mageia/fs-exfat-add-in-memory-and-on-disk-structures-and-heade.patch deleted file mode 100644 index e347a9ee..00000000 --- a/kernel/kernel/files/patches/mageia/fs-exfat-add-in-memory-and-on-disk-structures-and-heade.patch +++ /dev/null @@ -1,740 +0,0 @@ -From 1acf1a564b6034b5af1e7fb23cb98cb3bb4f6003 Mon Sep 17 00:00:00 2001 -From: Namjae Jeon -Date: Mon, 2 Mar 2020 15:21:32 +0900 -Subject: [PATCH 01/14] exfat: add in-memory and on-disk structures and headers -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This adds in-memory and on-disk structures and headers. - -Signed-off-by: Namjae Jeon -Signed-off-by: Sungjong Seo -Reviewed-by: Pali Rohár -Reviewed-by: Christoph Hellwig -Signed-off-by: Al Viro ---- - fs/exfat/exfat_fs.h | 519 +++++++++++++++++++++++++++++++++++++++++++ - fs/exfat/exfat_raw.h | 184 +++++++++++++++ - 2 files changed, 703 insertions(+) - create mode 100644 fs/exfat/exfat_fs.h - create mode 100644 fs/exfat/exfat_raw.h - -diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h -new file mode 100644 -index 000000000000..67d4e46fb810 ---- /dev/null -+++ b/fs/exfat/exfat_fs.h -@@ -0,0 +1,519 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -+ */ -+ -+#ifndef _EXFAT_FS_H -+#define _EXFAT_FS_H -+ -+#include -+#include -+#include -+ -+#define EXFAT_SUPER_MAGIC 0x2011BAB0UL -+#define EXFAT_ROOT_INO 1 -+ -+#define EXFAT_SB_DIRTY 0 -+ -+#define EXFAT_CLUSTERS_UNTRACKED (~0u) -+ -+/* -+ * exfat error flags -+ */ -+enum exfat_error_mode { -+ EXFAT_ERRORS_CONT, /* ignore error and continue */ -+ EXFAT_ERRORS_PANIC, /* panic on error */ -+ EXFAT_ERRORS_RO, /* remount r/o on error */ -+}; -+ -+/* -+ * exfat nls lossy flag -+ */ -+enum { -+ NLS_NAME_NO_LOSSY, /* no lossy */ -+ NLS_NAME_LOSSY, /* just detected incorrect filename(s) */ -+ NLS_NAME_OVERLEN, /* the length is over than its limit */ -+}; -+ -+#define EXFAT_HASH_BITS 8 -+#define EXFAT_HASH_SIZE (1UL << EXFAT_HASH_BITS) -+ -+/* -+ * Type Definitions -+ */ -+#define ES_2_ENTRIES 2 -+#define ES_ALL_ENTRIES 0 -+ -+#define DIR_DELETED 0xFFFF0321 -+ -+/* type values */ -+#define TYPE_UNUSED 0x0000 -+#define TYPE_DELETED 0x0001 -+#define TYPE_INVALID 0x0002 -+#define TYPE_CRITICAL_PRI 0x0100 -+#define TYPE_BITMAP 0x0101 -+#define TYPE_UPCASE 0x0102 -+#define TYPE_VOLUME 0x0103 -+#define TYPE_DIR 0x0104 -+#define TYPE_FILE 0x011F -+#define TYPE_CRITICAL_SEC 0x0200 -+#define TYPE_STREAM 0x0201 -+#define TYPE_EXTEND 0x0202 -+#define TYPE_ACL 0x0203 -+#define TYPE_BENIGN_PRI 0x0400 -+#define TYPE_GUID 0x0401 -+#define TYPE_PADDING 0x0402 -+#define TYPE_ACLTAB 0x0403 -+#define TYPE_BENIGN_SEC 0x0800 -+#define TYPE_ALL 0x0FFF -+ -+#define MAX_CHARSET_SIZE 6 /* max size of multi-byte character */ -+#define MAX_NAME_LENGTH 255 /* max len of file name excluding NULL */ -+#define MAX_VFSNAME_BUF_SIZE ((MAX_NAME_LENGTH + 1) * MAX_CHARSET_SIZE) -+ -+#define FAT_CACHE_SIZE 128 -+#define FAT_CACHE_HASH_SIZE 64 -+#define BUF_CACHE_SIZE 256 -+#define BUF_CACHE_HASH_SIZE 64 -+ -+#define EXFAT_HINT_NONE -1 -+#define EXFAT_MIN_SUBDIR 2 -+ -+/* -+ * helpers for cluster size to byte conversion. -+ */ -+#define EXFAT_CLU_TO_B(b, sbi) ((b) << (sbi)->cluster_size_bits) -+#define EXFAT_B_TO_CLU(b, sbi) ((b) >> (sbi)->cluster_size_bits) -+#define EXFAT_B_TO_CLU_ROUND_UP(b, sbi) \ -+ (((b - 1) >> (sbi)->cluster_size_bits) + 1) -+#define EXFAT_CLU_OFFSET(off, sbi) ((off) & ((sbi)->cluster_size - 1)) -+ -+/* -+ * helpers for block size to byte conversion. -+ */ -+#define EXFAT_BLK_TO_B(b, sb) ((b) << (sb)->s_blocksize_bits) -+#define EXFAT_B_TO_BLK(b, sb) ((b) >> (sb)->s_blocksize_bits) -+#define EXFAT_B_TO_BLK_ROUND_UP(b, sb) \ -+ (((b - 1) >> (sb)->s_blocksize_bits) + 1) -+#define EXFAT_BLK_OFFSET(off, sb) ((off) & ((sb)->s_blocksize - 1)) -+ -+/* -+ * helpers for block size to dentry size conversion. -+ */ -+#define EXFAT_B_TO_DEN_IDX(b, sbi) \ -+ ((b) << ((sbi)->cluster_size_bits - DENTRY_SIZE_BITS)) -+#define EXFAT_B_TO_DEN(b) ((b) >> DENTRY_SIZE_BITS) -+#define EXFAT_DEN_TO_B(b) ((b) << DENTRY_SIZE_BITS) -+ -+/* -+ * helpers for fat entry. -+ */ -+#define FAT_ENT_SIZE (4) -+#define FAT_ENT_SIZE_BITS (2) -+#define FAT_ENT_OFFSET_SECTOR(sb, loc) (EXFAT_SB(sb)->FAT1_start_sector + \ -+ (((u64)loc << FAT_ENT_SIZE_BITS) >> sb->s_blocksize_bits)) -+#define FAT_ENT_OFFSET_BYTE_IN_SECTOR(sb, loc) \ -+ ((loc << FAT_ENT_SIZE_BITS) & (sb->s_blocksize - 1)) -+ -+/* -+ * helpers for bitmap. -+ */ -+#define CLUSTER_TO_BITMAP_ENT(clu) ((clu) - EXFAT_RESERVED_CLUSTERS) -+#define BITMAP_ENT_TO_CLUSTER(ent) ((ent) + EXFAT_RESERVED_CLUSTERS) -+#define BITS_PER_SECTOR(sb) ((sb)->s_blocksize * BITS_PER_BYTE) -+#define BITS_PER_SECTOR_MASK(sb) (BITS_PER_SECTOR(sb) - 1) -+#define BITMAP_OFFSET_SECTOR_INDEX(sb, ent) \ -+ ((ent / BITS_PER_BYTE) >> (sb)->s_blocksize_bits) -+#define BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent) (ent & BITS_PER_SECTOR_MASK(sb)) -+#define BITMAP_OFFSET_BYTE_IN_SECTOR(sb, ent) \ -+ ((ent / BITS_PER_BYTE) & ((sb)->s_blocksize - 1)) -+#define BITS_PER_BYTE_MASK 0x7 -+#define IGNORED_BITS_REMAINED(clu, clu_base) ((1 << ((clu) - (clu_base))) - 1) -+ -+struct exfat_dentry_namebuf { -+ char *lfn; -+ int lfnbuf_len; /* usally MAX_UNINAME_BUF_SIZE */ -+}; -+ -+/* unicode name structure */ -+struct exfat_uni_name { -+ /* +3 for null and for converting */ -+ unsigned short name[MAX_NAME_LENGTH + 3]; -+ unsigned short name_hash; -+ unsigned char name_len; -+}; -+ -+/* directory structure */ -+struct exfat_chain { -+ unsigned int dir; -+ unsigned int size; -+ unsigned char flags; -+}; -+ -+/* first empty entry hint information */ -+struct exfat_hint_femp { -+ /* entry index of a directory */ -+ int eidx; -+ /* count of continuous empty entry */ -+ int count; -+ /* the cluster that first empty slot exists in */ -+ struct exfat_chain cur; -+}; -+ -+/* hint structure */ -+struct exfat_hint { -+ unsigned int clu; -+ union { -+ unsigned int off; /* cluster offset */ -+ int eidx; /* entry index */ -+ }; -+}; -+ -+struct exfat_entry_set_cache { -+ /* sector number that contains file_entry */ -+ sector_t sector; -+ /* byte offset in the sector */ -+ unsigned int offset; -+ /* flag in stream entry. 01 for cluster chain, 03 for contig. */ -+ int alloc_flag; -+ unsigned int num_entries; -+ struct exfat_dentry entries[]; -+}; -+ -+struct exfat_dir_entry { -+ struct exfat_chain dir; -+ int entry; -+ unsigned int type; -+ unsigned int start_clu; -+ unsigned char flags; -+ unsigned short attr; -+ loff_t size; -+ unsigned int num_subdirs; -+ struct timespec64 atime; -+ struct timespec64 mtime; -+ struct timespec64 crtime; -+ struct exfat_dentry_namebuf namebuf; -+}; -+ -+/* -+ * exfat mount in-memory data -+ */ -+struct exfat_mount_options { -+ kuid_t fs_uid; -+ kgid_t fs_gid; -+ unsigned short fs_fmask; -+ unsigned short fs_dmask; -+ /* permission for setting the [am]time */ -+ unsigned short allow_utime; -+ /* charset for filename input/display */ -+ char *iocharset; -+ /* on error: continue, panic, remount-ro */ -+ enum exfat_error_mode errors; -+ unsigned utf8:1, /* Use of UTF-8 character set */ -+ discard:1; /* Issue discard requests on deletions */ -+ int time_offset; /* Offset of timestamps from UTC (in minutes) */ -+}; -+ -+/* -+ * EXFAT file system superblock in-memory data -+ */ -+struct exfat_sb_info { -+ unsigned long long num_sectors; /* num of sectors in volume */ -+ unsigned int num_clusters; /* num of clusters in volume */ -+ unsigned int cluster_size; /* cluster size in bytes */ -+ unsigned int cluster_size_bits; -+ unsigned int sect_per_clus; /* cluster size in sectors */ -+ unsigned int sect_per_clus_bits; -+ unsigned long long FAT1_start_sector; /* FAT1 start sector */ -+ unsigned long long FAT2_start_sector; /* FAT2 start sector */ -+ unsigned long long data_start_sector; /* data area start sector */ -+ unsigned int num_FAT_sectors; /* num of FAT sectors */ -+ unsigned int root_dir; /* root dir cluster */ -+ unsigned int dentries_per_clu; /* num of dentries per cluster */ -+ unsigned int vol_flag; /* volume dirty flag */ -+ struct buffer_head *pbr_bh; /* buffer_head of PBR sector */ -+ -+ unsigned int map_clu; /* allocation bitmap start cluster */ -+ unsigned int map_sectors; /* num of allocation bitmap sectors */ -+ struct buffer_head **vol_amap; /* allocation bitmap */ -+ -+ unsigned short *vol_utbl; /* upcase table */ -+ -+ unsigned int clu_srch_ptr; /* cluster search pointer */ -+ unsigned int used_clusters; /* number of used clusters */ -+ -+ unsigned long s_state; -+ struct mutex s_lock; /* superblock lock */ -+ struct exfat_mount_options options; -+ struct nls_table *nls_io; /* Charset used for input and display */ -+ struct ratelimit_state ratelimit; -+ -+ spinlock_t inode_hash_lock; -+ struct hlist_head inode_hashtable[EXFAT_HASH_SIZE]; -+ -+ struct rcu_head rcu; -+}; -+ -+/* -+ * EXFAT file system inode in-memory data -+ */ -+struct exfat_inode_info { -+ struct exfat_chain dir; -+ int entry; -+ unsigned int type; -+ unsigned short attr; -+ unsigned int start_clu; -+ unsigned char flags; -+ /* -+ * the copy of low 32bit of i_version to check -+ * the validation of hint_stat. -+ */ -+ unsigned int version; -+ /* file offset or dentry index for readdir */ -+ loff_t rwoffset; -+ -+ /* hint for cluster last accessed */ -+ struct exfat_hint hint_bmap; -+ /* hint for entry index we try to lookup next time */ -+ struct exfat_hint hint_stat; -+ /* hint for first empty entry */ -+ struct exfat_hint_femp hint_femp; -+ -+ spinlock_t cache_lru_lock; -+ struct list_head cache_lru; -+ int nr_caches; -+ /* for avoiding the race between alloc and free */ -+ unsigned int cache_valid_id; -+ -+ /* -+ * NOTE: i_size_ondisk is 64bits, so must hold ->inode_lock to access. -+ * physically allocated size. -+ */ -+ loff_t i_size_ondisk; -+ /* block-aligned i_size (used in cont_write_begin) */ -+ loff_t i_size_aligned; -+ /* on-disk position of directory entry or 0 */ -+ loff_t i_pos; -+ /* hash by i_location */ -+ struct hlist_node i_hash_fat; -+ /* protect bmap against truncate */ -+ struct rw_semaphore truncate_lock; -+ struct inode vfs_inode; -+ /* File creation time */ -+ struct timespec64 i_crtime; -+}; -+ -+static inline struct exfat_sb_info *EXFAT_SB(struct super_block *sb) -+{ -+ return sb->s_fs_info; -+} -+ -+static inline struct exfat_inode_info *EXFAT_I(struct inode *inode) -+{ -+ return container_of(inode, struct exfat_inode_info, vfs_inode); -+} -+ -+/* -+ * If ->i_mode can't hold 0222 (i.e. ATTR_RO), we use ->i_attrs to -+ * save ATTR_RO instead of ->i_mode. -+ * -+ * If it's directory and !sbi->options.rodir, ATTR_RO isn't read-only -+ * bit, it's just used as flag for app. -+ */ -+static inline int exfat_mode_can_hold_ro(struct inode *inode) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); -+ -+ if (S_ISDIR(inode->i_mode)) -+ return 0; -+ -+ if ((~sbi->options.fs_fmask) & 0222) -+ return 1; -+ return 0; -+} -+ -+/* Convert attribute bits and a mask to the UNIX mode. */ -+static inline mode_t exfat_make_mode(struct exfat_sb_info *sbi, -+ unsigned short attr, mode_t mode) -+{ -+ if ((attr & ATTR_READONLY) && !(attr & ATTR_SUBDIR)) -+ mode &= ~0222; -+ -+ if (attr & ATTR_SUBDIR) -+ return (mode & ~sbi->options.fs_dmask) | S_IFDIR; -+ -+ return (mode & ~sbi->options.fs_fmask) | S_IFREG; -+} -+ -+/* Return the FAT attribute byte for this inode */ -+static inline unsigned short exfat_make_attr(struct inode *inode) -+{ -+ unsigned short attr = EXFAT_I(inode)->attr; -+ -+ if (S_ISDIR(inode->i_mode)) -+ attr |= ATTR_SUBDIR; -+ if (exfat_mode_can_hold_ro(inode) && !(inode->i_mode & 0222)) -+ attr |= ATTR_READONLY; -+ return attr; -+} -+ -+static inline void exfat_save_attr(struct inode *inode, unsigned short attr) -+{ -+ if (exfat_mode_can_hold_ro(inode)) -+ EXFAT_I(inode)->attr = attr & (ATTR_RWMASK | ATTR_READONLY); -+ else -+ EXFAT_I(inode)->attr = attr & ATTR_RWMASK; -+} -+ -+static inline bool exfat_is_last_sector_in_cluster(struct exfat_sb_info *sbi, -+ sector_t sec) -+{ -+ return ((sec - sbi->data_start_sector + 1) & -+ ((1 << sbi->sect_per_clus_bits) - 1)) == 0; -+} -+ -+static inline sector_t exfat_cluster_to_sector(struct exfat_sb_info *sbi, -+ unsigned int clus) -+{ -+ return ((clus - EXFAT_RESERVED_CLUSTERS) << sbi->sect_per_clus_bits) + -+ sbi->data_start_sector; -+} -+ -+static inline int exfat_sector_to_cluster(struct exfat_sb_info *sbi, -+ sector_t sec) -+{ -+ return ((sec - sbi->data_start_sector) >> sbi->sect_per_clus_bits) + -+ EXFAT_RESERVED_CLUSTERS; -+} -+ -+/* super.c */ -+int exfat_set_vol_flags(struct super_block *sb, unsigned short new_flag); -+ -+/* fatent.c */ -+#define exfat_get_next_cluster(sb, pclu) exfat_ent_get(sb, *(pclu), pclu) -+ -+int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc, -+ struct exfat_chain *p_chain); -+int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain); -+int exfat_ent_get(struct super_block *sb, unsigned int loc, -+ unsigned int *content); -+int exfat_ent_set(struct super_block *sb, unsigned int loc, -+ unsigned int content); -+int exfat_count_ext_entries(struct super_block *sb, struct exfat_chain *p_dir, -+ int entry, struct exfat_dentry *p_entry); -+int exfat_chain_cont_cluster(struct super_block *sb, unsigned int chain, -+ unsigned int len); -+int exfat_zeroed_cluster(struct inode *dir, unsigned int clu); -+int exfat_find_last_cluster(struct super_block *sb, struct exfat_chain *p_chain, -+ unsigned int *ret_clu); -+int exfat_count_num_clusters(struct super_block *sb, -+ struct exfat_chain *p_chain, unsigned int *ret_count); -+ -+/* balloc.c */ -+int exfat_load_bitmap(struct super_block *sb); -+void exfat_free_bitmap(struct exfat_sb_info *sbi); -+int exfat_set_bitmap(struct inode *inode, unsigned int clu); -+void exfat_clear_bitmap(struct inode *inode, unsigned int clu); -+unsigned int exfat_find_free_bitmap(struct super_block *sb, unsigned int clu); -+int exfat_count_used_clusters(struct super_block *sb, unsigned int *ret_count); -+ -+/* file.c */ -+extern const struct file_operations exfat_file_operations; -+int __exfat_truncate(struct inode *inode, loff_t new_size); -+void exfat_truncate(struct inode *inode, loff_t size); -+int exfat_setattr(struct dentry *dentry, struct iattr *attr); -+int exfat_getattr(const struct path *path, struct kstat *stat, -+ unsigned int request_mask, unsigned int query_flags); -+ -+/* namei.c */ -+extern const struct dentry_operations exfat_dentry_ops; -+extern const struct dentry_operations exfat_utf8_dentry_ops; -+ -+/* cache.c */ -+int exfat_cache_init(void); -+void exfat_cache_shutdown(void); -+void exfat_cache_init_inode(struct inode *inode); -+void exfat_cache_inval_inode(struct inode *inode); -+int exfat_get_cluster(struct inode *inode, unsigned int cluster, -+ unsigned int *fclus, unsigned int *dclus, -+ unsigned int *last_dclus, int allow_eof); -+ -+/* dir.c */ -+extern const struct inode_operations exfat_dir_inode_operations; -+extern const struct file_operations exfat_dir_operations; -+unsigned int exfat_get_entry_type(struct exfat_dentry *p_entry); -+int exfat_init_dir_entry(struct inode *inode, struct exfat_chain *p_dir, -+ int entry, unsigned int type, unsigned int start_clu, -+ unsigned long long size); -+int exfat_init_ext_entry(struct inode *inode, struct exfat_chain *p_dir, -+ int entry, int num_entries, struct exfat_uni_name *p_uniname); -+int exfat_remove_entries(struct inode *inode, struct exfat_chain *p_dir, -+ int entry, int order, int num_entries); -+int exfat_update_dir_chksum(struct inode *inode, struct exfat_chain *p_dir, -+ int entry); -+int exfat_update_dir_chksum_with_entry_set(struct super_block *sb, -+ struct exfat_entry_set_cache *es, int sync); -+int exfat_calc_num_entries(struct exfat_uni_name *p_uniname); -+int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei, -+ struct exfat_chain *p_dir, struct exfat_uni_name *p_uniname, -+ int num_entries, unsigned int type); -+int exfat_alloc_new_dir(struct inode *inode, struct exfat_chain *clu); -+int exfat_find_location(struct super_block *sb, struct exfat_chain *p_dir, -+ int entry, sector_t *sector, int *offset); -+struct exfat_dentry *exfat_get_dentry(struct super_block *sb, -+ struct exfat_chain *p_dir, int entry, struct buffer_head **bh, -+ sector_t *sector); -+struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb, -+ struct exfat_chain *p_dir, int entry, unsigned int type, -+ struct exfat_dentry **file_ep); -+int exfat_count_dir_entries(struct super_block *sb, struct exfat_chain *p_dir); -+ -+/* inode.c */ -+extern const struct inode_operations exfat_file_inode_operations; -+void exfat_sync_inode(struct inode *inode); -+struct inode *exfat_build_inode(struct super_block *sb, -+ struct exfat_dir_entry *info, loff_t i_pos); -+void exfat_hash_inode(struct inode *inode, loff_t i_pos); -+void exfat_unhash_inode(struct inode *inode); -+struct inode *exfat_iget(struct super_block *sb, loff_t i_pos); -+int exfat_write_inode(struct inode *inode, struct writeback_control *wbc); -+void exfat_evict_inode(struct inode *inode); -+int exfat_block_truncate_page(struct inode *inode, loff_t from); -+ -+/* exfat/nls.c */ -+unsigned short exfat_toupper(struct super_block *sb, unsigned short a); -+int exfat_uniname_ncmp(struct super_block *sb, unsigned short *a, -+ unsigned short *b, unsigned int len); -+int exfat_utf16_to_nls(struct super_block *sb, -+ struct exfat_uni_name *uniname, unsigned char *p_cstring, -+ int len); -+int exfat_nls_to_utf16(struct super_block *sb, -+ const unsigned char *p_cstring, const int len, -+ struct exfat_uni_name *uniname, int *p_lossy); -+int exfat_create_upcase_table(struct super_block *sb); -+void exfat_free_upcase_table(struct exfat_sb_info *sbi); -+unsigned short exfat_high_surrogate(unicode_t u); -+unsigned short exfat_low_surrogate(unicode_t u); -+ -+/* exfat/misc.c */ -+void __exfat_fs_error(struct super_block *sb, int report, const char *fmt, ...) -+ __printf(3, 4) __cold; -+#define exfat_fs_error(sb, fmt, args...) \ -+ __exfat_fs_error(sb, 1, fmt, ## args) -+#define exfat_fs_error_ratelimit(sb, fmt, args...) \ -+ __exfat_fs_error(sb, __ratelimit(&EXFAT_SB(sb)->ratelimit), \ -+ fmt, ## args) -+void exfat_msg(struct super_block *sb, const char *lv, const char *fmt, ...) -+ __printf(3, 4) __cold; -+void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, -+ u8 tz, __le16 time, __le16 date, u8 time_ms); -+void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, -+ u8 *tz, __le16 *time, __le16 *date, u8 *time_ms); -+unsigned short exfat_calc_chksum_2byte(void *data, int len, -+ unsigned short chksum, int type); -+void exfat_update_bh(struct super_block *sb, struct buffer_head *bh, int sync); -+void exfat_chain_set(struct exfat_chain *ec, unsigned int dir, -+ unsigned int size, unsigned char flags); -+void exfat_chain_dup(struct exfat_chain *dup, struct exfat_chain *ec); -+ -+#endif /* !_EXFAT_FS_H */ -diff --git a/fs/exfat/exfat_raw.h b/fs/exfat/exfat_raw.h -new file mode 100644 -index 000000000000..2a841010e649 ---- /dev/null -+++ b/fs/exfat/exfat_raw.h -@@ -0,0 +1,184 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -+ */ -+ -+#ifndef _EXFAT_RAW_H -+#define _EXFAT_RAW_H -+ -+#include -+ -+#define PBR_SIGNATURE 0xAA55 -+ -+#define EXFAT_MAX_FILE_LEN 255 -+ -+#define VOL_CLEAN 0x0000 -+#define VOL_DIRTY 0x0002 -+ -+#define EXFAT_EOF_CLUSTER 0xFFFFFFFFu -+#define EXFAT_BAD_CLUSTER 0xFFFFFFF7u -+#define EXFAT_FREE_CLUSTER 0 -+/* Cluster 0, 1 are reserved, the first cluster is 2 in the cluster heap. */ -+#define EXFAT_RESERVED_CLUSTERS 2 -+#define EXFAT_FIRST_CLUSTER 2 -+#define EXFAT_DATA_CLUSTER_COUNT(sbi) \ -+ ((sbi)->num_clusters - EXFAT_RESERVED_CLUSTERS) -+ -+/* AllocationPossible and NoFatChain field in GeneralSecondaryFlags Field */ -+#define ALLOC_FAT_CHAIN 0x01 -+#define ALLOC_NO_FAT_CHAIN 0x03 -+ -+#define DENTRY_SIZE 32 /* directory entry size */ -+#define DENTRY_SIZE_BITS 5 -+/* exFAT allows 8388608(256MB) directory entries */ -+#define MAX_EXFAT_DENTRIES 8388608 -+ -+/* dentry types */ -+#define EXFAT_UNUSED 0x00 /* end of directory */ -+#define EXFAT_DELETE (~0x80) -+#define IS_EXFAT_DELETED(x) ((x) < 0x80) /* deleted file (0x01~0x7F) */ -+#define EXFAT_INVAL 0x80 /* invalid value */ -+#define EXFAT_BITMAP 0x81 /* allocation bitmap */ -+#define EXFAT_UPCASE 0x82 /* upcase table */ -+#define EXFAT_VOLUME 0x83 /* volume label */ -+#define EXFAT_FILE 0x85 /* file or dir */ -+#define EXFAT_GUID 0xA0 -+#define EXFAT_PADDING 0xA1 -+#define EXFAT_ACLTAB 0xA2 -+#define EXFAT_STREAM 0xC0 /* stream entry */ -+#define EXFAT_NAME 0xC1 /* file name entry */ -+#define EXFAT_ACL 0xC2 /* stream entry */ -+ -+#define IS_EXFAT_CRITICAL_PRI(x) (x < 0xA0) -+#define IS_EXFAT_BENIGN_PRI(x) (x < 0xC0) -+#define IS_EXFAT_CRITICAL_SEC(x) (x < 0xE0) -+ -+/* checksum types */ -+#define CS_DIR_ENTRY 0 -+#define CS_PBR_SECTOR 1 -+#define CS_DEFAULT 2 -+ -+/* file attributes */ -+#define ATTR_READONLY 0x0001 -+#define ATTR_HIDDEN 0x0002 -+#define ATTR_SYSTEM 0x0004 -+#define ATTR_VOLUME 0x0008 -+#define ATTR_SUBDIR 0x0010 -+#define ATTR_ARCHIVE 0x0020 -+ -+#define ATTR_RWMASK (ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME | \ -+ ATTR_SUBDIR | ATTR_ARCHIVE) -+ -+#define PBR64_JUMP_BOOT_LEN 3 -+#define PBR64_OEM_NAME_LEN 8 -+#define PBR64_RESERVED_LEN 53 -+ -+#define EXFAT_FILE_NAME_LEN 15 -+ -+/* EXFAT BIOS parameter block (64 bytes) */ -+struct bpb64 { -+ __u8 jmp_boot[PBR64_JUMP_BOOT_LEN]; -+ __u8 oem_name[PBR64_OEM_NAME_LEN]; -+ __u8 res_zero[PBR64_RESERVED_LEN]; -+} __packed; -+ -+/* EXFAT EXTEND BIOS parameter block (56 bytes) */ -+struct bsx64 { -+ __le64 vol_offset; -+ __le64 vol_length; -+ __le32 fat_offset; -+ __le32 fat_length; -+ __le32 clu_offset; -+ __le32 clu_count; -+ __le32 root_cluster; -+ __le32 vol_serial; -+ __u8 fs_version[2]; -+ __le16 vol_flags; -+ __u8 sect_size_bits; -+ __u8 sect_per_clus_bits; -+ __u8 num_fats; -+ __u8 phy_drv_no; -+ __u8 perc_in_use; -+ __u8 reserved2[7]; -+} __packed; -+ -+/* EXFAT PBR[BPB+BSX] (120 bytes) */ -+struct pbr64 { -+ struct bpb64 bpb; -+ struct bsx64 bsx; -+} __packed; -+ -+/* Common PBR[Partition Boot Record] (512 bytes) */ -+struct pbr { -+ union { -+ __u8 raw[64]; -+ struct bpb64 f64; -+ } bpb; -+ union { -+ __u8 raw[56]; -+ struct bsx64 f64; -+ } bsx; -+ __u8 boot_code[390]; -+ __le16 signature; -+} __packed; -+ -+struct exfat_dentry { -+ __u8 type; -+ union { -+ struct { -+ __u8 num_ext; -+ __le16 checksum; -+ __le16 attr; -+ __le16 reserved1; -+ __le16 create_time; -+ __le16 create_date; -+ __le16 modify_time; -+ __le16 modify_date; -+ __le16 access_time; -+ __le16 access_date; -+ __u8 create_time_ms; -+ __u8 modify_time_ms; -+ __u8 create_tz; -+ __u8 modify_tz; -+ __u8 access_tz; -+ __u8 reserved2[7]; -+ } __packed file; /* file directory entry */ -+ struct { -+ __u8 flags; -+ __u8 reserved1; -+ __u8 name_len; -+ __le16 name_hash; -+ __le16 reserved2; -+ __le64 valid_size; -+ __le32 reserved3; -+ __le32 start_clu; -+ __le64 size; -+ } __packed stream; /* stream extension directory entry */ -+ struct { -+ __u8 flags; -+ __le16 unicode_0_14[EXFAT_FILE_NAME_LEN]; -+ } __packed name; /* file name directory entry */ -+ struct { -+ __u8 flags; -+ __u8 reserved[18]; -+ __le32 start_clu; -+ __le64 size; -+ } __packed bitmap; /* allocation bitmap directory entry */ -+ struct { -+ __u8 reserved1[3]; -+ __le32 checksum; -+ __u8 reserved2[12]; -+ __le32 start_clu; -+ __le64 size; -+ } __packed upcase; /* up-case table directory entry */ -+ } __packed dentry; -+} __packed; -+ -+#define EXFAT_TZ_VALID (1 << 7) -+ -+/* Jan 1 GMT 00:00:00 1980 */ -+#define EXFAT_MIN_TIMESTAMP_SECS 315532800LL -+/* Dec 31 GMT 23:59:59 2107 */ -+#define EXFAT_MAX_TIMESTAMP_SECS 4354819199LL -+ -+#endif /* !_EXFAT_RAW_H */ --- -2.25.1 - diff --git a/kernel/kernel/files/patches/mageia/fs-exfat-add-inode-operations.patch b/kernel/kernel/files/patches/mageia/fs-exfat-add-inode-operations.patch deleted file mode 100644 index 0b47e8a9..00000000 --- a/kernel/kernel/files/patches/mageia/fs-exfat-add-inode-operations.patch +++ /dev/null @@ -1,2156 +0,0 @@ -From 5f2aa075070cf5b2e6aae011d5a3390408d7d913 Mon Sep 17 00:00:00 2001 -From: Namjae Jeon -Date: Mon, 2 Mar 2020 15:21:34 +0900 -Subject: [PATCH 03/14] exfat: add inode operations -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This adds the implementation of inode operations for exfat. - -Signed-off-by: Namjae Jeon -Signed-off-by: Sungjong Seo -Reviewed-by: Pali Rohár -Reviewed-by: Christoph Hellwig -Signed-off-by: Al Viro ---- - fs/exfat/inode.c | 671 +++++++++++++++++++++ - fs/exfat/namei.c | 1448 ++++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 2119 insertions(+) - create mode 100644 fs/exfat/inode.c - create mode 100644 fs/exfat/namei.c - -diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c -new file mode 100644 -index 000000000000..06887492f54b ---- /dev/null -+++ b/fs/exfat/inode.c -@@ -0,0 +1,671 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "exfat_raw.h" -+#include "exfat_fs.h" -+ -+static int __exfat_write_inode(struct inode *inode, int sync) -+{ -+ int ret = -EIO; -+ unsigned long long on_disk_size; -+ struct exfat_dentry *ep, *ep2; -+ struct exfat_entry_set_cache *es = NULL; -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ bool is_dir = (ei->type == TYPE_DIR) ? true : false; -+ -+ if (inode->i_ino == EXFAT_ROOT_INO) -+ return 0; -+ -+ /* -+ * If the indode is already unlinked, there is no need for updating it. -+ */ -+ if (ei->dir.dir == DIR_DELETED) -+ return 0; -+ -+ if (is_dir && ei->dir.dir == sbi->root_dir && ei->entry == -1) -+ return 0; -+ -+ exfat_set_vol_flags(sb, VOL_DIRTY); -+ -+ /* get the directory entry of given file or directory */ -+ es = exfat_get_dentry_set(sb, &(ei->dir), ei->entry, ES_ALL_ENTRIES, -+ &ep); -+ if (!es) -+ return -EIO; -+ ep2 = ep + 1; -+ -+ ep->dentry.file.attr = cpu_to_le16(exfat_make_attr(inode)); -+ -+ /* set FILE_INFO structure using the acquired struct exfat_dentry */ -+ exfat_set_entry_time(sbi, &ei->i_crtime, -+ &ep->dentry.file.create_tz, -+ &ep->dentry.file.create_time, -+ &ep->dentry.file.create_date, -+ &ep->dentry.file.create_time_ms); -+ exfat_set_entry_time(sbi, &inode->i_mtime, -+ &ep->dentry.file.modify_tz, -+ &ep->dentry.file.modify_time, -+ &ep->dentry.file.modify_date, -+ &ep->dentry.file.modify_time_ms); -+ exfat_set_entry_time(sbi, &inode->i_atime, -+ &ep->dentry.file.access_tz, -+ &ep->dentry.file.access_time, -+ &ep->dentry.file.access_date, -+ NULL); -+ -+ /* File size should be zero if there is no cluster allocated */ -+ on_disk_size = i_size_read(inode); -+ -+ if (ei->start_clu == EXFAT_EOF_CLUSTER) -+ on_disk_size = 0; -+ -+ ep2->dentry.stream.valid_size = cpu_to_le64(on_disk_size); -+ ep2->dentry.stream.size = ep2->dentry.stream.valid_size; -+ -+ ret = exfat_update_dir_chksum_with_entry_set(sb, es, sync); -+ kfree(es); -+ return ret; -+} -+ -+int exfat_write_inode(struct inode *inode, struct writeback_control *wbc) -+{ -+ int ret; -+ -+ mutex_lock(&EXFAT_SB(inode->i_sb)->s_lock); -+ ret = __exfat_write_inode(inode, wbc->sync_mode == WB_SYNC_ALL); -+ mutex_unlock(&EXFAT_SB(inode->i_sb)->s_lock); -+ -+ return ret; -+} -+ -+void exfat_sync_inode(struct inode *inode) -+{ -+ lockdep_assert_held(&EXFAT_SB(inode->i_sb)->s_lock); -+ __exfat_write_inode(inode, 1); -+} -+ -+/* -+ * Input: inode, (logical) clu_offset, target allocation area -+ * Output: errcode, cluster number -+ * *clu = (~0), if it's unable to allocate a new cluster -+ */ -+static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset, -+ unsigned int *clu, int create) -+{ -+ int ret, modified = false; -+ unsigned int last_clu; -+ struct exfat_chain new_clu; -+ struct exfat_dentry *ep; -+ struct exfat_entry_set_cache *es = NULL; -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ unsigned int local_clu_offset = clu_offset; -+ unsigned int num_to_be_allocated = 0, num_clusters = 0; -+ -+ ei->rwoffset = EXFAT_CLU_TO_B(clu_offset, sbi); -+ -+ if (EXFAT_I(inode)->i_size_ondisk > 0) -+ num_clusters = -+ EXFAT_B_TO_CLU_ROUND_UP(EXFAT_I(inode)->i_size_ondisk, -+ sbi); -+ -+ if (clu_offset >= num_clusters) -+ num_to_be_allocated = clu_offset - num_clusters + 1; -+ -+ if (!create && (num_to_be_allocated > 0)) { -+ *clu = EXFAT_EOF_CLUSTER; -+ return 0; -+ } -+ -+ *clu = last_clu = ei->start_clu; -+ -+ if (ei->flags == ALLOC_NO_FAT_CHAIN) { -+ if (clu_offset > 0 && *clu != EXFAT_EOF_CLUSTER) { -+ last_clu += clu_offset - 1; -+ -+ if (clu_offset == num_clusters) -+ *clu = EXFAT_EOF_CLUSTER; -+ else -+ *clu += clu_offset; -+ } -+ } else if (ei->type == TYPE_FILE) { -+ unsigned int fclus = 0; -+ int err = exfat_get_cluster(inode, clu_offset, -+ &fclus, clu, &last_clu, 1); -+ if (err) -+ return -EIO; -+ -+ clu_offset -= fclus; -+ } else { -+ /* hint information */ -+ if (clu_offset > 0 && ei->hint_bmap.off != EXFAT_EOF_CLUSTER && -+ ei->hint_bmap.off > 0 && clu_offset >= ei->hint_bmap.off) { -+ clu_offset -= ei->hint_bmap.off; -+ /* hint_bmap.clu should be valid */ -+ WARN_ON(ei->hint_bmap.clu < 2); -+ *clu = ei->hint_bmap.clu; -+ } -+ -+ while (clu_offset > 0 && *clu != EXFAT_EOF_CLUSTER) { -+ last_clu = *clu; -+ if (exfat_get_next_cluster(sb, clu)) -+ return -EIO; -+ clu_offset--; -+ } -+ } -+ -+ if (*clu == EXFAT_EOF_CLUSTER) { -+ exfat_set_vol_flags(sb, VOL_DIRTY); -+ -+ new_clu.dir = (last_clu == EXFAT_EOF_CLUSTER) ? -+ EXFAT_EOF_CLUSTER : last_clu + 1; -+ new_clu.size = 0; -+ new_clu.flags = ei->flags; -+ -+ /* allocate a cluster */ -+ if (num_to_be_allocated < 1) { -+ /* Broken FAT (i_sze > allocated FAT) */ -+ exfat_fs_error(sb, "broken FAT chain."); -+ return -EIO; -+ } -+ -+ ret = exfat_alloc_cluster(inode, num_to_be_allocated, &new_clu); -+ if (ret) -+ return ret; -+ -+ if (new_clu.dir == EXFAT_EOF_CLUSTER || -+ new_clu.dir == EXFAT_FREE_CLUSTER) { -+ exfat_fs_error(sb, -+ "bogus cluster new allocated (last_clu : %u, new_clu : %u)", -+ last_clu, new_clu.dir); -+ return -EIO; -+ } -+ -+ /* append to the FAT chain */ -+ if (last_clu == EXFAT_EOF_CLUSTER) { -+ if (new_clu.flags == ALLOC_FAT_CHAIN) -+ ei->flags = ALLOC_FAT_CHAIN; -+ ei->start_clu = new_clu.dir; -+ modified = true; -+ } else { -+ if (new_clu.flags != ei->flags) { -+ /* no-fat-chain bit is disabled, -+ * so fat-chain should be synced with -+ * alloc-bitmap -+ */ -+ exfat_chain_cont_cluster(sb, ei->start_clu, -+ num_clusters); -+ ei->flags = ALLOC_FAT_CHAIN; -+ modified = true; -+ } -+ if (new_clu.flags == ALLOC_FAT_CHAIN) -+ if (exfat_ent_set(sb, last_clu, new_clu.dir)) -+ return -EIO; -+ } -+ -+ num_clusters += num_to_be_allocated; -+ *clu = new_clu.dir; -+ -+ if (ei->dir.dir != DIR_DELETED) { -+ es = exfat_get_dentry_set(sb, &(ei->dir), ei->entry, -+ ES_ALL_ENTRIES, &ep); -+ if (!es) -+ return -EIO; -+ /* get stream entry */ -+ ep++; -+ -+ /* update directory entry */ -+ if (modified) { -+ if (ep->dentry.stream.flags != ei->flags) -+ ep->dentry.stream.flags = ei->flags; -+ -+ if (le32_to_cpu(ep->dentry.stream.start_clu) != -+ ei->start_clu) -+ ep->dentry.stream.start_clu = -+ cpu_to_le32(ei->start_clu); -+ -+ ep->dentry.stream.valid_size = -+ cpu_to_le64(i_size_read(inode)); -+ ep->dentry.stream.size = -+ ep->dentry.stream.valid_size; -+ } -+ -+ if (exfat_update_dir_chksum_with_entry_set(sb, es, -+ inode_needs_sync(inode))) -+ return -EIO; -+ kfree(es); -+ -+ } /* end of if != DIR_DELETED */ -+ -+ inode->i_blocks += -+ num_to_be_allocated << sbi->sect_per_clus_bits; -+ -+ /* -+ * Move *clu pointer along FAT chains (hole care) because the -+ * caller of this function expect *clu to be the last cluster. -+ * This only works when num_to_be_allocated >= 2, -+ * *clu = (the first cluster of the allocated chain) => -+ * (the last cluster of ...) -+ */ -+ if (ei->flags == ALLOC_NO_FAT_CHAIN) { -+ *clu += num_to_be_allocated - 1; -+ } else { -+ while (num_to_be_allocated > 1) { -+ if (exfat_get_next_cluster(sb, clu)) -+ return -EIO; -+ num_to_be_allocated--; -+ } -+ } -+ -+ } -+ -+ /* hint information */ -+ ei->hint_bmap.off = local_clu_offset; -+ ei->hint_bmap.clu = *clu; -+ -+ return 0; -+} -+ -+static int exfat_map_new_buffer(struct exfat_inode_info *ei, -+ struct buffer_head *bh, loff_t pos) -+{ -+ if (buffer_delay(bh) && pos > ei->i_size_aligned) -+ return -EIO; -+ set_buffer_new(bh); -+ -+ /* -+ * Adjust i_size_aligned if i_size_ondisk is bigger than it. -+ */ -+ if (ei->i_size_ondisk > ei->i_size_aligned) -+ ei->i_size_aligned = ei->i_size_ondisk; -+ return 0; -+} -+ -+static int exfat_get_block(struct inode *inode, sector_t iblock, -+ struct buffer_head *bh_result, int create) -+{ -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits; -+ int err = 0; -+ unsigned long mapped_blocks = 0; -+ unsigned int cluster, sec_offset; -+ sector_t last_block; -+ sector_t phys = 0; -+ loff_t pos; -+ -+ mutex_lock(&sbi->s_lock); -+ last_block = EXFAT_B_TO_BLK_ROUND_UP(i_size_read(inode), sb); -+ if (iblock >= last_block && !create) -+ goto done; -+ -+ /* Is this block already allocated? */ -+ err = exfat_map_cluster(inode, iblock >> sbi->sect_per_clus_bits, -+ &cluster, create); -+ if (err) { -+ if (err != -ENOSPC) -+ exfat_fs_error_ratelimit(sb, -+ "failed to bmap (inode : %p iblock : %llu, err : %d)", -+ inode, (unsigned long long)iblock, err); -+ goto unlock_ret; -+ } -+ -+ if (cluster == EXFAT_EOF_CLUSTER) -+ goto done; -+ -+ /* sector offset in cluster */ -+ sec_offset = iblock & (sbi->sect_per_clus - 1); -+ -+ phys = exfat_cluster_to_sector(sbi, cluster) + sec_offset; -+ mapped_blocks = sbi->sect_per_clus - sec_offset; -+ max_blocks = min(mapped_blocks, max_blocks); -+ -+ /* Treat newly added block / cluster */ -+ if (iblock < last_block) -+ create = 0; -+ -+ if (create || buffer_delay(bh_result)) { -+ pos = EXFAT_BLK_TO_B((iblock + 1), sb); -+ if (ei->i_size_ondisk < pos) -+ ei->i_size_ondisk = pos; -+ } -+ -+ if (create) { -+ err = exfat_map_new_buffer(ei, bh_result, pos); -+ if (err) { -+ exfat_fs_error(sb, -+ "requested for bmap out of range(pos : (%llu) > i_size_aligned(%llu)\n", -+ pos, ei->i_size_aligned); -+ goto unlock_ret; -+ } -+ } -+ -+ if (buffer_delay(bh_result)) -+ clear_buffer_delay(bh_result); -+ map_bh(bh_result, sb, phys); -+done: -+ bh_result->b_size = EXFAT_BLK_TO_B(max_blocks, sb); -+unlock_ret: -+ mutex_unlock(&sbi->s_lock); -+ return err; -+} -+ -+static int exfat_readpage(struct file *file, struct page *page) -+{ -+ return mpage_readpage(page, exfat_get_block); -+} -+ -+static int exfat_readpages(struct file *file, struct address_space *mapping, -+ struct list_head *pages, unsigned int nr_pages) -+{ -+ return mpage_readpages(mapping, pages, nr_pages, exfat_get_block); -+} -+ -+static int exfat_writepage(struct page *page, struct writeback_control *wbc) -+{ -+ return block_write_full_page(page, exfat_get_block, wbc); -+} -+ -+static int exfat_writepages(struct address_space *mapping, -+ struct writeback_control *wbc) -+{ -+ return mpage_writepages(mapping, wbc, exfat_get_block); -+} -+ -+static void exfat_write_failed(struct address_space *mapping, loff_t to) -+{ -+ struct inode *inode = mapping->host; -+ -+ if (to > i_size_read(inode)) { -+ truncate_pagecache(inode, i_size_read(inode)); -+ exfat_truncate(inode, EXFAT_I(inode)->i_size_aligned); -+ } -+} -+ -+static int exfat_write_begin(struct file *file, struct address_space *mapping, -+ loff_t pos, unsigned int len, unsigned int flags, -+ struct page **pagep, void **fsdata) -+{ -+ int ret; -+ -+ *pagep = NULL; -+ ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, -+ exfat_get_block, -+ &EXFAT_I(mapping->host)->i_size_ondisk); -+ -+ if (ret < 0) -+ exfat_write_failed(mapping, pos+len); -+ -+ return ret; -+} -+ -+static int exfat_write_end(struct file *file, struct address_space *mapping, -+ loff_t pos, unsigned int len, unsigned int copied, -+ struct page *pagep, void *fsdata) -+{ -+ struct inode *inode = mapping->host; -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ int err; -+ -+ err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata); -+ -+ if (EXFAT_I(inode)->i_size_aligned < i_size_read(inode)) { -+ exfat_fs_error(inode->i_sb, -+ "invalid size(size(%llu) > aligned(%llu)\n", -+ i_size_read(inode), EXFAT_I(inode)->i_size_aligned); -+ return -EIO; -+ } -+ -+ if (err < len) -+ exfat_write_failed(mapping, pos+len); -+ -+ if (!(err < 0) && !(ei->attr & ATTR_ARCHIVE)) { -+ inode->i_mtime = inode->i_ctime = current_time(inode); -+ ei->attr |= ATTR_ARCHIVE; -+ mark_inode_dirty(inode); -+ } -+ -+ return err; -+} -+ -+static ssize_t exfat_direct_IO(struct kiocb *iocb, struct iov_iter *iter) -+{ -+ struct address_space *mapping = iocb->ki_filp->f_mapping; -+ struct inode *inode = mapping->host; -+ loff_t size = iocb->ki_pos + iov_iter_count(iter); -+ int rw = iov_iter_rw(iter); -+ ssize_t ret; -+ -+ if (rw == WRITE) { -+ /* -+ * FIXME: blockdev_direct_IO() doesn't use ->write_begin(), -+ * so we need to update the ->i_size_aligned to block boundary. -+ * -+ * But we must fill the remaining area or hole by nul for -+ * updating ->i_size_aligned -+ * -+ * Return 0, and fallback to normal buffered write. -+ */ -+ if (EXFAT_I(inode)->i_size_aligned < size) -+ return 0; -+ } -+ -+ /* -+ * Need to use the DIO_LOCKING for avoiding the race -+ * condition of exfat_get_block() and ->truncate(). -+ */ -+ ret = blockdev_direct_IO(iocb, inode, iter, exfat_get_block); -+ if (ret < 0 && (rw & WRITE)) -+ exfat_write_failed(mapping, size); -+ return ret; -+} -+ -+static sector_t exfat_aop_bmap(struct address_space *mapping, sector_t block) -+{ -+ sector_t blocknr; -+ -+ /* exfat_get_cluster() assumes the requested blocknr isn't truncated. */ -+ down_read(&EXFAT_I(mapping->host)->truncate_lock); -+ blocknr = generic_block_bmap(mapping, block, exfat_get_block); -+ up_read(&EXFAT_I(mapping->host)->truncate_lock); -+ return blocknr; -+} -+ -+/* -+ * exfat_block_truncate_page() zeroes out a mapping from file offset `from' -+ * up to the end of the block which corresponds to `from'. -+ * This is required during truncate to physically zeroout the tail end -+ * of that block so it doesn't yield old data if the file is later grown. -+ * Also, avoid causing failure from fsx for cases of "data past EOF" -+ */ -+int exfat_block_truncate_page(struct inode *inode, loff_t from) -+{ -+ return block_truncate_page(inode->i_mapping, from, exfat_get_block); -+} -+ -+static const struct address_space_operations exfat_aops = { -+ .readpage = exfat_readpage, -+ .readpages = exfat_readpages, -+ .writepage = exfat_writepage, -+ .writepages = exfat_writepages, -+ .write_begin = exfat_write_begin, -+ .write_end = exfat_write_end, -+ .direct_IO = exfat_direct_IO, -+ .bmap = exfat_aop_bmap -+}; -+ -+static inline unsigned long exfat_hash(loff_t i_pos) -+{ -+ return hash_32(i_pos, EXFAT_HASH_BITS); -+} -+ -+void exfat_hash_inode(struct inode *inode, loff_t i_pos) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); -+ struct hlist_head *head = sbi->inode_hashtable + exfat_hash(i_pos); -+ -+ spin_lock(&sbi->inode_hash_lock); -+ EXFAT_I(inode)->i_pos = i_pos; -+ hlist_add_head(&EXFAT_I(inode)->i_hash_fat, head); -+ spin_unlock(&sbi->inode_hash_lock); -+} -+ -+void exfat_unhash_inode(struct inode *inode) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); -+ -+ spin_lock(&sbi->inode_hash_lock); -+ hlist_del_init(&EXFAT_I(inode)->i_hash_fat); -+ EXFAT_I(inode)->i_pos = 0; -+ spin_unlock(&sbi->inode_hash_lock); -+} -+ -+struct inode *exfat_iget(struct super_block *sb, loff_t i_pos) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct exfat_inode_info *info; -+ struct hlist_head *head = sbi->inode_hashtable + exfat_hash(i_pos); -+ struct inode *inode = NULL; -+ -+ spin_lock(&sbi->inode_hash_lock); -+ hlist_for_each_entry(info, head, i_hash_fat) { -+ WARN_ON(info->vfs_inode.i_sb != sb); -+ -+ if (i_pos != info->i_pos) -+ continue; -+ inode = igrab(&info->vfs_inode); -+ if (inode) -+ break; -+ } -+ spin_unlock(&sbi->inode_hash_lock); -+ return inode; -+} -+ -+/* doesn't deal with root inode */ -+static int exfat_fill_inode(struct inode *inode, struct exfat_dir_entry *info) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ loff_t size = info->size; -+ -+ memcpy(&ei->dir, &info->dir, sizeof(struct exfat_chain)); -+ ei->entry = info->entry; -+ ei->attr = info->attr; -+ ei->start_clu = info->start_clu; -+ ei->flags = info->flags; -+ ei->type = info->type; -+ -+ ei->version = 0; -+ ei->hint_stat.eidx = 0; -+ ei->hint_stat.clu = info->start_clu; -+ ei->hint_femp.eidx = EXFAT_HINT_NONE; -+ ei->rwoffset = 0; -+ ei->hint_bmap.off = EXFAT_EOF_CLUSTER; -+ ei->i_pos = 0; -+ -+ inode->i_uid = sbi->options.fs_uid; -+ inode->i_gid = sbi->options.fs_gid; -+ inode_inc_iversion(inode); -+ inode->i_generation = prandom_u32(); -+ -+ if (info->attr & ATTR_SUBDIR) { /* directory */ -+ inode->i_generation &= ~1; -+ inode->i_mode = exfat_make_mode(sbi, info->attr, 0777); -+ inode->i_op = &exfat_dir_inode_operations; -+ inode->i_fop = &exfat_dir_operations; -+ set_nlink(inode, info->num_subdirs); -+ } else { /* regular file */ -+ inode->i_generation |= 1; -+ inode->i_mode = exfat_make_mode(sbi, info->attr, 0777); -+ inode->i_op = &exfat_file_inode_operations; -+ inode->i_fop = &exfat_file_operations; -+ inode->i_mapping->a_ops = &exfat_aops; -+ inode->i_mapping->nrpages = 0; -+ } -+ -+ i_size_write(inode, size); -+ -+ /* ondisk and aligned size should be aligned with block size */ -+ if (size & (inode->i_sb->s_blocksize - 1)) { -+ size |= (inode->i_sb->s_blocksize - 1); -+ size++; -+ } -+ -+ ei->i_size_aligned = size; -+ ei->i_size_ondisk = size; -+ -+ exfat_save_attr(inode, info->attr); -+ -+ inode->i_blocks = ((i_size_read(inode) + (sbi->cluster_size - 1)) & -+ ~(sbi->cluster_size - 1)) >> inode->i_blkbits; -+ inode->i_mtime = info->mtime; -+ inode->i_ctime = info->mtime; -+ ei->i_crtime = info->crtime; -+ inode->i_atime = info->atime; -+ -+ exfat_cache_init_inode(inode); -+ -+ return 0; -+} -+ -+struct inode *exfat_build_inode(struct super_block *sb, -+ struct exfat_dir_entry *info, loff_t i_pos) -+{ -+ struct inode *inode; -+ int err; -+ -+ inode = exfat_iget(sb, i_pos); -+ if (inode) -+ goto out; -+ inode = new_inode(sb); -+ if (!inode) { -+ inode = ERR_PTR(-ENOMEM); -+ goto out; -+ } -+ inode->i_ino = iunique(sb, EXFAT_ROOT_INO); -+ inode_set_iversion(inode, 1); -+ err = exfat_fill_inode(inode, info); -+ if (err) { -+ iput(inode); -+ inode = ERR_PTR(err); -+ goto out; -+ } -+ exfat_hash_inode(inode, i_pos); -+ insert_inode_hash(inode); -+out: -+ return inode; -+} -+ -+void exfat_evict_inode(struct inode *inode) -+{ -+ truncate_inode_pages(&inode->i_data, 0); -+ -+ if (!inode->i_nlink) { -+ i_size_write(inode, 0); -+ mutex_lock(&EXFAT_SB(inode->i_sb)->s_lock); -+ __exfat_truncate(inode, 0); -+ mutex_unlock(&EXFAT_SB(inode->i_sb)->s_lock); -+ } -+ -+ invalidate_inode_buffers(inode); -+ clear_inode(inode); -+ exfat_cache_inval_inode(inode); -+ exfat_unhash_inode(inode); -+} -diff --git a/fs/exfat/namei.c b/fs/exfat/namei.c -new file mode 100644 -index 000000000000..a8681d91f569 ---- /dev/null -+++ b/fs/exfat/namei.c -@@ -0,0 +1,1448 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "exfat_raw.h" -+#include "exfat_fs.h" -+ -+static inline unsigned long exfat_d_version(struct dentry *dentry) -+{ -+ return (unsigned long) dentry->d_fsdata; -+} -+ -+static inline void exfat_d_version_set(struct dentry *dentry, -+ unsigned long version) -+{ -+ dentry->d_fsdata = (void *) version; -+} -+ -+/* -+ * If new entry was created in the parent, it could create the 8.3 alias (the -+ * shortname of logname). So, the parent may have the negative-dentry which -+ * matches the created 8.3 alias. -+ * -+ * If it happened, the negative dentry isn't actually negative anymore. So, -+ * drop it. -+ */ -+static int exfat_d_revalidate(struct dentry *dentry, unsigned int flags) -+{ -+ int ret; -+ -+ if (flags & LOOKUP_RCU) -+ return -ECHILD; -+ -+ /* -+ * This is not negative dentry. Always valid. -+ * -+ * Note, rename() to existing directory entry will have ->d_inode, and -+ * will use existing name which isn't specified name by user. -+ * -+ * We may be able to drop this positive dentry here. But dropping -+ * positive dentry isn't good idea. So it's unsupported like -+ * rename("filename", "FILENAME") for now. -+ */ -+ if (d_really_is_positive(dentry)) -+ return 1; -+ -+ /* -+ * Drop the negative dentry, in order to make sure to use the case -+ * sensitive name which is specified by user if this is for creation. -+ */ -+ if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) -+ return 0; -+ -+ spin_lock(&dentry->d_lock); -+ ret = inode_eq_iversion(d_inode(dentry->d_parent), -+ exfat_d_version(dentry)); -+ spin_unlock(&dentry->d_lock); -+ return ret; -+} -+ -+/* returns the length of a struct qstr, ignoring trailing dots */ -+static unsigned int exfat_striptail_len(unsigned int len, const char *name) -+{ -+ while (len && name[len - 1] == '.') -+ len--; -+ return len; -+} -+ -+/* -+ * Compute the hash for the exfat name corresponding to the dentry. If the name -+ * is invalid, we leave the hash code unchanged so that the existing dentry can -+ * be used. The exfat fs routines will return ENOENT or EINVAL as appropriate. -+ */ -+static int exfat_d_hash(const struct dentry *dentry, struct qstr *qstr) -+{ -+ struct super_block *sb = dentry->d_sb; -+ struct nls_table *t = EXFAT_SB(sb)->nls_io; -+ const unsigned char *name = qstr->name; -+ unsigned int len = exfat_striptail_len(qstr->len, qstr->name); -+ unsigned long hash = init_name_hash(dentry); -+ int i, charlen; -+ wchar_t c; -+ -+ for (i = 0; i < len; i += charlen) { -+ charlen = t->char2uni(&name[i], len - i, &c); -+ if (charlen < 0) -+ return charlen; -+ hash = partial_name_hash(exfat_toupper(sb, c), hash); -+ } -+ -+ qstr->hash = end_name_hash(hash); -+ return 0; -+} -+ -+static int exfat_d_cmp(const struct dentry *dentry, unsigned int len, -+ const char *str, const struct qstr *name) -+{ -+ struct super_block *sb = dentry->d_sb; -+ struct nls_table *t = EXFAT_SB(sb)->nls_io; -+ unsigned int alen = exfat_striptail_len(name->len, name->name); -+ unsigned int blen = exfat_striptail_len(len, str); -+ wchar_t c1, c2; -+ int charlen, i; -+ -+ if (alen != blen) -+ return 1; -+ -+ for (i = 0; i < len; i += charlen) { -+ charlen = t->char2uni(&name->name[i], alen - i, &c1); -+ if (charlen < 0) -+ return 1; -+ if (charlen != t->char2uni(&str[i], blen - i, &c2)) -+ return 1; -+ -+ if (exfat_toupper(sb, c1) != exfat_toupper(sb, c2)) -+ return 1; -+ } -+ -+ return 0; -+} -+ -+const struct dentry_operations exfat_dentry_ops = { -+ .d_revalidate = exfat_d_revalidate, -+ .d_hash = exfat_d_hash, -+ .d_compare = exfat_d_cmp, -+}; -+ -+static int exfat_utf8_d_hash(const struct dentry *dentry, struct qstr *qstr) -+{ -+ struct super_block *sb = dentry->d_sb; -+ const unsigned char *name = qstr->name; -+ unsigned int len = exfat_striptail_len(qstr->len, qstr->name); -+ unsigned long hash = init_name_hash(dentry); -+ int i, charlen; -+ unicode_t u; -+ -+ for (i = 0; i < len; i += charlen) { -+ charlen = utf8_to_utf32(&name[i], len - i, &u); -+ if (charlen < 0) -+ return charlen; -+ -+ /* -+ * Convert to UTF-16: code points above U+FFFF are encoded as -+ * surrogate pairs. -+ * exfat_toupper() works only for code points up to the U+FFFF. -+ */ -+ if (u > 0xFFFF) { -+ hash = partial_name_hash(exfat_high_surrogate(u), hash); -+ hash = partial_name_hash(exfat_low_surrogate(u), hash); -+ } else { -+ hash = partial_name_hash(exfat_toupper(sb, u), hash); -+ } -+ } -+ -+ qstr->hash = end_name_hash(hash); -+ return 0; -+} -+ -+static int exfat_utf8_d_cmp(const struct dentry *dentry, unsigned int len, -+ const char *str, const struct qstr *name) -+{ -+ struct super_block *sb = dentry->d_sb; -+ unsigned int alen = exfat_striptail_len(name->len, name->name); -+ unsigned int blen = exfat_striptail_len(len, str); -+ unicode_t u_a, u_b; -+ int charlen, i; -+ -+ if (alen != blen) -+ return 1; -+ -+ for (i = 0; i < alen; i += charlen) { -+ charlen = utf8_to_utf32(&name->name[i], alen - i, &u_a); -+ if (charlen < 0) -+ return 1; -+ if (charlen != utf8_to_utf32(&str[i], blen - i, &u_b)) -+ return 1; -+ -+ if (u_a <= 0xFFFF && u_b <= 0xFFFF) { -+ if (exfat_toupper(sb, u_a) != exfat_toupper(sb, u_b)) -+ return 1; -+ } else if (u_a > 0xFFFF && u_b > 0xFFFF) { -+ if (exfat_low_surrogate(u_a) != -+ exfat_low_surrogate(u_b) || -+ exfat_high_surrogate(u_a) != -+ exfat_high_surrogate(u_b)) -+ return 1; -+ } else { -+ return 1; -+ } -+ } -+ -+ return 0; -+} -+ -+const struct dentry_operations exfat_utf8_dentry_ops = { -+ .d_revalidate = exfat_d_revalidate, -+ .d_hash = exfat_utf8_d_hash, -+ .d_compare = exfat_utf8_d_cmp, -+}; -+ -+/* used only in search empty_slot() */ -+#define CNT_UNUSED_NOHIT (-1) -+#define CNT_UNUSED_HIT (-2) -+/* search EMPTY CONTINUOUS "num_entries" entries */ -+static int exfat_search_empty_slot(struct super_block *sb, -+ struct exfat_hint_femp *hint_femp, struct exfat_chain *p_dir, -+ int num_entries) -+{ -+ int i, dentry, num_empty = 0; -+ int dentries_per_clu; -+ unsigned int type; -+ struct exfat_chain clu; -+ struct exfat_dentry *ep; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct buffer_head *bh; -+ -+ dentries_per_clu = sbi->dentries_per_clu; -+ -+ if (hint_femp->eidx != EXFAT_HINT_NONE) { -+ dentry = hint_femp->eidx; -+ if (num_entries <= hint_femp->count) { -+ hint_femp->eidx = EXFAT_HINT_NONE; -+ return dentry; -+ } -+ -+ exfat_chain_dup(&clu, &hint_femp->cur); -+ } else { -+ exfat_chain_dup(&clu, p_dir); -+ dentry = 0; -+ } -+ -+ while (clu.dir != EXFAT_EOF_CLUSTER) { -+ i = dentry & (dentries_per_clu - 1); -+ -+ for (; i < dentries_per_clu; i++, dentry++) { -+ ep = exfat_get_dentry(sb, &clu, i, &bh, NULL); -+ if (!ep) -+ return -EIO; -+ type = exfat_get_entry_type(ep); -+ brelse(bh); -+ -+ if (type == TYPE_UNUSED || type == TYPE_DELETED) { -+ num_empty++; -+ if (hint_femp->eidx == EXFAT_HINT_NONE) { -+ hint_femp->eidx = dentry; -+ hint_femp->count = CNT_UNUSED_NOHIT; -+ exfat_chain_set(&hint_femp->cur, -+ clu.dir, clu.size, clu.flags); -+ } -+ -+ if (type == TYPE_UNUSED && -+ hint_femp->count != CNT_UNUSED_HIT) -+ hint_femp->count = CNT_UNUSED_HIT; -+ } else { -+ if (hint_femp->eidx != EXFAT_HINT_NONE && -+ hint_femp->count == CNT_UNUSED_HIT) { -+ /* unused empty group means -+ * an empty group which includes -+ * unused dentry -+ */ -+ exfat_fs_error(sb, -+ "found bogus dentry(%d) beyond unused empty group(%d) (start_clu : %u, cur_clu : %u)", -+ dentry, hint_femp->eidx, -+ p_dir->dir, clu.dir); -+ return -EIO; -+ } -+ -+ num_empty = 0; -+ hint_femp->eidx = EXFAT_HINT_NONE; -+ } -+ -+ if (num_empty >= num_entries) { -+ /* found and invalidate hint_femp */ -+ hint_femp->eidx = EXFAT_HINT_NONE; -+ return (dentry - (num_entries - 1)); -+ } -+ } -+ -+ if (clu.flags == ALLOC_NO_FAT_CHAIN) { -+ if (--clu.size > 0) -+ clu.dir++; -+ else -+ clu.dir = EXFAT_EOF_CLUSTER; -+ } else { -+ if (exfat_get_next_cluster(sb, &clu.dir)) -+ return -EIO; -+ } -+ } -+ -+ return -ENOSPC; -+} -+ -+static int exfat_check_max_dentries(struct inode *inode) -+{ -+ if (EXFAT_B_TO_DEN(i_size_read(inode)) >= MAX_EXFAT_DENTRIES) { -+ /* -+ * exFAT spec allows a dir to grow upto 8388608(256MB) -+ * dentries -+ */ -+ return -ENOSPC; -+ } -+ return 0; -+} -+ -+/* find empty directory entry. -+ * if there isn't any empty slot, expand cluster chain. -+ */ -+static int exfat_find_empty_entry(struct inode *inode, -+ struct exfat_chain *p_dir, int num_entries) -+{ -+ int dentry; -+ unsigned int ret, last_clu; -+ sector_t sector; -+ loff_t size = 0; -+ struct exfat_chain clu; -+ struct exfat_dentry *ep = NULL; -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ struct exfat_hint_femp hint_femp; -+ -+ hint_femp.eidx = EXFAT_HINT_NONE; -+ -+ if (ei->hint_femp.eidx != EXFAT_HINT_NONE) { -+ memcpy(&hint_femp, &ei->hint_femp, -+ sizeof(struct exfat_hint_femp)); -+ ei->hint_femp.eidx = EXFAT_HINT_NONE; -+ } -+ -+ while ((dentry = exfat_search_empty_slot(sb, &hint_femp, p_dir, -+ num_entries)) < 0) { -+ if (dentry == -EIO) -+ break; -+ -+ if (exfat_check_max_dentries(inode)) -+ return -ENOSPC; -+ -+ /* we trust p_dir->size regardless of FAT type */ -+ if (exfat_find_last_cluster(sb, p_dir, &last_clu)) -+ return -EIO; -+ -+ /* -+ * Allocate new cluster to this directory -+ */ -+ exfat_chain_set(&clu, last_clu + 1, 0, p_dir->flags); -+ -+ /* allocate a cluster */ -+ ret = exfat_alloc_cluster(inode, 1, &clu); -+ if (ret) -+ return ret; -+ -+ if (exfat_zeroed_cluster(inode, clu.dir)) -+ return -EIO; -+ -+ /* append to the FAT chain */ -+ if (clu.flags != p_dir->flags) { -+ /* no-fat-chain bit is disabled, -+ * so fat-chain should be synced with alloc-bitmap -+ */ -+ exfat_chain_cont_cluster(sb, p_dir->dir, p_dir->size); -+ p_dir->flags = ALLOC_FAT_CHAIN; -+ hint_femp.cur.flags = ALLOC_FAT_CHAIN; -+ } -+ -+ if (clu.flags == ALLOC_FAT_CHAIN) -+ if (exfat_ent_set(sb, last_clu, clu.dir)) -+ return -EIO; -+ -+ if (hint_femp.eidx == EXFAT_HINT_NONE) { -+ /* the special case that new dentry -+ * should be allocated from the start of new cluster -+ */ -+ hint_femp.eidx = EXFAT_B_TO_DEN_IDX(p_dir->size, sbi); -+ hint_femp.count = sbi->dentries_per_clu; -+ -+ exfat_chain_set(&hint_femp.cur, clu.dir, 0, clu.flags); -+ } -+ hint_femp.cur.size++; -+ p_dir->size++; -+ size = EXFAT_CLU_TO_B(p_dir->size, sbi); -+ -+ /* update the directory entry */ -+ if (p_dir->dir != sbi->root_dir) { -+ struct buffer_head *bh; -+ -+ ep = exfat_get_dentry(sb, -+ &(ei->dir), ei->entry + 1, &bh, §or); -+ if (!ep) -+ return -EIO; -+ -+ ep->dentry.stream.valid_size = cpu_to_le64(size); -+ ep->dentry.stream.size = ep->dentry.stream.valid_size; -+ ep->dentry.stream.flags = p_dir->flags; -+ exfat_update_bh(sb, bh, IS_DIRSYNC(inode)); -+ brelse(bh); -+ if (exfat_update_dir_chksum(inode, &(ei->dir), -+ ei->entry)) -+ return -EIO; -+ } -+ -+ /* directory inode should be updated in here */ -+ i_size_write(inode, size); -+ EXFAT_I(inode)->i_size_ondisk += sbi->cluster_size; -+ EXFAT_I(inode)->i_size_aligned += sbi->cluster_size; -+ EXFAT_I(inode)->flags = p_dir->flags; -+ inode->i_blocks += 1 << sbi->sect_per_clus_bits; -+ } -+ -+ return dentry; -+} -+ -+/* -+ * Name Resolution Functions : -+ * Zero if it was successful; otherwise nonzero. -+ */ -+static int __exfat_resolve_path(struct inode *inode, const unsigned char *path, -+ struct exfat_chain *p_dir, struct exfat_uni_name *p_uniname, -+ int lookup) -+{ -+ int namelen; -+ int lossy = NLS_NAME_NO_LOSSY; -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ -+ /* strip all trailing periods */ -+ namelen = exfat_striptail_len(strlen(path), path); -+ if (!namelen) -+ return -ENOENT; -+ -+ if (strlen(path) > (MAX_NAME_LENGTH * MAX_CHARSET_SIZE)) -+ return -ENAMETOOLONG; -+ -+ /* -+ * strip all leading spaces : -+ * "MS windows 7" supports leading spaces. -+ * So we should skip this preprocessing for compatibility. -+ */ -+ -+ /* file name conversion : -+ * If lookup case, we allow bad-name for compatibility. -+ */ -+ namelen = exfat_nls_to_utf16(sb, path, namelen, p_uniname, -+ &lossy); -+ if (namelen < 0) -+ return namelen; /* return error value */ -+ -+ if ((lossy && !lookup) || !namelen) -+ return -EINVAL; -+ -+ exfat_chain_set(p_dir, ei->start_clu, -+ EXFAT_B_TO_CLU(i_size_read(inode), sbi), ei->flags); -+ -+ return 0; -+} -+ -+static inline int exfat_resolve_path(struct inode *inode, -+ const unsigned char *path, struct exfat_chain *dir, -+ struct exfat_uni_name *uni) -+{ -+ return __exfat_resolve_path(inode, path, dir, uni, 0); -+} -+ -+static inline int exfat_resolve_path_for_lookup(struct inode *inode, -+ const unsigned char *path, struct exfat_chain *dir, -+ struct exfat_uni_name *uni) -+{ -+ return __exfat_resolve_path(inode, path, dir, uni, 1); -+} -+ -+static inline loff_t exfat_make_i_pos(struct exfat_dir_entry *info) -+{ -+ return ((loff_t) info->dir.dir << 32) | (info->entry & 0xffffffff); -+} -+ -+static int exfat_add_entry(struct inode *inode, const char *path, -+ struct exfat_chain *p_dir, unsigned int type, -+ struct exfat_dir_entry *info) -+{ -+ int ret, dentry, num_entries; -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct exfat_uni_name uniname; -+ struct exfat_chain clu; -+ int clu_size = 0; -+ unsigned int start_clu = EXFAT_FREE_CLUSTER; -+ -+ ret = exfat_resolve_path(inode, path, p_dir, &uniname); -+ if (ret) -+ goto out; -+ -+ num_entries = exfat_calc_num_entries(&uniname); -+ if (num_entries < 0) { -+ ret = num_entries; -+ goto out; -+ } -+ -+ /* exfat_find_empty_entry must be called before alloc_cluster() */ -+ dentry = exfat_find_empty_entry(inode, p_dir, num_entries); -+ if (dentry < 0) { -+ ret = dentry; /* -EIO or -ENOSPC */ -+ goto out; -+ } -+ -+ if (type == TYPE_DIR) { -+ ret = exfat_alloc_new_dir(inode, &clu); -+ if (ret) -+ goto out; -+ start_clu = clu.dir; -+ clu_size = sbi->cluster_size; -+ } -+ -+ /* update the directory entry */ -+ /* fill the dos name directory entry information of the created file. -+ * the first cluster is not determined yet. (0) -+ */ -+ ret = exfat_init_dir_entry(inode, p_dir, dentry, type, -+ start_clu, clu_size); -+ if (ret) -+ goto out; -+ -+ ret = exfat_init_ext_entry(inode, p_dir, dentry, num_entries, &uniname); -+ if (ret) -+ goto out; -+ -+ memcpy(&info->dir, p_dir, sizeof(struct exfat_chain)); -+ info->entry = dentry; -+ info->flags = ALLOC_NO_FAT_CHAIN; -+ info->type = type; -+ -+ if (type == TYPE_FILE) { -+ info->attr = ATTR_ARCHIVE; -+ info->start_clu = EXFAT_EOF_CLUSTER; -+ info->size = 0; -+ info->num_subdirs = 0; -+ } else { -+ int count; -+ struct exfat_chain cdir; -+ -+ info->attr = ATTR_SUBDIR; -+ info->start_clu = start_clu; -+ info->size = clu_size; -+ -+ exfat_chain_set(&cdir, info->start_clu, -+ EXFAT_B_TO_CLU(info->size, sbi), info->flags); -+ count = exfat_count_dir_entries(sb, &cdir); -+ if (count < 0) -+ return -EIO; -+ info->num_subdirs = count + EXFAT_MIN_SUBDIR; -+ } -+ memset(&info->crtime, 0, sizeof(info->crtime)); -+ memset(&info->mtime, 0, sizeof(info->mtime)); -+ memset(&info->atime, 0, sizeof(info->atime)); -+out: -+ return ret; -+} -+ -+static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, -+ bool excl) -+{ -+ struct super_block *sb = dir->i_sb; -+ struct inode *inode; -+ struct exfat_chain cdir; -+ struct exfat_dir_entry info; -+ loff_t i_pos; -+ int err; -+ -+ mutex_lock(&EXFAT_SB(sb)->s_lock); -+ exfat_set_vol_flags(sb, VOL_DIRTY); -+ err = exfat_add_entry(dir, dentry->d_name.name, &cdir, TYPE_FILE, -+ &info); -+ exfat_set_vol_flags(sb, VOL_CLEAN); -+ if (err) -+ goto unlock; -+ -+ inode_inc_iversion(dir); -+ dir->i_ctime = dir->i_mtime = current_time(dir); -+ if (IS_DIRSYNC(dir)) -+ exfat_sync_inode(dir); -+ else -+ mark_inode_dirty(dir); -+ -+ i_pos = exfat_make_i_pos(&info); -+ inode = exfat_build_inode(sb, &info, i_pos); -+ if (IS_ERR(inode)) -+ goto unlock; -+ -+ inode_inc_iversion(inode); -+ inode->i_mtime = inode->i_atime = inode->i_ctime = -+ EXFAT_I(inode)->i_crtime = current_time(inode); -+ /* timestamp is already written, so mark_inode_dirty() is unneeded. */ -+ -+ d_instantiate(dentry, inode); -+unlock: -+ mutex_unlock(&EXFAT_SB(sb)->s_lock); -+ return err; -+} -+ -+/* lookup a file */ -+static int exfat_find(struct inode *dir, struct qstr *qname, -+ struct exfat_dir_entry *info) -+{ -+ int ret, dentry, num_entries, count; -+ struct exfat_chain cdir; -+ struct exfat_uni_name uni_name; -+ struct exfat_dentry *ep, *ep2; -+ struct exfat_entry_set_cache *es = NULL; -+ struct super_block *sb = dir->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct exfat_inode_info *ei = EXFAT_I(dir); -+ -+ if (qname->len == 0) -+ return -ENOENT; -+ -+ /* check the validity of directory name in the given pathname */ -+ ret = exfat_resolve_path_for_lookup(dir, qname->name, &cdir, &uni_name); -+ if (ret) -+ return ret; -+ -+ num_entries = exfat_calc_num_entries(&uni_name); -+ if (num_entries < 0) -+ return num_entries; -+ -+ /* check the validation of hint_stat and initialize it if required */ -+ if (ei->version != (inode_peek_iversion_raw(dir) & 0xffffffff)) { -+ ei->hint_stat.clu = cdir.dir; -+ ei->hint_stat.eidx = 0; -+ ei->version = (inode_peek_iversion_raw(dir) & 0xffffffff); -+ ei->hint_femp.eidx = EXFAT_HINT_NONE; -+ } -+ -+ /* search the file name for directories */ -+ dentry = exfat_find_dir_entry(sb, ei, &cdir, &uni_name, -+ num_entries, TYPE_ALL); -+ -+ if ((dentry < 0) && (dentry != -EEXIST)) -+ return dentry; /* -error value */ -+ -+ memcpy(&info->dir, &cdir.dir, sizeof(struct exfat_chain)); -+ info->entry = dentry; -+ info->num_subdirs = 0; -+ -+ /* root directory itself */ -+ if (unlikely(dentry == -EEXIST)) { -+ int num_clu = 0; -+ -+ info->type = TYPE_DIR; -+ info->attr = ATTR_SUBDIR; -+ info->flags = ALLOC_FAT_CHAIN; -+ info->start_clu = sbi->root_dir; -+ memset(&info->crtime, 0, sizeof(info->crtime)); -+ memset(&info->mtime, 0, sizeof(info->mtime)); -+ memset(&info->atime, 0, sizeof(info->atime)); -+ -+ exfat_chain_set(&cdir, sbi->root_dir, 0, ALLOC_FAT_CHAIN); -+ if (exfat_count_num_clusters(sb, &cdir, &num_clu)) -+ return -EIO; -+ info->size = num_clu << sbi->cluster_size_bits; -+ -+ count = exfat_count_dir_entries(sb, &cdir); -+ if (count < 0) -+ return -EIO; -+ -+ info->num_subdirs = count; -+ } else { -+ es = exfat_get_dentry_set(sb, &cdir, dentry, ES_2_ENTRIES, &ep); -+ if (!es) -+ return -EIO; -+ ep2 = ep + 1; -+ -+ info->type = exfat_get_entry_type(ep); -+ info->attr = le16_to_cpu(ep->dentry.file.attr); -+ info->size = le64_to_cpu(ep2->dentry.stream.valid_size); -+ if ((info->type == TYPE_FILE) && (info->size == 0)) { -+ info->flags = ALLOC_NO_FAT_CHAIN; -+ info->start_clu = EXFAT_EOF_CLUSTER; -+ } else { -+ info->flags = ep2->dentry.stream.flags; -+ info->start_clu = -+ le32_to_cpu(ep2->dentry.stream.start_clu); -+ } -+ -+ if (ei->start_clu == EXFAT_FREE_CLUSTER) { -+ exfat_fs_error(sb, -+ "non-zero size file starts with zero cluster (size : %llu, p_dir : %u, entry : 0x%08x)", -+ i_size_read(dir), ei->dir.dir, ei->entry); -+ return -EIO; -+ } -+ -+ exfat_get_entry_time(sbi, &info->crtime, -+ ep->dentry.file.create_tz, -+ ep->dentry.file.create_time, -+ ep->dentry.file.create_date, -+ ep->dentry.file.create_time_ms); -+ exfat_get_entry_time(sbi, &info->mtime, -+ ep->dentry.file.modify_tz, -+ ep->dentry.file.modify_time, -+ ep->dentry.file.modify_date, -+ ep->dentry.file.modify_time_ms); -+ exfat_get_entry_time(sbi, &info->atime, -+ ep->dentry.file.access_tz, -+ ep->dentry.file.access_time, -+ ep->dentry.file.access_date, -+ 0); -+ kfree(es); -+ -+ if (info->type == TYPE_DIR) { -+ exfat_chain_set(&cdir, info->start_clu, -+ EXFAT_B_TO_CLU(info->size, sbi), info->flags); -+ count = exfat_count_dir_entries(sb, &cdir); -+ if (count < 0) -+ return -EIO; -+ -+ info->num_subdirs = count + EXFAT_MIN_SUBDIR; -+ } -+ } -+ return 0; -+} -+ -+static int exfat_d_anon_disconn(struct dentry *dentry) -+{ -+ return IS_ROOT(dentry) && (dentry->d_flags & DCACHE_DISCONNECTED); -+} -+ -+static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry, -+ unsigned int flags) -+{ -+ struct super_block *sb = dir->i_sb; -+ struct inode *inode; -+ struct dentry *alias; -+ struct exfat_dir_entry info; -+ int err; -+ loff_t i_pos; -+ mode_t i_mode; -+ -+ mutex_lock(&EXFAT_SB(sb)->s_lock); -+ err = exfat_find(dir, &dentry->d_name, &info); -+ if (err) { -+ if (err == -ENOENT) { -+ inode = NULL; -+ goto out; -+ } -+ goto unlock; -+ } -+ -+ i_pos = exfat_make_i_pos(&info); -+ inode = exfat_build_inode(sb, &info, i_pos); -+ if (IS_ERR(inode)) { -+ err = PTR_ERR(inode); -+ goto unlock; -+ } -+ -+ i_mode = inode->i_mode; -+ alias = d_find_alias(inode); -+ -+ /* -+ * Checking "alias->d_parent == dentry->d_parent" to make sure -+ * FS is not corrupted (especially double linked dir). -+ */ -+ if (alias && alias->d_parent == dentry->d_parent && -+ !exfat_d_anon_disconn(alias)) { -+ -+ /* -+ * Unhashed alias is able to exist because of revalidate() -+ * called by lookup_fast. You can easily make this status -+ * by calling create and lookup concurrently -+ * In such case, we reuse an alias instead of new dentry -+ */ -+ if (d_unhashed(alias)) { -+ WARN_ON(alias->d_name.hash_len != -+ dentry->d_name.hash_len); -+ exfat_msg(sb, KERN_INFO, -+ "rehashed a dentry(%p) in read lookup", alias); -+ d_drop(dentry); -+ d_rehash(alias); -+ } else if (!S_ISDIR(i_mode)) { -+ /* -+ * This inode has non anonymous-DCACHE_DISCONNECTED -+ * dentry. This means, the user did ->lookup() by an -+ * another name (longname vs 8.3 alias of it) in past. -+ * -+ * Switch to new one for reason of locality if possible. -+ */ -+ d_move(alias, dentry); -+ } -+ iput(inode); -+ mutex_unlock(&EXFAT_SB(sb)->s_lock); -+ return alias; -+ } -+ dput(alias); -+out: -+ mutex_unlock(&EXFAT_SB(sb)->s_lock); -+ if (!inode) -+ exfat_d_version_set(dentry, inode_query_iversion(dir)); -+ -+ return d_splice_alias(inode, dentry); -+unlock: -+ mutex_unlock(&EXFAT_SB(sb)->s_lock); -+ return ERR_PTR(err); -+} -+ -+/* remove an entry, BUT don't truncate */ -+static int exfat_unlink(struct inode *dir, struct dentry *dentry) -+{ -+ struct exfat_chain cdir; -+ struct exfat_dentry *ep; -+ struct super_block *sb = dir->i_sb; -+ struct inode *inode = dentry->d_inode; -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ struct buffer_head *bh; -+ sector_t sector; -+ int num_entries, entry, err = 0; -+ -+ mutex_lock(&EXFAT_SB(sb)->s_lock); -+ exfat_chain_dup(&cdir, &ei->dir); -+ entry = ei->entry; -+ if (ei->dir.dir == DIR_DELETED) { -+ exfat_msg(sb, KERN_ERR, "abnormal access to deleted dentry"); -+ err = -ENOENT; -+ goto unlock; -+ } -+ -+ ep = exfat_get_dentry(sb, &cdir, entry, &bh, §or); -+ if (!ep) { -+ err = -EIO; -+ goto unlock; -+ } -+ num_entries = exfat_count_ext_entries(sb, &cdir, entry, ep); -+ if (num_entries < 0) { -+ err = -EIO; -+ brelse(bh); -+ goto unlock; -+ } -+ num_entries++; -+ brelse(bh); -+ -+ exfat_set_vol_flags(sb, VOL_DIRTY); -+ /* update the directory entry */ -+ if (exfat_remove_entries(dir, &cdir, entry, 0, num_entries)) { -+ err = -EIO; -+ goto unlock; -+ } -+ -+ /* This doesn't modify ei */ -+ ei->dir.dir = DIR_DELETED; -+ exfat_set_vol_flags(sb, VOL_CLEAN); -+ -+ inode_inc_iversion(dir); -+ dir->i_mtime = dir->i_atime = current_time(dir); -+ if (IS_DIRSYNC(dir)) -+ exfat_sync_inode(dir); -+ else -+ mark_inode_dirty(dir); -+ -+ clear_nlink(inode); -+ inode->i_mtime = inode->i_atime = current_time(inode); -+ exfat_unhash_inode(inode); -+ exfat_d_version_set(dentry, inode_query_iversion(dir)); -+unlock: -+ mutex_unlock(&EXFAT_SB(sb)->s_lock); -+ return err; -+} -+ -+static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) -+{ -+ struct super_block *sb = dir->i_sb; -+ struct inode *inode; -+ struct exfat_dir_entry info; -+ struct exfat_chain cdir; -+ loff_t i_pos; -+ int err; -+ -+ mutex_lock(&EXFAT_SB(sb)->s_lock); -+ exfat_set_vol_flags(sb, VOL_DIRTY); -+ err = exfat_add_entry(dir, dentry->d_name.name, &cdir, TYPE_DIR, -+ &info); -+ exfat_set_vol_flags(sb, VOL_CLEAN); -+ if (err) -+ goto unlock; -+ -+ inode_inc_iversion(dir); -+ dir->i_ctime = dir->i_mtime = current_time(dir); -+ if (IS_DIRSYNC(dir)) -+ exfat_sync_inode(dir); -+ else -+ mark_inode_dirty(dir); -+ inc_nlink(dir); -+ -+ i_pos = exfat_make_i_pos(&info); -+ inode = exfat_build_inode(sb, &info, i_pos); -+ if (IS_ERR(inode)) { -+ err = PTR_ERR(inode); -+ goto unlock; -+ } -+ -+ inode_inc_iversion(inode); -+ inode->i_mtime = inode->i_atime = inode->i_ctime = -+ EXFAT_I(inode)->i_crtime = current_time(inode); -+ /* timestamp is already written, so mark_inode_dirty() is unneeded. */ -+ -+ d_instantiate(dentry, inode); -+ -+unlock: -+ mutex_unlock(&EXFAT_SB(sb)->s_lock); -+ return err; -+} -+ -+static int exfat_check_dir_empty(struct super_block *sb, -+ struct exfat_chain *p_dir) -+{ -+ int i, dentries_per_clu; -+ unsigned int type; -+ struct exfat_chain clu; -+ struct exfat_dentry *ep; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct buffer_head *bh; -+ -+ dentries_per_clu = sbi->dentries_per_clu; -+ -+ exfat_chain_dup(&clu, p_dir); -+ -+ while (clu.dir != EXFAT_EOF_CLUSTER) { -+ for (i = 0; i < dentries_per_clu; i++) { -+ ep = exfat_get_dentry(sb, &clu, i, &bh, NULL); -+ if (!ep) -+ return -EIO; -+ type = exfat_get_entry_type(ep); -+ brelse(bh); -+ if (type == TYPE_UNUSED) -+ return 0; -+ -+ if (type != TYPE_FILE && type != TYPE_DIR) -+ continue; -+ -+ return -ENOTEMPTY; -+ } -+ -+ if (clu.flags == ALLOC_NO_FAT_CHAIN) { -+ if (--clu.size > 0) -+ clu.dir++; -+ else -+ clu.dir = EXFAT_EOF_CLUSTER; -+ } else { -+ if (exfat_get_next_cluster(sb, &(clu.dir))) -+ return -EIO; -+ } -+ } -+ -+ return 0; -+} -+ -+static int exfat_rmdir(struct inode *dir, struct dentry *dentry) -+{ -+ struct inode *inode = dentry->d_inode; -+ struct exfat_dentry *ep; -+ struct exfat_chain cdir, clu_to_free; -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ struct buffer_head *bh; -+ sector_t sector; -+ int num_entries, entry, err; -+ -+ mutex_lock(&EXFAT_SB(inode->i_sb)->s_lock); -+ -+ exfat_chain_dup(&cdir, &ei->dir); -+ entry = ei->entry; -+ -+ if (ei->dir.dir == DIR_DELETED) { -+ exfat_msg(sb, KERN_ERR, "abnormal access to deleted dentry"); -+ err = -ENOENT; -+ goto unlock; -+ } -+ -+ exfat_set_vol_flags(sb, VOL_DIRTY); -+ exfat_chain_set(&clu_to_free, ei->start_clu, -+ EXFAT_B_TO_CLU_ROUND_UP(i_size_read(inode), sbi), ei->flags); -+ -+ err = exfat_check_dir_empty(sb, &clu_to_free); -+ if (err) { -+ if (err == -EIO) -+ exfat_msg(sb, KERN_ERR, -+ "failed to exfat_check_dir_empty : err(%d)", -+ err); -+ goto unlock; -+ } -+ -+ ep = exfat_get_dentry(sb, &cdir, entry, &bh, §or); -+ if (!ep) { -+ err = -EIO; -+ goto unlock; -+ } -+ -+ num_entries = exfat_count_ext_entries(sb, &cdir, entry, ep); -+ if (num_entries < 0) { -+ err = -EIO; -+ brelse(bh); -+ goto unlock; -+ } -+ num_entries++; -+ brelse(bh); -+ -+ err = exfat_remove_entries(dir, &cdir, entry, 0, num_entries); -+ if (err) { -+ exfat_msg(sb, KERN_ERR, -+ "failed to exfat_remove_entries : err(%d)", -+ err); -+ goto unlock; -+ } -+ ei->dir.dir = DIR_DELETED; -+ exfat_set_vol_flags(sb, VOL_CLEAN); -+ -+ inode_inc_iversion(dir); -+ dir->i_mtime = dir->i_atime = current_time(dir); -+ if (IS_DIRSYNC(dir)) -+ exfat_sync_inode(dir); -+ else -+ mark_inode_dirty(dir); -+ drop_nlink(dir); -+ -+ clear_nlink(inode); -+ inode->i_mtime = inode->i_atime = current_time(inode); -+ exfat_unhash_inode(inode); -+ exfat_d_version_set(dentry, inode_query_iversion(dir)); -+unlock: -+ mutex_unlock(&EXFAT_SB(inode->i_sb)->s_lock); -+ return err; -+} -+ -+static int exfat_rename_file(struct inode *inode, struct exfat_chain *p_dir, -+ int oldentry, struct exfat_uni_name *p_uniname, -+ struct exfat_inode_info *ei) -+{ -+ int ret, num_old_entries, num_new_entries; -+ sector_t sector_old, sector_new; -+ struct exfat_dentry *epold, *epnew; -+ struct super_block *sb = inode->i_sb; -+ struct buffer_head *new_bh, *old_bh; -+ int sync = IS_DIRSYNC(inode); -+ -+ epold = exfat_get_dentry(sb, p_dir, oldentry, &old_bh, §or_old); -+ if (!epold) -+ return -EIO; -+ -+ num_old_entries = exfat_count_ext_entries(sb, p_dir, oldentry, epold); -+ if (num_old_entries < 0) -+ return -EIO; -+ num_old_entries++; -+ -+ num_new_entries = exfat_calc_num_entries(p_uniname); -+ if (num_new_entries < 0) -+ return num_new_entries; -+ -+ if (num_old_entries < num_new_entries) { -+ int newentry; -+ -+ newentry = -+ exfat_find_empty_entry(inode, p_dir, num_new_entries); -+ if (newentry < 0) -+ return newentry; /* -EIO or -ENOSPC */ -+ -+ epnew = exfat_get_dentry(sb, p_dir, newentry, &new_bh, -+ §or_new); -+ if (!epnew) -+ return -EIO; -+ -+ memcpy(epnew, epold, DENTRY_SIZE); -+ if (exfat_get_entry_type(epnew) == TYPE_FILE) { -+ epnew->dentry.file.attr |= cpu_to_le16(ATTR_ARCHIVE); -+ ei->attr |= ATTR_ARCHIVE; -+ } -+ exfat_update_bh(sb, new_bh, sync); -+ brelse(old_bh); -+ brelse(new_bh); -+ -+ epold = exfat_get_dentry(sb, p_dir, oldentry + 1, &old_bh, -+ §or_old); -+ epnew = exfat_get_dentry(sb, p_dir, newentry + 1, &new_bh, -+ §or_new); -+ if (!epold || !epnew) -+ return -EIO; -+ -+ memcpy(epnew, epold, DENTRY_SIZE); -+ exfat_update_bh(sb, new_bh, sync); -+ brelse(old_bh); -+ brelse(new_bh); -+ -+ ret = exfat_init_ext_entry(inode, p_dir, newentry, -+ num_new_entries, p_uniname); -+ if (ret) -+ return ret; -+ -+ exfat_remove_entries(inode, p_dir, oldentry, 0, -+ num_old_entries); -+ ei->entry = newentry; -+ } else { -+ if (exfat_get_entry_type(epold) == TYPE_FILE) { -+ epold->dentry.file.attr |= cpu_to_le16(ATTR_ARCHIVE); -+ ei->attr |= ATTR_ARCHIVE; -+ } -+ exfat_update_bh(sb, old_bh, sync); -+ brelse(old_bh); -+ ret = exfat_init_ext_entry(inode, p_dir, oldentry, -+ num_new_entries, p_uniname); -+ if (ret) -+ return ret; -+ -+ exfat_remove_entries(inode, p_dir, oldentry, num_new_entries, -+ num_old_entries); -+ } -+ return 0; -+} -+ -+static int exfat_move_file(struct inode *inode, struct exfat_chain *p_olddir, -+ int oldentry, struct exfat_chain *p_newdir, -+ struct exfat_uni_name *p_uniname, struct exfat_inode_info *ei) -+{ -+ int ret, newentry, num_new_entries, num_old_entries; -+ sector_t sector_mov, sector_new; -+ struct exfat_dentry *epmov, *epnew; -+ struct super_block *sb = inode->i_sb; -+ struct buffer_head *mov_bh, *new_bh; -+ -+ epmov = exfat_get_dentry(sb, p_olddir, oldentry, &mov_bh, §or_mov); -+ if (!epmov) -+ return -EIO; -+ -+ /* check if the source and target directory is the same */ -+ if (exfat_get_entry_type(epmov) == TYPE_DIR && -+ le32_to_cpu(epmov->dentry.stream.start_clu) == p_newdir->dir) -+ return -EINVAL; -+ -+ num_old_entries = exfat_count_ext_entries(sb, p_olddir, oldentry, -+ epmov); -+ if (num_old_entries < 0) -+ return -EIO; -+ num_old_entries++; -+ -+ num_new_entries = exfat_calc_num_entries(p_uniname); -+ if (num_new_entries < 0) -+ return num_new_entries; -+ -+ newentry = exfat_find_empty_entry(inode, p_newdir, num_new_entries); -+ if (newentry < 0) -+ return newentry; /* -EIO or -ENOSPC */ -+ -+ epnew = exfat_get_dentry(sb, p_newdir, newentry, &new_bh, §or_new); -+ if (!epnew) -+ return -EIO; -+ -+ memcpy(epnew, epmov, DENTRY_SIZE); -+ if (exfat_get_entry_type(epnew) == TYPE_FILE) { -+ epnew->dentry.file.attr |= cpu_to_le16(ATTR_ARCHIVE); -+ ei->attr |= ATTR_ARCHIVE; -+ } -+ exfat_update_bh(sb, new_bh, IS_DIRSYNC(inode)); -+ brelse(mov_bh); -+ brelse(new_bh); -+ -+ epmov = exfat_get_dentry(sb, p_olddir, oldentry + 1, &mov_bh, -+ §or_mov); -+ epnew = exfat_get_dentry(sb, p_newdir, newentry + 1, &new_bh, -+ §or_new); -+ if (!epmov || !epnew) -+ return -EIO; -+ -+ memcpy(epnew, epmov, DENTRY_SIZE); -+ exfat_update_bh(sb, new_bh, IS_DIRSYNC(inode)); -+ brelse(mov_bh); -+ brelse(new_bh); -+ -+ ret = exfat_init_ext_entry(inode, p_newdir, newentry, num_new_entries, -+ p_uniname); -+ if (ret) -+ return ret; -+ -+ exfat_remove_entries(inode, p_olddir, oldentry, 0, num_old_entries); -+ -+ exfat_chain_set(&ei->dir, p_newdir->dir, p_newdir->size, -+ p_newdir->flags); -+ -+ ei->entry = newentry; -+ return 0; -+} -+ -+static void exfat_update_parent_info(struct exfat_inode_info *ei, -+ struct inode *parent_inode) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(parent_inode->i_sb); -+ struct exfat_inode_info *parent_ei = EXFAT_I(parent_inode); -+ loff_t parent_isize = i_size_read(parent_inode); -+ -+ /* -+ * the problem that struct exfat_inode_info caches wrong parent info. -+ * -+ * because of flag-mismatch of ei->dir, -+ * there is abnormal traversing cluster chain. -+ */ -+ if (unlikely(parent_ei->flags != ei->dir.flags || -+ parent_isize != EXFAT_CLU_TO_B(ei->dir.size, sbi) || -+ parent_ei->start_clu != ei->dir.dir)) { -+ exfat_chain_set(&ei->dir, parent_ei->start_clu, -+ EXFAT_B_TO_CLU_ROUND_UP(parent_isize, sbi), -+ parent_ei->flags); -+ } -+} -+ -+/* rename or move a old file into a new file */ -+static int __exfat_rename(struct inode *old_parent_inode, -+ struct exfat_inode_info *ei, struct inode *new_parent_inode, -+ struct dentry *new_dentry) -+{ -+ int ret; -+ int dentry; -+ struct exfat_chain olddir, newdir; -+ struct exfat_chain *p_dir = NULL; -+ struct exfat_uni_name uni_name; -+ struct exfat_dentry *ep; -+ struct super_block *sb = old_parent_inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ const unsigned char *new_path = new_dentry->d_name.name; -+ struct inode *new_inode = new_dentry->d_inode; -+ int num_entries; -+ struct exfat_inode_info *new_ei = NULL; -+ unsigned int new_entry_type = TYPE_UNUSED; -+ int new_entry = 0; -+ struct buffer_head *old_bh, *new_bh = NULL; -+ -+ /* check the validity of pointer parameters */ -+ if (new_path == NULL || strlen(new_path) == 0) -+ return -EINVAL; -+ -+ if (ei->dir.dir == DIR_DELETED) { -+ exfat_msg(sb, KERN_ERR, -+ "abnormal access to deleted source dentry"); -+ return -ENOENT; -+ } -+ -+ exfat_update_parent_info(ei, old_parent_inode); -+ -+ exfat_chain_dup(&olddir, &ei->dir); -+ dentry = ei->entry; -+ -+ ep = exfat_get_dentry(sb, &olddir, dentry, &old_bh, NULL); -+ if (!ep) { -+ ret = -EIO; -+ goto out; -+ } -+ brelse(old_bh); -+ -+ /* check whether new dir is existing directory and empty */ -+ if (new_inode) { -+ ret = -EIO; -+ new_ei = EXFAT_I(new_inode); -+ -+ if (new_ei->dir.dir == DIR_DELETED) { -+ exfat_msg(sb, KERN_ERR, -+ "abnormal access to deleted target dentry"); -+ goto out; -+ } -+ -+ exfat_update_parent_info(new_ei, new_parent_inode); -+ -+ p_dir = &(new_ei->dir); -+ new_entry = new_ei->entry; -+ ep = exfat_get_dentry(sb, p_dir, new_entry, &new_bh, NULL); -+ if (!ep) -+ goto out; -+ -+ new_entry_type = exfat_get_entry_type(ep); -+ brelse(new_bh); -+ -+ /* if new_inode exists, update ei */ -+ if (new_entry_type == TYPE_DIR) { -+ struct exfat_chain new_clu; -+ -+ new_clu.dir = new_ei->start_clu; -+ new_clu.size = -+ EXFAT_B_TO_CLU_ROUND_UP(i_size_read(new_inode), -+ sbi); -+ new_clu.flags = new_ei->flags; -+ -+ ret = exfat_check_dir_empty(sb, &new_clu); -+ if (ret) -+ goto out; -+ } -+ } -+ -+ /* check the validity of directory name in the given new pathname */ -+ ret = exfat_resolve_path(new_parent_inode, new_path, &newdir, -+ &uni_name); -+ if (ret) -+ goto out; -+ -+ exfat_set_vol_flags(sb, VOL_DIRTY); -+ -+ if (olddir.dir == newdir.dir) -+ ret = exfat_rename_file(new_parent_inode, &olddir, dentry, -+ &uni_name, ei); -+ else -+ ret = exfat_move_file(new_parent_inode, &olddir, dentry, -+ &newdir, &uni_name, ei); -+ -+ if (!ret && new_inode) { -+ /* delete entries of new_dir */ -+ ep = exfat_get_dentry(sb, p_dir, new_entry, &new_bh, NULL); -+ if (!ep) { -+ ret = -EIO; -+ goto del_out; -+ } -+ -+ num_entries = exfat_count_ext_entries(sb, p_dir, new_entry, ep); -+ if (num_entries < 0) { -+ ret = -EIO; -+ goto del_out; -+ } -+ brelse(new_bh); -+ -+ if (exfat_remove_entries(new_inode, p_dir, new_entry, 0, -+ num_entries + 1)) { -+ ret = -EIO; -+ goto del_out; -+ } -+ -+ /* Free the clusters if new_inode is a dir(as if exfat_rmdir) */ -+ if (new_entry_type == TYPE_DIR) { -+ /* new_ei, new_clu_to_free */ -+ struct exfat_chain new_clu_to_free; -+ -+ exfat_chain_set(&new_clu_to_free, new_ei->start_clu, -+ EXFAT_B_TO_CLU_ROUND_UP(i_size_read(new_inode), -+ sbi), new_ei->flags); -+ -+ if (exfat_free_cluster(new_inode, &new_clu_to_free)) { -+ /* just set I/O error only */ -+ ret = -EIO; -+ } -+ -+ i_size_write(new_inode, 0); -+ new_ei->start_clu = EXFAT_EOF_CLUSTER; -+ new_ei->flags = ALLOC_NO_FAT_CHAIN; -+ } -+del_out: -+ /* Update new_inode ei -+ * Prevent syncing removed new_inode -+ * (new_ei is already initialized above code ("if (new_inode)") -+ */ -+ new_ei->dir.dir = DIR_DELETED; -+ } -+ exfat_set_vol_flags(sb, VOL_CLEAN); -+out: -+ return ret; -+} -+ -+static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry, -+ struct inode *new_dir, struct dentry *new_dentry, -+ unsigned int flags) -+{ -+ struct inode *old_inode, *new_inode; -+ struct super_block *sb = old_dir->i_sb; -+ loff_t i_pos; -+ int err; -+ -+ /* -+ * The VFS already checks for existence, so for local filesystems -+ * the RENAME_NOREPLACE implementation is equivalent to plain rename. -+ * Don't support any other flags -+ */ -+ if (flags & ~RENAME_NOREPLACE) -+ return -EINVAL; -+ -+ mutex_lock(&EXFAT_SB(sb)->s_lock); -+ old_inode = old_dentry->d_inode; -+ new_inode = new_dentry->d_inode; -+ -+ err = __exfat_rename(old_dir, EXFAT_I(old_inode), new_dir, new_dentry); -+ if (err) -+ goto unlock; -+ -+ inode_inc_iversion(new_dir); -+ new_dir->i_ctime = new_dir->i_mtime = new_dir->i_atime = -+ EXFAT_I(new_dir)->i_crtime = current_time(new_dir); -+ if (IS_DIRSYNC(new_dir)) -+ exfat_sync_inode(new_dir); -+ else -+ mark_inode_dirty(new_dir); -+ -+ i_pos = ((loff_t)EXFAT_I(old_inode)->dir.dir << 32) | -+ (EXFAT_I(old_inode)->entry & 0xffffffff); -+ exfat_unhash_inode(old_inode); -+ exfat_hash_inode(old_inode, i_pos); -+ if (IS_DIRSYNC(new_dir)) -+ exfat_sync_inode(old_inode); -+ else -+ mark_inode_dirty(old_inode); -+ -+ if (S_ISDIR(old_inode->i_mode) && old_dir != new_dir) { -+ drop_nlink(old_dir); -+ if (!new_inode) -+ inc_nlink(new_dir); -+ } -+ -+ inode_inc_iversion(old_dir); -+ old_dir->i_ctime = old_dir->i_mtime = current_time(old_dir); -+ if (IS_DIRSYNC(old_dir)) -+ exfat_sync_inode(old_dir); -+ else -+ mark_inode_dirty(old_dir); -+ -+ if (new_inode) { -+ exfat_unhash_inode(new_inode); -+ -+ /* skip drop_nlink if new_inode already has been dropped */ -+ if (new_inode->i_nlink) { -+ drop_nlink(new_inode); -+ if (S_ISDIR(new_inode->i_mode)) -+ drop_nlink(new_inode); -+ } else { -+ exfat_msg(sb, KERN_WARNING, -+ "abnormal access to an inode dropped"); -+ WARN_ON(new_inode->i_nlink == 0); -+ } -+ new_inode->i_ctime = EXFAT_I(new_inode)->i_crtime = -+ current_time(new_inode); -+ } -+ -+unlock: -+ mutex_unlock(&EXFAT_SB(sb)->s_lock); -+ return err; -+} -+ -+const struct inode_operations exfat_dir_inode_operations = { -+ .create = exfat_create, -+ .lookup = exfat_lookup, -+ .unlink = exfat_unlink, -+ .mkdir = exfat_mkdir, -+ .rmdir = exfat_rmdir, -+ .rename = exfat_rename, -+ .setattr = exfat_setattr, -+ .getattr = exfat_getattr, -+}; --- -2.25.1 - diff --git a/kernel/kernel/files/patches/mageia/fs-exfat-add-misc-operations.patch b/kernel/kernel/files/patches/mageia/fs-exfat-add-misc-operations.patch deleted file mode 100644 index 5d461d19..00000000 --- a/kernel/kernel/files/patches/mageia/fs-exfat-add-misc-operations.patch +++ /dev/null @@ -1,193 +0,0 @@ -From 772b29cca528fcb21374bb3e597d848779938d16 Mon Sep 17 00:00:00 2001 -From: Namjae Jeon -Date: Mon, 2 Mar 2020 15:21:40 +0900 -Subject: [PATCH 09/14] exfat: add misc operations -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This adds the implementation of misc operations for exfat. - -Signed-off-by: Namjae Jeon -Signed-off-by: Sungjong Seo -Reviewed-by: Arnd Bergmann -Reviewed-by: Pali Rohár -Reviewed-by: Christoph Hellwig -Signed-off-by: Al Viro ---- - fs/exfat/misc.c | 163 ++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 163 insertions(+) - create mode 100644 fs/exfat/misc.c - -diff --git a/fs/exfat/misc.c b/fs/exfat/misc.c -new file mode 100644 -index 000000000000..14a3300848f6 ---- /dev/null -+++ b/fs/exfat/misc.c -@@ -0,0 +1,163 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Written 1992,1993 by Werner Almesberger -+ * 22/11/2000 - Fixed fat_date_unix2dos for dates earlier than 01/01/1980 -+ * and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru) -+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include "exfat_raw.h" -+#include "exfat_fs.h" -+ -+/* -+ * exfat_fs_error reports a file system problem that might indicate fa data -+ * corruption/inconsistency. Depending on 'errors' mount option the -+ * panic() is called, or error message is printed FAT and nothing is done, -+ * or filesystem is remounted read-only (default behavior). -+ * In case the file system is remounted read-only, it can be made writable -+ * again by remounting it. -+ */ -+void __exfat_fs_error(struct super_block *sb, int report, const char *fmt, ...) -+{ -+ struct exfat_mount_options *opts = &EXFAT_SB(sb)->options; -+ va_list args; -+ struct va_format vaf; -+ -+ if (report) { -+ va_start(args, fmt); -+ vaf.fmt = fmt; -+ vaf.va = &args; -+ exfat_msg(sb, KERN_ERR, "error, %pV\n", &vaf); -+ va_end(args); -+ } -+ -+ if (opts->errors == EXFAT_ERRORS_PANIC) { -+ panic("exFAT-fs (%s): fs panic from previous error\n", -+ sb->s_id); -+ } else if (opts->errors == EXFAT_ERRORS_RO && !sb_rdonly(sb)) { -+ sb->s_flags |= SB_RDONLY; -+ exfat_msg(sb, KERN_ERR, "Filesystem has been set read-only"); -+ } -+} -+ -+/* -+ * exfat_msg() - print preformated EXFAT specific messages. -+ * All logs except what uses exfat_fs_error() should be written by exfat_msg() -+ */ -+void exfat_msg(struct super_block *sb, const char *level, const char *fmt, ...) -+{ -+ struct va_format vaf; -+ va_list args; -+ -+ va_start(args, fmt); -+ vaf.fmt = fmt; -+ vaf.va = &args; -+ /* level means KERN_ pacility level */ -+ printk("%sexFAT-fs (%s): %pV\n", level, sb->s_id, &vaf); -+ va_end(args); -+} -+ -+#define SECS_PER_MIN (60) -+#define TIMEZONE_SEC(x) ((x) * 15 * SECS_PER_MIN) -+ -+static void exfat_adjust_tz(struct timespec64 *ts, u8 tz_off) -+{ -+ if (tz_off <= 0x3F) -+ ts->tv_sec -= TIMEZONE_SEC(tz_off); -+ else /* 0x40 <= (tz_off & 0x7F) <=0x7F */ -+ ts->tv_sec += TIMEZONE_SEC(0x80 - tz_off); -+} -+ -+/* Convert a EXFAT time/date pair to a UNIX date (seconds since 1 1 70). */ -+void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, -+ u8 tz, __le16 time, __le16 date, u8 time_ms) -+{ -+ u16 t = le16_to_cpu(time); -+ u16 d = le16_to_cpu(date); -+ -+ ts->tv_sec = mktime64(1980 + (d >> 9), d >> 5 & 0x000F, d & 0x001F, -+ t >> 11, (t >> 5) & 0x003F, (t & 0x001F) << 1); -+ -+ -+ /* time_ms field represent 0 ~ 199(1990 ms) */ -+ if (time_ms) { -+ ts->tv_sec += time_ms / 100; -+ ts->tv_nsec = (time_ms % 100) * 10 * NSEC_PER_MSEC; -+ } -+ -+ if (tz & EXFAT_TZ_VALID) -+ /* Adjust timezone to UTC0. */ -+ exfat_adjust_tz(ts, tz & ~EXFAT_TZ_VALID); -+ else -+ /* Convert from local time to UTC using time_offset. */ -+ ts->tv_sec -= sbi->options.time_offset * SECS_PER_MIN; -+} -+ -+/* Convert linear UNIX date to a EXFAT time/date pair. */ -+void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, -+ u8 *tz, __le16 *time, __le16 *date, u8 *time_ms) -+{ -+ struct tm tm; -+ u16 t, d; -+ -+ time64_to_tm(ts->tv_sec, 0, &tm); -+ t = (tm.tm_hour << 11) | (tm.tm_min << 5) | (tm.tm_sec >> 1); -+ d = ((tm.tm_year - 80) << 9) | ((tm.tm_mon + 1) << 5) | tm.tm_mday; -+ -+ *time = cpu_to_le16(t); -+ *date = cpu_to_le16(d); -+ -+ /* time_ms field represent 0 ~ 199(1990 ms) */ -+ if (time_ms) -+ *time_ms = (tm.tm_sec & 1) * 100 + -+ ts->tv_nsec / (10 * NSEC_PER_MSEC); -+ -+ /* -+ * Record 00h value for OffsetFromUtc field and 1 value for OffsetValid -+ * to indicate that local time and UTC are the same. -+ */ -+ *tz = EXFAT_TZ_VALID; -+} -+ -+unsigned short exfat_calc_chksum_2byte(void *data, int len, -+ unsigned short chksum, int type) -+{ -+ int i; -+ unsigned char *c = (unsigned char *)data; -+ -+ for (i = 0; i < len; i++, c++) { -+ if (((i == 2) || (i == 3)) && (type == CS_DIR_ENTRY)) -+ continue; -+ chksum = (((chksum & 1) << 15) | ((chksum & 0xFFFE) >> 1)) + -+ (unsigned short)*c; -+ } -+ return chksum; -+} -+ -+void exfat_update_bh(struct super_block *sb, struct buffer_head *bh, int sync) -+{ -+ set_bit(EXFAT_SB_DIRTY, &EXFAT_SB(sb)->s_state); -+ set_buffer_uptodate(bh); -+ mark_buffer_dirty(bh); -+ -+ if (sync) -+ sync_dirty_buffer(bh); -+} -+ -+void exfat_chain_set(struct exfat_chain *ec, unsigned int dir, -+ unsigned int size, unsigned char flags) -+{ -+ ec->dir = dir; -+ ec->size = size; -+ ec->flags = flags; -+} -+ -+void exfat_chain_dup(struct exfat_chain *dup, struct exfat_chain *ec) -+{ -+ return exfat_chain_set(dup, ec->dir, ec->size, ec->flags); -+} --- -2.25.1 - diff --git a/kernel/kernel/files/patches/mageia/fs-exfat-add-module_alias_fs.patch b/kernel/kernel/files/patches/mageia/fs-exfat-add-module_alias_fs.patch deleted file mode 100644 index 6232c18b..00000000 --- a/kernel/kernel/files/patches/mageia/fs-exfat-add-module_alias_fs.patch +++ /dev/null @@ -1,30 +0,0 @@ -From c37f83b424911f9bb6c9f17a4543c9c77cd73282 Mon Sep 17 00:00:00 2001 -From: Thomas Backlund -Date: Sat, 4 Apr 2020 23:00:31 +0300 -Subject: [PATCH v2] exfat: add missing MODULE_ALIAS_FS() - -This adds the necessary MODULE_ALIAS_FS() to exfat so the module gets -automatically loaded when an exfat filesystem is mounted. - -Signed-off-by: Thomas Backlund -Cc: Namjae Jeon -Cc: Sungjong Seo ---- - fs/exfat/super.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/fs/exfat/super.c b/fs/exfat/super.c -index 16ed202ef527..b4a4063a0272 100644 ---- a/fs/exfat/super.c -+++ b/fs/exfat/super.c -@@ -717,6 +717,7 @@ static void __exit exit_exfat_fs(void) - module_init(init_exfat_fs); - module_exit(exit_exfat_fs); - -+MODULE_ALIAS_FS("exfat"); - MODULE_LICENSE("GPL"); - MODULE_DESCRIPTION("exFAT filesystem support"); - MODULE_AUTHOR("Samsung Electronics Co., Ltd."); --- -2.26.0 - diff --git a/kernel/kernel/files/patches/mageia/fs-exfat-add-nls-operations.patch b/kernel/kernel/files/patches/mageia/fs-exfat-add-nls-operations.patch deleted file mode 100644 index 5c5792d5..00000000 --- a/kernel/kernel/files/patches/mageia/fs-exfat-add-nls-operations.patch +++ /dev/null @@ -1,860 +0,0 @@ -From 370e812b3ec190fa492c9fd5a80c38b086d105c0 Mon Sep 17 00:00:00 2001 -From: Namjae Jeon -Date: Mon, 2 Mar 2020 15:21:41 +0900 -Subject: [PATCH 10/14] exfat: add nls operations -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This adds the implementation of nls operations for exfat. - -Signed-off-by: Namjae Jeon -Signed-off-by: Sungjong Seo -Reviewed-by: Pali Rohár -Reviewed-by: Christoph Hellwig -Signed-off-by: Al Viro ---- - fs/exfat/nls.c | 831 +++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 831 insertions(+) - create mode 100644 fs/exfat/nls.c - -diff --git a/fs/exfat/nls.c b/fs/exfat/nls.c -new file mode 100644 -index 000000000000..6d1c3ae130ff ---- /dev/null -+++ b/fs/exfat/nls.c -@@ -0,0 +1,831 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include "exfat_raw.h" -+#include "exfat_fs.h" -+ -+/* Upcase tabel macro */ -+#define EXFAT_NUM_UPCASE (2918) -+#define UTBL_COUNT (0x10000) -+ -+/* -+ * Upcase table in compressed format (7.2.5.1 Recommended Up-case Table -+ * in exfat specification, See: -+ * https://docs.microsoft.com/en-us/windows/win32/fileio/exfat-specification). -+ */ -+static const unsigned short uni_def_upcase[EXFAT_NUM_UPCASE] = { -+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, -+ 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, -+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, -+ 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, -+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, -+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, -+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, -+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, -+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, -+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, -+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, -+ 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, -+ 0x0060, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, -+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, -+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, -+ 0x0058, 0x0059, 0x005a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, -+ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, -+ 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, -+ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, -+ 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, -+ 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, -+ 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, -+ 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, -+ 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, -+ 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, -+ 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, -+ 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, -+ 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, -+ 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, -+ 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, -+ 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00f7, -+ 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x0178, -+ 0x0100, 0x0100, 0x0102, 0x0102, 0x0104, 0x0104, 0x0106, 0x0106, -+ 0x0108, 0x0108, 0x010a, 0x010a, 0x010c, 0x010c, 0x010e, 0x010e, -+ 0x0110, 0x0110, 0x0112, 0x0112, 0x0114, 0x0114, 0x0116, 0x0116, -+ 0x0118, 0x0118, 0x011a, 0x011a, 0x011c, 0x011c, 0x011e, 0x011e, -+ 0x0120, 0x0120, 0x0122, 0x0122, 0x0124, 0x0124, 0x0126, 0x0126, -+ 0x0128, 0x0128, 0x012a, 0x012a, 0x012c, 0x012c, 0x012e, 0x012e, -+ 0x0130, 0x0131, 0x0132, 0x0132, 0x0134, 0x0134, 0x0136, 0x0136, -+ 0x0138, 0x0139, 0x0139, 0x013b, 0x013b, 0x013d, 0x013d, 0x013f, -+ 0x013f, 0x0141, 0x0141, 0x0143, 0x0143, 0x0145, 0x0145, 0x0147, -+ 0x0147, 0x0149, 0x014a, 0x014a, 0x014c, 0x014c, 0x014e, 0x014e, -+ 0x0150, 0x0150, 0x0152, 0x0152, 0x0154, 0x0154, 0x0156, 0x0156, -+ 0x0158, 0x0158, 0x015a, 0x015a, 0x015c, 0x015c, 0x015e, 0x015e, -+ 0x0160, 0x0160, 0x0162, 0x0162, 0x0164, 0x0164, 0x0166, 0x0166, -+ 0x0168, 0x0168, 0x016a, 0x016a, 0x016c, 0x016c, 0x016e, 0x016e, -+ 0x0170, 0x0170, 0x0172, 0x0172, 0x0174, 0x0174, 0x0176, 0x0176, -+ 0x0178, 0x0179, 0x0179, 0x017b, 0x017b, 0x017d, 0x017d, 0x017f, -+ 0x0243, 0x0181, 0x0182, 0x0182, 0x0184, 0x0184, 0x0186, 0x0187, -+ 0x0187, 0x0189, 0x018a, 0x018b, 0x018b, 0x018d, 0x018e, 0x018f, -+ 0x0190, 0x0191, 0x0191, 0x0193, 0x0194, 0x01f6, 0x0196, 0x0197, -+ 0x0198, 0x0198, 0x023d, 0x019b, 0x019c, 0x019d, 0x0220, 0x019f, -+ 0x01a0, 0x01a0, 0x01a2, 0x01a2, 0x01a4, 0x01a4, 0x01a6, 0x01a7, -+ 0x01a7, 0x01a9, 0x01aa, 0x01ab, 0x01ac, 0x01ac, 0x01ae, 0x01af, -+ 0x01af, 0x01b1, 0x01b2, 0x01b3, 0x01b3, 0x01b5, 0x01b5, 0x01b7, -+ 0x01b8, 0x01b8, 0x01ba, 0x01bb, 0x01bc, 0x01bc, 0x01be, 0x01f7, -+ 0x01c0, 0x01c1, 0x01c2, 0x01c3, 0x01c4, 0x01c5, 0x01c4, 0x01c7, -+ 0x01c8, 0x01c7, 0x01ca, 0x01cb, 0x01ca, 0x01cd, 0x01cd, 0x01cf, -+ 0x01cf, 0x01d1, 0x01d1, 0x01d3, 0x01d3, 0x01d5, 0x01d5, 0x01d7, -+ 0x01d7, 0x01d9, 0x01d9, 0x01db, 0x01db, 0x018e, 0x01de, 0x01de, -+ 0x01e0, 0x01e0, 0x01e2, 0x01e2, 0x01e4, 0x01e4, 0x01e6, 0x01e6, -+ 0x01e8, 0x01e8, 0x01ea, 0x01ea, 0x01ec, 0x01ec, 0x01ee, 0x01ee, -+ 0x01f0, 0x01f1, 0x01f2, 0x01f1, 0x01f4, 0x01f4, 0x01f6, 0x01f7, -+ 0x01f8, 0x01f8, 0x01fa, 0x01fa, 0x01fc, 0x01fc, 0x01fe, 0x01fe, -+ 0x0200, 0x0200, 0x0202, 0x0202, 0x0204, 0x0204, 0x0206, 0x0206, -+ 0x0208, 0x0208, 0x020a, 0x020a, 0x020c, 0x020c, 0x020e, 0x020e, -+ 0x0210, 0x0210, 0x0212, 0x0212, 0x0214, 0x0214, 0x0216, 0x0216, -+ 0x0218, 0x0218, 0x021a, 0x021a, 0x021c, 0x021c, 0x021e, 0x021e, -+ 0x0220, 0x0221, 0x0222, 0x0222, 0x0224, 0x0224, 0x0226, 0x0226, -+ 0x0228, 0x0228, 0x022a, 0x022a, 0x022c, 0x022c, 0x022e, 0x022e, -+ 0x0230, 0x0230, 0x0232, 0x0232, 0x0234, 0x0235, 0x0236, 0x0237, -+ 0x0238, 0x0239, 0x2c65, 0x023b, 0x023b, 0x023d, 0x2c66, 0x023f, -+ 0x0240, 0x0241, 0x0241, 0x0243, 0x0244, 0x0245, 0x0246, 0x0246, -+ 0x0248, 0x0248, 0x024a, 0x024a, 0x024c, 0x024c, 0x024e, 0x024e, -+ 0x0250, 0x0251, 0x0252, 0x0181, 0x0186, 0x0255, 0x0189, 0x018a, -+ 0x0258, 0x018f, 0x025a, 0x0190, 0x025c, 0x025d, 0x025e, 0x025f, -+ 0x0193, 0x0261, 0x0262, 0x0194, 0x0264, 0x0265, 0x0266, 0x0267, -+ 0x0197, 0x0196, 0x026a, 0x2c62, 0x026c, 0x026d, 0x026e, 0x019c, -+ 0x0270, 0x0271, 0x019d, 0x0273, 0x0274, 0x019f, 0x0276, 0x0277, -+ 0x0278, 0x0279, 0x027a, 0x027b, 0x027c, 0x2c64, 0x027e, 0x027f, -+ 0x01a6, 0x0281, 0x0282, 0x01a9, 0x0284, 0x0285, 0x0286, 0x0287, -+ 0x01ae, 0x0244, 0x01b1, 0x01b2, 0x0245, 0x028d, 0x028e, 0x028f, -+ 0x0290, 0x0291, 0x01b7, 0x0293, 0x0294, 0x0295, 0x0296, 0x0297, -+ 0x0298, 0x0299, 0x029a, 0x029b, 0x029c, 0x029d, 0x029e, 0x029f, -+ 0x02a0, 0x02a1, 0x02a2, 0x02a3, 0x02a4, 0x02a5, 0x02a6, 0x02a7, -+ 0x02a8, 0x02a9, 0x02aa, 0x02ab, 0x02ac, 0x02ad, 0x02ae, 0x02af, -+ 0x02b0, 0x02b1, 0x02b2, 0x02b3, 0x02b4, 0x02b5, 0x02b6, 0x02b7, -+ 0x02b8, 0x02b9, 0x02ba, 0x02bb, 0x02bc, 0x02bd, 0x02be, 0x02bf, -+ 0x02c0, 0x02c1, 0x02c2, 0x02c3, 0x02c4, 0x02c5, 0x02c6, 0x02c7, -+ 0x02c8, 0x02c9, 0x02ca, 0x02cb, 0x02cc, 0x02cd, 0x02ce, 0x02cf, -+ 0x02d0, 0x02d1, 0x02d2, 0x02d3, 0x02d4, 0x02d5, 0x02d6, 0x02d7, -+ 0x02d8, 0x02d9, 0x02da, 0x02db, 0x02dc, 0x02dd, 0x02de, 0x02df, -+ 0x02e0, 0x02e1, 0x02e2, 0x02e3, 0x02e4, 0x02e5, 0x02e6, 0x02e7, -+ 0x02e8, 0x02e9, 0x02ea, 0x02eb, 0x02ec, 0x02ed, 0x02ee, 0x02ef, -+ 0x02f0, 0x02f1, 0x02f2, 0x02f3, 0x02f4, 0x02f5, 0x02f6, 0x02f7, -+ 0x02f8, 0x02f9, 0x02fa, 0x02fb, 0x02fc, 0x02fd, 0x02fe, 0x02ff, -+ 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, -+ 0x0308, 0x0309, 0x030a, 0x030b, 0x030c, 0x030d, 0x030e, 0x030f, -+ 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317, -+ 0x0318, 0x0319, 0x031a, 0x031b, 0x031c, 0x031d, 0x031e, 0x031f, -+ 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327, -+ 0x0328, 0x0329, 0x032a, 0x032b, 0x032c, 0x032d, 0x032e, 0x032f, -+ 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337, -+ 0x0338, 0x0339, 0x033a, 0x033b, 0x033c, 0x033d, 0x033e, 0x033f, -+ 0x0340, 0x0341, 0x0342, 0x0343, 0x0344, 0x0345, 0x0346, 0x0347, -+ 0x0348, 0x0349, 0x034a, 0x034b, 0x034c, 0x034d, 0x034e, 0x034f, -+ 0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357, -+ 0x0358, 0x0359, 0x035a, 0x035b, 0x035c, 0x035d, 0x035e, 0x035f, -+ 0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367, -+ 0x0368, 0x0369, 0x036a, 0x036b, 0x036c, 0x036d, 0x036e, 0x036f, -+ 0x0370, 0x0371, 0x0372, 0x0373, 0x0374, 0x0375, 0x0376, 0x0377, -+ 0x0378, 0x0379, 0x037a, 0x03fd, 0x03fe, 0x03ff, 0x037e, 0x037f, -+ 0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0386, 0x0387, -+ 0x0388, 0x0389, 0x038a, 0x038b, 0x038c, 0x038d, 0x038e, 0x038f, -+ 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, -+ 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, -+ 0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, -+ 0x03a8, 0x03a9, 0x03aa, 0x03ab, 0x0386, 0x0388, 0x0389, 0x038a, -+ 0x03b0, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, -+ 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, -+ 0x03a0, 0x03a1, 0x03a3, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, -+ 0x03a8, 0x03a9, 0x03aa, 0x03ab, 0x038c, 0x038e, 0x038f, 0x03cf, -+ 0x03d0, 0x03d1, 0x03d2, 0x03d3, 0x03d4, 0x03d5, 0x03d6, 0x03d7, -+ 0x03d8, 0x03d8, 0x03da, 0x03da, 0x03dc, 0x03dc, 0x03de, 0x03de, -+ 0x03e0, 0x03e0, 0x03e2, 0x03e2, 0x03e4, 0x03e4, 0x03e6, 0x03e6, -+ 0x03e8, 0x03e8, 0x03ea, 0x03ea, 0x03ec, 0x03ec, 0x03ee, 0x03ee, -+ 0x03f0, 0x03f1, 0x03f9, 0x03f3, 0x03f4, 0x03f5, 0x03f6, 0x03f7, -+ 0x03f7, 0x03f9, 0x03fa, 0x03fa, 0x03fc, 0x03fd, 0x03fe, 0x03ff, -+ 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, -+ 0x0408, 0x0409, 0x040a, 0x040b, 0x040c, 0x040d, 0x040e, 0x040f, -+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, -+ 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, -+ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, -+ 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, -+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, -+ 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, -+ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, -+ 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, -+ 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, -+ 0x0408, 0x0409, 0x040a, 0x040b, 0x040c, 0x040d, 0x040e, 0x040f, -+ 0x0460, 0x0460, 0x0462, 0x0462, 0x0464, 0x0464, 0x0466, 0x0466, -+ 0x0468, 0x0468, 0x046a, 0x046a, 0x046c, 0x046c, 0x046e, 0x046e, -+ 0x0470, 0x0470, 0x0472, 0x0472, 0x0474, 0x0474, 0x0476, 0x0476, -+ 0x0478, 0x0478, 0x047a, 0x047a, 0x047c, 0x047c, 0x047e, 0x047e, -+ 0x0480, 0x0480, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, -+ 0x0488, 0x0489, 0x048a, 0x048a, 0x048c, 0x048c, 0x048e, 0x048e, -+ 0x0490, 0x0490, 0x0492, 0x0492, 0x0494, 0x0494, 0x0496, 0x0496, -+ 0x0498, 0x0498, 0x049a, 0x049a, 0x049c, 0x049c, 0x049e, 0x049e, -+ 0x04a0, 0x04a0, 0x04a2, 0x04a2, 0x04a4, 0x04a4, 0x04a6, 0x04a6, -+ 0x04a8, 0x04a8, 0x04aa, 0x04aa, 0x04ac, 0x04ac, 0x04ae, 0x04ae, -+ 0x04b0, 0x04b0, 0x04b2, 0x04b2, 0x04b4, 0x04b4, 0x04b6, 0x04b6, -+ 0x04b8, 0x04b8, 0x04ba, 0x04ba, 0x04bc, 0x04bc, 0x04be, 0x04be, -+ 0x04c0, 0x04c1, 0x04c1, 0x04c3, 0x04c3, 0x04c5, 0x04c5, 0x04c7, -+ 0x04c7, 0x04c9, 0x04c9, 0x04cb, 0x04cb, 0x04cd, 0x04cd, 0x04c0, -+ 0x04d0, 0x04d0, 0x04d2, 0x04d2, 0x04d4, 0x04d4, 0x04d6, 0x04d6, -+ 0x04d8, 0x04d8, 0x04da, 0x04da, 0x04dc, 0x04dc, 0x04de, 0x04de, -+ 0x04e0, 0x04e0, 0x04e2, 0x04e2, 0x04e4, 0x04e4, 0x04e6, 0x04e6, -+ 0x04e8, 0x04e8, 0x04ea, 0x04ea, 0x04ec, 0x04ec, 0x04ee, 0x04ee, -+ 0x04f0, 0x04f0, 0x04f2, 0x04f2, 0x04f4, 0x04f4, 0x04f6, 0x04f6, -+ 0x04f8, 0x04f8, 0x04fa, 0x04fa, 0x04fc, 0x04fc, 0x04fe, 0x04fe, -+ 0x0500, 0x0500, 0x0502, 0x0502, 0x0504, 0x0504, 0x0506, 0x0506, -+ 0x0508, 0x0508, 0x050a, 0x050a, 0x050c, 0x050c, 0x050e, 0x050e, -+ 0x0510, 0x0510, 0x0512, 0x0512, 0x0514, 0x0515, 0x0516, 0x0517, -+ 0x0518, 0x0519, 0x051a, 0x051b, 0x051c, 0x051d, 0x051e, 0x051f, -+ 0x0520, 0x0521, 0x0522, 0x0523, 0x0524, 0x0525, 0x0526, 0x0527, -+ 0x0528, 0x0529, 0x052a, 0x052b, 0x052c, 0x052d, 0x052e, 0x052f, -+ 0x0530, 0x0531, 0x0532, 0x0533, 0x0534, 0x0535, 0x0536, 0x0537, -+ 0x0538, 0x0539, 0x053a, 0x053b, 0x053c, 0x053d, 0x053e, 0x053f, -+ 0x0540, 0x0541, 0x0542, 0x0543, 0x0544, 0x0545, 0x0546, 0x0547, -+ 0x0548, 0x0549, 0x054a, 0x054b, 0x054c, 0x054d, 0x054e, 0x054f, -+ 0x0550, 0x0551, 0x0552, 0x0553, 0x0554, 0x0555, 0x0556, 0x0557, -+ 0x0558, 0x0559, 0x055a, 0x055b, 0x055c, 0x055d, 0x055e, 0x055f, -+ 0x0560, 0x0531, 0x0532, 0x0533, 0x0534, 0x0535, 0x0536, 0x0537, -+ 0x0538, 0x0539, 0x053a, 0x053b, 0x053c, 0x053d, 0x053e, 0x053f, -+ 0x0540, 0x0541, 0x0542, 0x0543, 0x0544, 0x0545, 0x0546, 0x0547, -+ 0x0548, 0x0549, 0x054a, 0x054b, 0x054c, 0x054d, 0x054e, 0x054f, -+ 0x0550, 0x0551, 0x0552, 0x0553, 0x0554, 0x0555, 0x0556, 0xffff, -+ 0x17f6, 0x2c63, 0x1d7e, 0x1d7f, 0x1d80, 0x1d81, 0x1d82, 0x1d83, -+ 0x1d84, 0x1d85, 0x1d86, 0x1d87, 0x1d88, 0x1d89, 0x1d8a, 0x1d8b, -+ 0x1d8c, 0x1d8d, 0x1d8e, 0x1d8f, 0x1d90, 0x1d91, 0x1d92, 0x1d93, -+ 0x1d94, 0x1d95, 0x1d96, 0x1d97, 0x1d98, 0x1d99, 0x1d9a, 0x1d9b, -+ 0x1d9c, 0x1d9d, 0x1d9e, 0x1d9f, 0x1da0, 0x1da1, 0x1da2, 0x1da3, -+ 0x1da4, 0x1da5, 0x1da6, 0x1da7, 0x1da8, 0x1da9, 0x1daa, 0x1dab, -+ 0x1dac, 0x1dad, 0x1dae, 0x1daf, 0x1db0, 0x1db1, 0x1db2, 0x1db3, -+ 0x1db4, 0x1db5, 0x1db6, 0x1db7, 0x1db8, 0x1db9, 0x1dba, 0x1dbb, -+ 0x1dbc, 0x1dbd, 0x1dbe, 0x1dbf, 0x1dc0, 0x1dc1, 0x1dc2, 0x1dc3, -+ 0x1dc4, 0x1dc5, 0x1dc6, 0x1dc7, 0x1dc8, 0x1dc9, 0x1dca, 0x1dcb, -+ 0x1dcc, 0x1dcd, 0x1dce, 0x1dcf, 0x1dd0, 0x1dd1, 0x1dd2, 0x1dd3, -+ 0x1dd4, 0x1dd5, 0x1dd6, 0x1dd7, 0x1dd8, 0x1dd9, 0x1dda, 0x1ddb, -+ 0x1ddc, 0x1ddd, 0x1dde, 0x1ddf, 0x1de0, 0x1de1, 0x1de2, 0x1de3, -+ 0x1de4, 0x1de5, 0x1de6, 0x1de7, 0x1de8, 0x1de9, 0x1dea, 0x1deb, -+ 0x1dec, 0x1ded, 0x1dee, 0x1def, 0x1df0, 0x1df1, 0x1df2, 0x1df3, -+ 0x1df4, 0x1df5, 0x1df6, 0x1df7, 0x1df8, 0x1df9, 0x1dfa, 0x1dfb, -+ 0x1dfc, 0x1dfd, 0x1dfe, 0x1dff, 0x1e00, 0x1e00, 0x1e02, 0x1e02, -+ 0x1e04, 0x1e04, 0x1e06, 0x1e06, 0x1e08, 0x1e08, 0x1e0a, 0x1e0a, -+ 0x1e0c, 0x1e0c, 0x1e0e, 0x1e0e, 0x1e10, 0x1e10, 0x1e12, 0x1e12, -+ 0x1e14, 0x1e14, 0x1e16, 0x1e16, 0x1e18, 0x1e18, 0x1e1a, 0x1e1a, -+ 0x1e1c, 0x1e1c, 0x1e1e, 0x1e1e, 0x1e20, 0x1e20, 0x1e22, 0x1e22, -+ 0x1e24, 0x1e24, 0x1e26, 0x1e26, 0x1e28, 0x1e28, 0x1e2a, 0x1e2a, -+ 0x1e2c, 0x1e2c, 0x1e2e, 0x1e2e, 0x1e30, 0x1e30, 0x1e32, 0x1e32, -+ 0x1e34, 0x1e34, 0x1e36, 0x1e36, 0x1e38, 0x1e38, 0x1e3a, 0x1e3a, -+ 0x1e3c, 0x1e3c, 0x1e3e, 0x1e3e, 0x1e40, 0x1e40, 0x1e42, 0x1e42, -+ 0x1e44, 0x1e44, 0x1e46, 0x1e46, 0x1e48, 0x1e48, 0x1e4a, 0x1e4a, -+ 0x1e4c, 0x1e4c, 0x1e4e, 0x1e4e, 0x1e50, 0x1e50, 0x1e52, 0x1e52, -+ 0x1e54, 0x1e54, 0x1e56, 0x1e56, 0x1e58, 0x1e58, 0x1e5a, 0x1e5a, -+ 0x1e5c, 0x1e5c, 0x1e5e, 0x1e5e, 0x1e60, 0x1e60, 0x1e62, 0x1e62, -+ 0x1e64, 0x1e64, 0x1e66, 0x1e66, 0x1e68, 0x1e68, 0x1e6a, 0x1e6a, -+ 0x1e6c, 0x1e6c, 0x1e6e, 0x1e6e, 0x1e70, 0x1e70, 0x1e72, 0x1e72, -+ 0x1e74, 0x1e74, 0x1e76, 0x1e76, 0x1e78, 0x1e78, 0x1e7a, 0x1e7a, -+ 0x1e7c, 0x1e7c, 0x1e7e, 0x1e7e, 0x1e80, 0x1e80, 0x1e82, 0x1e82, -+ 0x1e84, 0x1e84, 0x1e86, 0x1e86, 0x1e88, 0x1e88, 0x1e8a, 0x1e8a, -+ 0x1e8c, 0x1e8c, 0x1e8e, 0x1e8e, 0x1e90, 0x1e90, 0x1e92, 0x1e92, -+ 0x1e94, 0x1e94, 0x1e96, 0x1e97, 0x1e98, 0x1e99, 0x1e9a, 0x1e9b, -+ 0x1e9c, 0x1e9d, 0x1e9e, 0x1e9f, 0x1ea0, 0x1ea0, 0x1ea2, 0x1ea2, -+ 0x1ea4, 0x1ea4, 0x1ea6, 0x1ea6, 0x1ea8, 0x1ea8, 0x1eaa, 0x1eaa, -+ 0x1eac, 0x1eac, 0x1eae, 0x1eae, 0x1eb0, 0x1eb0, 0x1eb2, 0x1eb2, -+ 0x1eb4, 0x1eb4, 0x1eb6, 0x1eb6, 0x1eb8, 0x1eb8, 0x1eba, 0x1eba, -+ 0x1ebc, 0x1ebc, 0x1ebe, 0x1ebe, 0x1ec0, 0x1ec0, 0x1ec2, 0x1ec2, -+ 0x1ec4, 0x1ec4, 0x1ec6, 0x1ec6, 0x1ec8, 0x1ec8, 0x1eca, 0x1eca, -+ 0x1ecc, 0x1ecc, 0x1ece, 0x1ece, 0x1ed0, 0x1ed0, 0x1ed2, 0x1ed2, -+ 0x1ed4, 0x1ed4, 0x1ed6, 0x1ed6, 0x1ed8, 0x1ed8, 0x1eda, 0x1eda, -+ 0x1edc, 0x1edc, 0x1ede, 0x1ede, 0x1ee0, 0x1ee0, 0x1ee2, 0x1ee2, -+ 0x1ee4, 0x1ee4, 0x1ee6, 0x1ee6, 0x1ee8, 0x1ee8, 0x1eea, 0x1eea, -+ 0x1eec, 0x1eec, 0x1eee, 0x1eee, 0x1ef0, 0x1ef0, 0x1ef2, 0x1ef2, -+ 0x1ef4, 0x1ef4, 0x1ef6, 0x1ef6, 0x1ef8, 0x1ef8, 0x1efa, 0x1efb, -+ 0x1efc, 0x1efd, 0x1efe, 0x1eff, 0x1f08, 0x1f09, 0x1f0a, 0x1f0b, -+ 0x1f0c, 0x1f0d, 0x1f0e, 0x1f0f, 0x1f08, 0x1f09, 0x1f0a, 0x1f0b, -+ 0x1f0c, 0x1f0d, 0x1f0e, 0x1f0f, 0x1f18, 0x1f19, 0x1f1a, 0x1f1b, -+ 0x1f1c, 0x1f1d, 0x1f16, 0x1f17, 0x1f18, 0x1f19, 0x1f1a, 0x1f1b, -+ 0x1f1c, 0x1f1d, 0x1f1e, 0x1f1f, 0x1f28, 0x1f29, 0x1f2a, 0x1f2b, -+ 0x1f2c, 0x1f2d, 0x1f2e, 0x1f2f, 0x1f28, 0x1f29, 0x1f2a, 0x1f2b, -+ 0x1f2c, 0x1f2d, 0x1f2e, 0x1f2f, 0x1f38, 0x1f39, 0x1f3a, 0x1f3b, -+ 0x1f3c, 0x1f3d, 0x1f3e, 0x1f3f, 0x1f38, 0x1f39, 0x1f3a, 0x1f3b, -+ 0x1f3c, 0x1f3d, 0x1f3e, 0x1f3f, 0x1f48, 0x1f49, 0x1f4a, 0x1f4b, -+ 0x1f4c, 0x1f4d, 0x1f46, 0x1f47, 0x1f48, 0x1f49, 0x1f4a, 0x1f4b, -+ 0x1f4c, 0x1f4d, 0x1f4e, 0x1f4f, 0x1f50, 0x1f59, 0x1f52, 0x1f5b, -+ 0x1f54, 0x1f5d, 0x1f56, 0x1f5f, 0x1f58, 0x1f59, 0x1f5a, 0x1f5b, -+ 0x1f5c, 0x1f5d, 0x1f5e, 0x1f5f, 0x1f68, 0x1f69, 0x1f6a, 0x1f6b, -+ 0x1f6c, 0x1f6d, 0x1f6e, 0x1f6f, 0x1f68, 0x1f69, 0x1f6a, 0x1f6b, -+ 0x1f6c, 0x1f6d, 0x1f6e, 0x1f6f, 0x1fba, 0x1fbb, 0x1fc8, 0x1fc9, -+ 0x1fca, 0x1fcb, 0x1fda, 0x1fdb, 0x1ff8, 0x1ff9, 0x1fea, 0x1feb, -+ 0x1ffa, 0x1ffb, 0x1f7e, 0x1f7f, 0x1f88, 0x1f89, 0x1f8a, 0x1f8b, -+ 0x1f8c, 0x1f8d, 0x1f8e, 0x1f8f, 0x1f88, 0x1f89, 0x1f8a, 0x1f8b, -+ 0x1f8c, 0x1f8d, 0x1f8e, 0x1f8f, 0x1f98, 0x1f99, 0x1f9a, 0x1f9b, -+ 0x1f9c, 0x1f9d, 0x1f9e, 0x1f9f, 0x1f98, 0x1f99, 0x1f9a, 0x1f9b, -+ 0x1f9c, 0x1f9d, 0x1f9e, 0x1f9f, 0x1fa8, 0x1fa9, 0x1faa, 0x1fab, -+ 0x1fac, 0x1fad, 0x1fae, 0x1faf, 0x1fa8, 0x1fa9, 0x1faa, 0x1fab, -+ 0x1fac, 0x1fad, 0x1fae, 0x1faf, 0x1fb8, 0x1fb9, 0x1fb2, 0x1fbc, -+ 0x1fb4, 0x1fb5, 0x1fb6, 0x1fb7, 0x1fb8, 0x1fb9, 0x1fba, 0x1fbb, -+ 0x1fbc, 0x1fbd, 0x1fbe, 0x1fbf, 0x1fc0, 0x1fc1, 0x1fc2, 0x1fc3, -+ 0x1fc4, 0x1fc5, 0x1fc6, 0x1fc7, 0x1fc8, 0x1fc9, 0x1fca, 0x1fcb, -+ 0x1fc3, 0x1fcd, 0x1fce, 0x1fcf, 0x1fd8, 0x1fd9, 0x1fd2, 0x1fd3, -+ 0x1fd4, 0x1fd5, 0x1fd6, 0x1fd7, 0x1fd8, 0x1fd9, 0x1fda, 0x1fdb, -+ 0x1fdc, 0x1fdd, 0x1fde, 0x1fdf, 0x1fe8, 0x1fe9, 0x1fe2, 0x1fe3, -+ 0x1fe4, 0x1fec, 0x1fe6, 0x1fe7, 0x1fe8, 0x1fe9, 0x1fea, 0x1feb, -+ 0x1fec, 0x1fed, 0x1fee, 0x1fef, 0x1ff0, 0x1ff1, 0x1ff2, 0x1ff3, -+ 0x1ff4, 0x1ff5, 0x1ff6, 0x1ff7, 0x1ff8, 0x1ff9, 0x1ffa, 0x1ffb, -+ 0x1ff3, 0x1ffd, 0x1ffe, 0x1fff, 0x2000, 0x2001, 0x2002, 0x2003, -+ 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200a, 0x200b, -+ 0x200c, 0x200d, 0x200e, 0x200f, 0x2010, 0x2011, 0x2012, 0x2013, -+ 0x2014, 0x2015, 0x2016, 0x2017, 0x2018, 0x2019, 0x201a, 0x201b, -+ 0x201c, 0x201d, 0x201e, 0x201f, 0x2020, 0x2021, 0x2022, 0x2023, -+ 0x2024, 0x2025, 0x2026, 0x2027, 0x2028, 0x2029, 0x202a, 0x202b, -+ 0x202c, 0x202d, 0x202e, 0x202f, 0x2030, 0x2031, 0x2032, 0x2033, -+ 0x2034, 0x2035, 0x2036, 0x2037, 0x2038, 0x2039, 0x203a, 0x203b, -+ 0x203c, 0x203d, 0x203e, 0x203f, 0x2040, 0x2041, 0x2042, 0x2043, -+ 0x2044, 0x2045, 0x2046, 0x2047, 0x2048, 0x2049, 0x204a, 0x204b, -+ 0x204c, 0x204d, 0x204e, 0x204f, 0x2050, 0x2051, 0x2052, 0x2053, -+ 0x2054, 0x2055, 0x2056, 0x2057, 0x2058, 0x2059, 0x205a, 0x205b, -+ 0x205c, 0x205d, 0x205e, 0x205f, 0x2060, 0x2061, 0x2062, 0x2063, -+ 0x2064, 0x2065, 0x2066, 0x2067, 0x2068, 0x2069, 0x206a, 0x206b, -+ 0x206c, 0x206d, 0x206e, 0x206f, 0x2070, 0x2071, 0x2072, 0x2073, -+ 0x2074, 0x2075, 0x2076, 0x2077, 0x2078, 0x2079, 0x207a, 0x207b, -+ 0x207c, 0x207d, 0x207e, 0x207f, 0x2080, 0x2081, 0x2082, 0x2083, -+ 0x2084, 0x2085, 0x2086, 0x2087, 0x2088, 0x2089, 0x208a, 0x208b, -+ 0x208c, 0x208d, 0x208e, 0x208f, 0x2090, 0x2091, 0x2092, 0x2093, -+ 0x2094, 0x2095, 0x2096, 0x2097, 0x2098, 0x2099, 0x209a, 0x209b, -+ 0x209c, 0x209d, 0x209e, 0x209f, 0x20a0, 0x20a1, 0x20a2, 0x20a3, -+ 0x20a4, 0x20a5, 0x20a6, 0x20a7, 0x20a8, 0x20a9, 0x20aa, 0x20ab, -+ 0x20ac, 0x20ad, 0x20ae, 0x20af, 0x20b0, 0x20b1, 0x20b2, 0x20b3, -+ 0x20b4, 0x20b5, 0x20b6, 0x20b7, 0x20b8, 0x20b9, 0x20ba, 0x20bb, -+ 0x20bc, 0x20bd, 0x20be, 0x20bf, 0x20c0, 0x20c1, 0x20c2, 0x20c3, -+ 0x20c4, 0x20c5, 0x20c6, 0x20c7, 0x20c8, 0x20c9, 0x20ca, 0x20cb, -+ 0x20cc, 0x20cd, 0x20ce, 0x20cf, 0x20d0, 0x20d1, 0x20d2, 0x20d3, -+ 0x20d4, 0x20d5, 0x20d6, 0x20d7, 0x20d8, 0x20d9, 0x20da, 0x20db, -+ 0x20dc, 0x20dd, 0x20de, 0x20df, 0x20e0, 0x20e1, 0x20e2, 0x20e3, -+ 0x20e4, 0x20e5, 0x20e6, 0x20e7, 0x20e8, 0x20e9, 0x20ea, 0x20eb, -+ 0x20ec, 0x20ed, 0x20ee, 0x20ef, 0x20f0, 0x20f1, 0x20f2, 0x20f3, -+ 0x20f4, 0x20f5, 0x20f6, 0x20f7, 0x20f8, 0x20f9, 0x20fa, 0x20fb, -+ 0x20fc, 0x20fd, 0x20fe, 0x20ff, 0x2100, 0x2101, 0x2102, 0x2103, -+ 0x2104, 0x2105, 0x2106, 0x2107, 0x2108, 0x2109, 0x210a, 0x210b, -+ 0x210c, 0x210d, 0x210e, 0x210f, 0x2110, 0x2111, 0x2112, 0x2113, -+ 0x2114, 0x2115, 0x2116, 0x2117, 0x2118, 0x2119, 0x211a, 0x211b, -+ 0x211c, 0x211d, 0x211e, 0x211f, 0x2120, 0x2121, 0x2122, 0x2123, -+ 0x2124, 0x2125, 0x2126, 0x2127, 0x2128, 0x2129, 0x212a, 0x212b, -+ 0x212c, 0x212d, 0x212e, 0x212f, 0x2130, 0x2131, 0x2132, 0x2133, -+ 0x2134, 0x2135, 0x2136, 0x2137, 0x2138, 0x2139, 0x213a, 0x213b, -+ 0x213c, 0x213d, 0x213e, 0x213f, 0x2140, 0x2141, 0x2142, 0x2143, -+ 0x2144, 0x2145, 0x2146, 0x2147, 0x2148, 0x2149, 0x214a, 0x214b, -+ 0x214c, 0x214d, 0x2132, 0x214f, 0x2150, 0x2151, 0x2152, 0x2153, -+ 0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159, 0x215a, 0x215b, -+ 0x215c, 0x215d, 0x215e, 0x215f, 0x2160, 0x2161, 0x2162, 0x2163, -+ 0x2164, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0x216a, 0x216b, -+ 0x216c, 0x216d, 0x216e, 0x216f, 0x2160, 0x2161, 0x2162, 0x2163, -+ 0x2164, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0x216a, 0x216b, -+ 0x216c, 0x216d, 0x216e, 0x216f, 0x2180, 0x2181, 0x2182, 0x2183, -+ 0x2183, 0xffff, 0x034b, 0x24b6, 0x24b7, 0x24b8, 0x24b9, 0x24ba, -+ 0x24bb, 0x24bc, 0x24bd, 0x24be, 0x24bf, 0x24c0, 0x24c1, 0x24c2, -+ 0x24c3, 0x24c4, 0x24c5, 0x24c6, 0x24c7, 0x24c8, 0x24c9, 0x24ca, -+ 0x24cb, 0x24cc, 0x24cd, 0x24ce, 0x24cf, 0xffff, 0x0746, 0x2c00, -+ 0x2c01, 0x2c02, 0x2c03, 0x2c04, 0x2c05, 0x2c06, 0x2c07, 0x2c08, -+ 0x2c09, 0x2c0a, 0x2c0b, 0x2c0c, 0x2c0d, 0x2c0e, 0x2c0f, 0x2c10, -+ 0x2c11, 0x2c12, 0x2c13, 0x2c14, 0x2c15, 0x2c16, 0x2c17, 0x2c18, -+ 0x2c19, 0x2c1a, 0x2c1b, 0x2c1c, 0x2c1d, 0x2c1e, 0x2c1f, 0x2c20, -+ 0x2c21, 0x2c22, 0x2c23, 0x2c24, 0x2c25, 0x2c26, 0x2c27, 0x2c28, -+ 0x2c29, 0x2c2a, 0x2c2b, 0x2c2c, 0x2c2d, 0x2c2e, 0x2c5f, 0x2c60, -+ 0x2c60, 0x2c62, 0x2c63, 0x2c64, 0x2c65, 0x2c66, 0x2c67, 0x2c67, -+ 0x2c69, 0x2c69, 0x2c6b, 0x2c6b, 0x2c6d, 0x2c6e, 0x2c6f, 0x2c70, -+ 0x2c71, 0x2c72, 0x2c73, 0x2c74, 0x2c75, 0x2c75, 0x2c77, 0x2c78, -+ 0x2c79, 0x2c7a, 0x2c7b, 0x2c7c, 0x2c7d, 0x2c7e, 0x2c7f, 0x2c80, -+ 0x2c80, 0x2c82, 0x2c82, 0x2c84, 0x2c84, 0x2c86, 0x2c86, 0x2c88, -+ 0x2c88, 0x2c8a, 0x2c8a, 0x2c8c, 0x2c8c, 0x2c8e, 0x2c8e, 0x2c90, -+ 0x2c90, 0x2c92, 0x2c92, 0x2c94, 0x2c94, 0x2c96, 0x2c96, 0x2c98, -+ 0x2c98, 0x2c9a, 0x2c9a, 0x2c9c, 0x2c9c, 0x2c9e, 0x2c9e, 0x2ca0, -+ 0x2ca0, 0x2ca2, 0x2ca2, 0x2ca4, 0x2ca4, 0x2ca6, 0x2ca6, 0x2ca8, -+ 0x2ca8, 0x2caa, 0x2caa, 0x2cac, 0x2cac, 0x2cae, 0x2cae, 0x2cb0, -+ 0x2cb0, 0x2cb2, 0x2cb2, 0x2cb4, 0x2cb4, 0x2cb6, 0x2cb6, 0x2cb8, -+ 0x2cb8, 0x2cba, 0x2cba, 0x2cbc, 0x2cbc, 0x2cbe, 0x2cbe, 0x2cc0, -+ 0x2cc0, 0x2cc2, 0x2cc2, 0x2cc4, 0x2cc4, 0x2cc6, 0x2cc6, 0x2cc8, -+ 0x2cc8, 0x2cca, 0x2cca, 0x2ccc, 0x2ccc, 0x2cce, 0x2cce, 0x2cd0, -+ 0x2cd0, 0x2cd2, 0x2cd2, 0x2cd4, 0x2cd4, 0x2cd6, 0x2cd6, 0x2cd8, -+ 0x2cd8, 0x2cda, 0x2cda, 0x2cdc, 0x2cdc, 0x2cde, 0x2cde, 0x2ce0, -+ 0x2ce0, 0x2ce2, 0x2ce2, 0x2ce4, 0x2ce5, 0x2ce6, 0x2ce7, 0x2ce8, -+ 0x2ce9, 0x2cea, 0x2ceb, 0x2cec, 0x2ced, 0x2cee, 0x2cef, 0x2cf0, -+ 0x2cf1, 0x2cf2, 0x2cf3, 0x2cf4, 0x2cf5, 0x2cf6, 0x2cf7, 0x2cf8, -+ 0x2cf9, 0x2cfa, 0x2cfb, 0x2cfc, 0x2cfd, 0x2cfe, 0x2cff, 0x10a0, -+ 0x10a1, 0x10a2, 0x10a3, 0x10a4, 0x10a5, 0x10a6, 0x10a7, 0x10a8, -+ 0x10a9, 0x10aa, 0x10ab, 0x10ac, 0x10ad, 0x10ae, 0x10af, 0x10b0, -+ 0x10b1, 0x10b2, 0x10b3, 0x10b4, 0x10b5, 0x10b6, 0x10b7, 0x10b8, -+ 0x10b9, 0x10ba, 0x10bb, 0x10bc, 0x10bd, 0x10be, 0x10bf, 0x10c0, -+ 0x10c1, 0x10c2, 0x10c3, 0x10c4, 0x10c5, 0xffff, 0xd21b, 0xff21, -+ 0xff22, 0xff23, 0xff24, 0xff25, 0xff26, 0xff27, 0xff28, 0xff29, -+ 0xff2a, 0xff2b, 0xff2c, 0xff2d, 0xff2e, 0xff2f, 0xff30, 0xff31, -+ 0xff32, 0xff33, 0xff34, 0xff35, 0xff36, 0xff37, 0xff38, 0xff39, -+ 0xff3a, 0xff5b, 0xff5c, 0xff5d, 0xff5e, 0xff5f, 0xff60, 0xff61, -+ 0xff62, 0xff63, 0xff64, 0xff65, 0xff66, 0xff67, 0xff68, 0xff69, -+ 0xff6a, 0xff6b, 0xff6c, 0xff6d, 0xff6e, 0xff6f, 0xff70, 0xff71, -+ 0xff72, 0xff73, 0xff74, 0xff75, 0xff76, 0xff77, 0xff78, 0xff79, -+ 0xff7a, 0xff7b, 0xff7c, 0xff7d, 0xff7e, 0xff7f, 0xff80, 0xff81, -+ 0xff82, 0xff83, 0xff84, 0xff85, 0xff86, 0xff87, 0xff88, 0xff89, -+ 0xff8a, 0xff8b, 0xff8c, 0xff8d, 0xff8e, 0xff8f, 0xff90, 0xff91, -+ 0xff92, 0xff93, 0xff94, 0xff95, 0xff96, 0xff97, 0xff98, 0xff99, -+ 0xff9a, 0xff9b, 0xff9c, 0xff9d, 0xff9e, 0xff9f, 0xffa0, 0xffa1, -+ 0xffa2, 0xffa3, 0xffa4, 0xffa5, 0xffa6, 0xffa7, 0xffa8, 0xffa9, -+ 0xffaa, 0xffab, 0xffac, 0xffad, 0xffae, 0xffaf, 0xffb0, 0xffb1, -+ 0xffb2, 0xffb3, 0xffb4, 0xffb5, 0xffb6, 0xffb7, 0xffb8, 0xffb9, -+ 0xffba, 0xffbb, 0xffbc, 0xffbd, 0xffbe, 0xffbf, 0xffc0, 0xffc1, -+ 0xffc2, 0xffc3, 0xffc4, 0xffc5, 0xffc6, 0xffc7, 0xffc8, 0xffc9, -+ 0xffca, 0xffcb, 0xffcc, 0xffcd, 0xffce, 0xffcf, 0xffd0, 0xffd1, -+ 0xffd2, 0xffd3, 0xffd4, 0xffd5, 0xffd6, 0xffd7, 0xffd8, 0xffd9, -+ 0xffda, 0xffdb, 0xffdc, 0xffdd, 0xffde, 0xffdf, 0xffe0, 0xffe1, -+ 0xffe2, 0xffe3, 0xffe4, 0xffe5, 0xffe6, 0xffe7, 0xffe8, 0xffe9, -+ 0xffea, 0xffeb, 0xffec, 0xffed, 0xffee, 0xffef, 0xfff0, 0xfff1, -+ 0xfff2, 0xfff3, 0xfff4, 0xfff5, 0xfff6, 0xfff7, 0xfff8, 0xfff9, -+ 0xfffa, 0xfffb, 0xfffc, 0xfffd, 0xfffe, 0xffff, -+}; -+ -+/* -+ * Allow full-width illegal characters : -+ * "MS windows 7" supports full-width-invalid-name-characters. -+ * So we should check half-width-invalid-name-characters(ASCII) only -+ * for compatibility. -+ * -+ * " * / : < > ? \ | -+ */ -+static unsigned short bad_uni_chars[] = { -+ 0x0022, 0x002A, 0x002F, 0x003A, -+ 0x003C, 0x003E, 0x003F, 0x005C, 0x007C, -+ 0 -+}; -+ -+static int exfat_convert_char_to_ucs2(struct nls_table *nls, -+ const unsigned char *ch, int ch_len, unsigned short *ucs2, -+ int *lossy) -+{ -+ int len; -+ -+ *ucs2 = 0x0; -+ -+ if (ch[0] < 0x80) { -+ *ucs2 = ch[0]; -+ return 1; -+ } -+ -+ len = nls->char2uni(ch, ch_len, ucs2); -+ if (len < 0) { -+ /* conversion failed */ -+ if (lossy != NULL) -+ *lossy |= NLS_NAME_LOSSY; -+ *ucs2 = '_'; -+ return 1; -+ } -+ return len; -+} -+ -+static int exfat_convert_ucs2_to_char(struct nls_table *nls, -+ unsigned short ucs2, unsigned char *ch, int *lossy) -+{ -+ int len; -+ -+ ch[0] = 0x0; -+ -+ if (ucs2 < 0x0080) { -+ ch[0] = ucs2; -+ return 1; -+ } -+ -+ len = nls->uni2char(ucs2, ch, MAX_CHARSET_SIZE); -+ if (len < 0) { -+ /* conversion failed */ -+ if (lossy != NULL) -+ *lossy |= NLS_NAME_LOSSY; -+ ch[0] = '_'; -+ return 1; -+ } -+ return len; -+} -+ -+unsigned short exfat_toupper(struct super_block *sb, unsigned short a) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ -+ return sbi->vol_utbl[a] ? sbi->vol_utbl[a] : a; -+} -+ -+static unsigned short *exfat_wstrchr(unsigned short *str, unsigned short wchar) -+{ -+ while (*str) { -+ if (*(str++) == wchar) -+ return str; -+ } -+ return NULL; -+} -+ -+int exfat_uniname_ncmp(struct super_block *sb, unsigned short *a, -+ unsigned short *b, unsigned int len) -+{ -+ int i; -+ -+ for (i = 0; i < len; i++, a++, b++) -+ if (exfat_toupper(sb, *a) != exfat_toupper(sb, *b)) -+ return 1; -+ return 0; -+} -+ -+static int exfat_utf16_to_utf8(struct super_block *sb, -+ struct exfat_uni_name *p_uniname, unsigned char *p_cstring, -+ int buflen) -+{ -+ int len; -+ const unsigned short *uniname = p_uniname->name; -+ -+ /* always len >= 0 */ -+ len = utf16s_to_utf8s(uniname, MAX_NAME_LENGTH, UTF16_HOST_ENDIAN, -+ p_cstring, buflen); -+ p_cstring[len] = '\0'; -+ return len; -+} -+ -+static int exfat_utf8_to_utf16(struct super_block *sb, -+ const unsigned char *p_cstring, const int len, -+ struct exfat_uni_name *p_uniname, int *p_lossy) -+{ -+ int i, unilen, lossy = NLS_NAME_NO_LOSSY; -+ unsigned short upname[MAX_NAME_LENGTH + 1]; -+ unsigned short *uniname = p_uniname->name; -+ -+ WARN_ON(!len); -+ -+ unilen = utf8s_to_utf16s(p_cstring, len, UTF16_HOST_ENDIAN, -+ (wchar_t *)uniname, MAX_NAME_LENGTH + 2); -+ if (unilen < 0) { -+ exfat_msg(sb, KERN_ERR, -+ "failed to %s (err : %d) nls len : %d", -+ __func__, unilen, len); -+ return unilen; -+ } -+ -+ if (unilen > MAX_NAME_LENGTH) { -+ exfat_msg(sb, KERN_ERR, -+ "failed to %s (estr:ENAMETOOLONG) nls len : %d, unilen : %d > %d", -+ __func__, len, unilen, MAX_NAME_LENGTH); -+ return -ENAMETOOLONG; -+ } -+ -+ p_uniname->name_len = unilen & 0xFF; -+ -+ for (i = 0; i < unilen; i++) { -+ if (*uniname < 0x0020 || -+ exfat_wstrchr(bad_uni_chars, *uniname)) -+ lossy |= NLS_NAME_LOSSY; -+ -+ upname[i] = exfat_toupper(sb, *uniname); -+ uniname++; -+ } -+ -+ *uniname = '\0'; -+ p_uniname->name_len = unilen; -+ p_uniname->name_hash = exfat_calc_chksum_2byte(upname, unilen << 1, 0, -+ CS_DEFAULT); -+ -+ if (p_lossy) -+ *p_lossy = lossy; -+ return unilen; -+} -+ -+#define PLANE_SIZE 0x00010000 -+#define SURROGATE_MASK 0xfffff800 -+#define SURROGATE_PAIR 0x0000d800 -+#define SURROGATE_LOW 0x00000400 -+#define SURROGATE_BITS 0x000003ff -+ -+unsigned short exfat_high_surrogate(unicode_t u) -+{ -+ return ((u - PLANE_SIZE) >> 10) + SURROGATE_PAIR; -+} -+ -+unsigned short exfat_low_surrogate(unicode_t u) -+{ -+ return ((u - PLANE_SIZE) & SURROGATE_BITS) | SURROGATE_PAIR | -+ SURROGATE_LOW; -+} -+ -+static int __exfat_utf16_to_nls(struct super_block *sb, -+ struct exfat_uni_name *p_uniname, unsigned char *p_cstring, -+ int buflen) -+{ -+ int i, j, len, out_len = 0; -+ unsigned char buf[MAX_CHARSET_SIZE]; -+ const unsigned short *uniname = p_uniname->name; -+ struct nls_table *nls = EXFAT_SB(sb)->nls_io; -+ -+ i = 0; -+ while (i < MAX_NAME_LENGTH && out_len < (buflen - 1)) { -+ if (*uniname == '\0') -+ break; -+ if ((*uniname & SURROGATE_MASK) != SURROGATE_PAIR) { -+ len = exfat_convert_ucs2_to_char(nls, *uniname, buf, -+ NULL); -+ } else { -+ /* Process UTF-16 surrogate pair as one character */ -+ if (!(*uniname & SURROGATE_LOW) && -+ i+1 < MAX_NAME_LENGTH && -+ (*(uniname+1) & SURROGATE_MASK) == SURROGATE_PAIR && -+ (*(uniname+1) & SURROGATE_LOW)) { -+ uniname++; -+ i++; -+ } -+ -+ /* -+ * UTF-16 surrogate pair encodes code points above -+ * U+FFFF. Code points above U+FFFF are not supported -+ * by kernel NLS framework therefore use replacement -+ * character -+ */ -+ len = 1; -+ buf[0] = '_'; -+ } -+ -+ if (out_len + len >= buflen) -+ len = buflen - 1 - out_len; -+ out_len += len; -+ -+ if (len > 1) { -+ for (j = 0; j < len; j++) -+ *p_cstring++ = buf[j]; -+ } else { /* len == 1 */ -+ *p_cstring++ = *buf; -+ } -+ -+ uniname++; -+ i++; -+ } -+ -+ *p_cstring = '\0'; -+ return out_len; -+} -+ -+static int exfat_nls_to_ucs2(struct super_block *sb, -+ const unsigned char *p_cstring, const int len, -+ struct exfat_uni_name *p_uniname, int *p_lossy) -+{ -+ int i = 0, unilen = 0, lossy = NLS_NAME_NO_LOSSY; -+ unsigned short upname[MAX_NAME_LENGTH + 1]; -+ unsigned short *uniname = p_uniname->name; -+ struct nls_table *nls = EXFAT_SB(sb)->nls_io; -+ -+ WARN_ON(!len); -+ -+ while (unilen < MAX_NAME_LENGTH && i < len) { -+ i += exfat_convert_char_to_ucs2(nls, p_cstring + i, len - i, -+ uniname, &lossy); -+ -+ if (*uniname < 0x0020 || -+ exfat_wstrchr(bad_uni_chars, *uniname)) -+ lossy |= NLS_NAME_LOSSY; -+ -+ upname[unilen] = exfat_toupper(sb, *uniname); -+ uniname++; -+ unilen++; -+ } -+ -+ if (p_cstring[i] != '\0') -+ lossy |= NLS_NAME_OVERLEN; -+ -+ *uniname = '\0'; -+ p_uniname->name_len = unilen; -+ p_uniname->name_hash = exfat_calc_chksum_2byte(upname, unilen << 1, 0, -+ CS_DEFAULT); -+ -+ if (p_lossy) -+ *p_lossy = lossy; -+ return unilen; -+} -+ -+int exfat_utf16_to_nls(struct super_block *sb, struct exfat_uni_name *uniname, -+ unsigned char *p_cstring, int buflen) -+{ -+ if (EXFAT_SB(sb)->options.utf8) -+ return exfat_utf16_to_utf8(sb, uniname, p_cstring, -+ buflen); -+ return __exfat_utf16_to_nls(sb, uniname, p_cstring, buflen); -+} -+ -+int exfat_nls_to_utf16(struct super_block *sb, const unsigned char *p_cstring, -+ const int len, struct exfat_uni_name *uniname, int *p_lossy) -+{ -+ if (EXFAT_SB(sb)->options.utf8) -+ return exfat_utf8_to_utf16(sb, p_cstring, len, -+ uniname, p_lossy); -+ return exfat_nls_to_ucs2(sb, p_cstring, len, uniname, p_lossy); -+} -+ -+static int exfat_load_upcase_table(struct super_block *sb, -+ sector_t sector, unsigned long long num_sectors, -+ unsigned int utbl_checksum) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ unsigned int sect_size = sb->s_blocksize; -+ unsigned int i, index = 0, checksum = 0; -+ int ret; -+ unsigned char skip = false; -+ unsigned short *upcase_table; -+ -+ upcase_table = kcalloc(UTBL_COUNT, sizeof(unsigned short), GFP_KERNEL); -+ if (!upcase_table) -+ return -ENOMEM; -+ -+ sbi->vol_utbl = upcase_table; -+ num_sectors += sector; -+ -+ while (sector < num_sectors) { -+ struct buffer_head *bh; -+ -+ bh = sb_bread(sb, sector); -+ if (!bh) { -+ exfat_msg(sb, KERN_ERR, -+ "failed to read sector(0x%llx)\n", -+ (unsigned long long)sector); -+ ret = -EIO; -+ goto free_table; -+ } -+ sector++; -+ for (i = 0; i < sect_size && index <= 0xFFFF; i += 2) { -+ unsigned short uni = get_unaligned_le16(bh->b_data + i); -+ -+ checksum = ((checksum & 1) ? 0x80000000 : 0) + -+ (checksum >> 1) + -+ *(((unsigned char *)bh->b_data) + i); -+ checksum = ((checksum & 1) ? 0x80000000 : 0) + -+ (checksum >> 1) + -+ *(((unsigned char *)bh->b_data) + (i + 1)); -+ -+ if (skip) { -+ index += uni; -+ skip = false; -+ } else if (uni == index) { -+ index++; -+ } else if (uni == 0xFFFF) { -+ skip = true; -+ } else { /* uni != index , uni != 0xFFFF */ -+ upcase_table[index] = uni; -+ index++; -+ } -+ } -+ brelse(bh); -+ } -+ -+ if (index >= 0xFFFF && utbl_checksum == checksum) -+ return 0; -+ -+ exfat_msg(sb, KERN_ERR, -+ "failed to load upcase table (idx : 0x%08x, chksum : 0x%08x, utbl_chksum : 0x%08x)\n", -+ index, checksum, utbl_checksum); -+ ret = -EINVAL; -+free_table: -+ exfat_free_upcase_table(sbi); -+ return ret; -+} -+ -+static int exfat_load_default_upcase_table(struct super_block *sb) -+{ -+ int i, ret = -EIO; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ unsigned char skip = false; -+ unsigned short uni = 0, *upcase_table; -+ unsigned int index = 0; -+ -+ upcase_table = kcalloc(UTBL_COUNT, sizeof(unsigned short), GFP_KERNEL); -+ if (!upcase_table) -+ return -ENOMEM; -+ -+ sbi->vol_utbl = upcase_table; -+ -+ for (i = 0; index <= 0xFFFF && i < EXFAT_NUM_UPCASE; i++) { -+ uni = uni_def_upcase[i]; -+ if (skip) { -+ index += uni; -+ skip = false; -+ } else if (uni == index) { -+ index++; -+ } else if (uni == 0xFFFF) { -+ skip = true; -+ } else { -+ upcase_table[index] = uni; -+ index++; -+ } -+ } -+ -+ if (index >= 0xFFFF) -+ return 0; -+ -+ /* FATAL error: default upcase table has error */ -+ exfat_free_upcase_table(sbi); -+ return ret; -+} -+ -+int exfat_create_upcase_table(struct super_block *sb) -+{ -+ int i, ret; -+ unsigned int tbl_clu, type; -+ sector_t sector; -+ unsigned long long tbl_size, num_sectors; -+ unsigned char blksize_bits = sb->s_blocksize_bits; -+ struct exfat_chain clu; -+ struct exfat_dentry *ep; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct buffer_head *bh; -+ -+ clu.dir = sbi->root_dir; -+ clu.flags = ALLOC_FAT_CHAIN; -+ -+ while (clu.dir != EXFAT_EOF_CLUSTER) { -+ for (i = 0; i < sbi->dentries_per_clu; i++) { -+ ep = exfat_get_dentry(sb, &clu, i, &bh, NULL); -+ if (!ep) -+ return -EIO; -+ -+ type = exfat_get_entry_type(ep); -+ if (type == TYPE_UNUSED) { -+ brelse(bh); -+ break; -+ } -+ -+ if (type != TYPE_UPCASE) { -+ brelse(bh); -+ continue; -+ } -+ -+ tbl_clu = le32_to_cpu(ep->dentry.upcase.start_clu); -+ tbl_size = le64_to_cpu(ep->dentry.upcase.size); -+ -+ sector = exfat_cluster_to_sector(sbi, tbl_clu); -+ num_sectors = ((tbl_size - 1) >> blksize_bits) + 1; -+ ret = exfat_load_upcase_table(sb, sector, num_sectors, -+ le32_to_cpu(ep->dentry.upcase.checksum)); -+ -+ brelse(bh); -+ if (ret && ret != -EIO) -+ goto load_default; -+ -+ /* load successfully */ -+ return ret; -+ } -+ -+ if (exfat_get_next_cluster(sb, &(clu.dir))) -+ return -EIO; -+ } -+ -+load_default: -+ /* load default upcase table */ -+ return exfat_load_default_upcase_table(sb); -+} -+ -+void exfat_free_upcase_table(struct exfat_sb_info *sbi) -+{ -+ kfree(sbi->vol_utbl); -+} --- -2.25.1 - diff --git a/kernel/kernel/files/patches/mageia/fs-exfat-add-super-block-operations.patch b/kernel/kernel/files/patches/mageia/fs-exfat-add-super-block-operations.patch deleted file mode 100644 index f51a2518..00000000 --- a/kernel/kernel/files/patches/mageia/fs-exfat-add-super-block-operations.patch +++ /dev/null @@ -1,758 +0,0 @@ -From 719c1e1829166da399903b13da6dcc5344e73449 Mon Sep 17 00:00:00 2001 -From: Namjae Jeon -Date: Mon, 2 Mar 2020 15:21:33 +0900 -Subject: [PATCH 02/14] exfat: add super block operations -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This adds the implementation of superblock operations for exfat. - -Signed-off-by: Namjae Jeon -Signed-off-by: Sungjong Seo -Reviewed-by: Pali Rohár -Reviewed-by: Christoph Hellwig -Reviewed-by: Arnd Bergmann -Signed-off-by: Al Viro ---- - fs/exfat/super.c | 728 +++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 728 insertions(+) - create mode 100644 fs/exfat/super.c - -diff --git a/fs/exfat/super.c b/fs/exfat/super.c -new file mode 100644 -index 000000000000..f06e0b53e393 ---- /dev/null -+++ b/fs/exfat/super.c -@@ -0,0 +1,728 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "exfat_raw.h" -+#include "exfat_fs.h" -+ -+static char exfat_default_iocharset[] = CONFIG_EXFAT_DEFAULT_IOCHARSET; -+static struct kmem_cache *exfat_inode_cachep; -+ -+static void exfat_free_iocharset(struct exfat_sb_info *sbi) -+{ -+ if (sbi->options.iocharset != exfat_default_iocharset) -+ kfree(sbi->options.iocharset); -+} -+ -+static void exfat_delayed_free(struct rcu_head *p) -+{ -+ struct exfat_sb_info *sbi = container_of(p, struct exfat_sb_info, rcu); -+ -+ unload_nls(sbi->nls_io); -+ exfat_free_iocharset(sbi); -+ exfat_free_upcase_table(sbi); -+ kfree(sbi); -+} -+ -+static void exfat_put_super(struct super_block *sb) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ -+ mutex_lock(&sbi->s_lock); -+ if (test_and_clear_bit(EXFAT_SB_DIRTY, &sbi->s_state)) -+ sync_blockdev(sb->s_bdev); -+ exfat_set_vol_flags(sb, VOL_CLEAN); -+ exfat_free_bitmap(sbi); -+ mutex_unlock(&sbi->s_lock); -+ -+ call_rcu(&sbi->rcu, exfat_delayed_free); -+} -+ -+static int exfat_sync_fs(struct super_block *sb, int wait) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ int err = 0; -+ -+ /* If there are some dirty buffers in the bdev inode */ -+ mutex_lock(&sbi->s_lock); -+ if (test_and_clear_bit(EXFAT_SB_DIRTY, &sbi->s_state)) { -+ sync_blockdev(sb->s_bdev); -+ if (exfat_set_vol_flags(sb, VOL_CLEAN)) -+ err = -EIO; -+ } -+ mutex_unlock(&sbi->s_lock); -+ return err; -+} -+ -+static int exfat_statfs(struct dentry *dentry, struct kstatfs *buf) -+{ -+ struct super_block *sb = dentry->d_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ unsigned long long id = huge_encode_dev(sb->s_bdev->bd_dev); -+ -+ if (sbi->used_clusters == EXFAT_CLUSTERS_UNTRACKED) { -+ mutex_lock(&sbi->s_lock); -+ if (exfat_count_used_clusters(sb, &sbi->used_clusters)) { -+ mutex_unlock(&sbi->s_lock); -+ return -EIO; -+ } -+ mutex_unlock(&sbi->s_lock); -+ } -+ -+ buf->f_type = sb->s_magic; -+ buf->f_bsize = sbi->cluster_size; -+ buf->f_blocks = sbi->num_clusters - 2; /* clu 0 & 1 */ -+ buf->f_bfree = buf->f_blocks - sbi->used_clusters; -+ buf->f_bavail = buf->f_bfree; -+ buf->f_fsid.val[0] = (unsigned int)id; -+ buf->f_fsid.val[1] = (unsigned int)(id >> 32); -+ /* Unicode utf16 255 characters */ -+ buf->f_namelen = EXFAT_MAX_FILE_LEN * NLS_MAX_CHARSET_SIZE; -+ return 0; -+} -+ -+int exfat_set_vol_flags(struct super_block *sb, unsigned short new_flag) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct pbr64 *bpb; -+ bool sync = 0; -+ -+ /* flags are not changed */ -+ if (sbi->vol_flag == new_flag) -+ return 0; -+ -+ sbi->vol_flag = new_flag; -+ -+ /* skip updating volume dirty flag, -+ * if this volume has been mounted with read-only -+ */ -+ if (sb_rdonly(sb)) -+ return 0; -+ -+ if (!sbi->pbr_bh) { -+ sbi->pbr_bh = sb_bread(sb, 0); -+ if (!sbi->pbr_bh) { -+ exfat_msg(sb, KERN_ERR, "failed to read boot sector"); -+ return -ENOMEM; -+ } -+ } -+ -+ bpb = (struct pbr64 *)sbi->pbr_bh->b_data; -+ bpb->bsx.vol_flags = cpu_to_le16(new_flag); -+ -+ if (new_flag == VOL_DIRTY && !buffer_dirty(sbi->pbr_bh)) -+ sync = true; -+ else -+ sync = false; -+ -+ set_buffer_uptodate(sbi->pbr_bh); -+ mark_buffer_dirty(sbi->pbr_bh); -+ -+ if (sync) -+ sync_dirty_buffer(sbi->pbr_bh); -+ return 0; -+} -+ -+static int exfat_show_options(struct seq_file *m, struct dentry *root) -+{ -+ struct super_block *sb = root->d_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct exfat_mount_options *opts = &sbi->options; -+ -+ /* Show partition info */ -+ if (!uid_eq(opts->fs_uid, GLOBAL_ROOT_UID)) -+ seq_printf(m, ",uid=%u", -+ from_kuid_munged(&init_user_ns, opts->fs_uid)); -+ if (!gid_eq(opts->fs_gid, GLOBAL_ROOT_GID)) -+ seq_printf(m, ",gid=%u", -+ from_kgid_munged(&init_user_ns, opts->fs_gid)); -+ seq_printf(m, ",fmask=%04o,dmask=%04o", opts->fs_fmask, opts->fs_dmask); -+ if (opts->allow_utime) -+ seq_printf(m, ",allow_utime=%04o", opts->allow_utime); -+ if (opts->utf8) -+ seq_puts(m, ",iocharset=utf8"); -+ else if (sbi->nls_io) -+ seq_printf(m, ",iocharset=%s", sbi->nls_io->charset); -+ seq_printf(m, ",bps=%ld", sb->s_blocksize); -+ if (opts->errors == EXFAT_ERRORS_CONT) -+ seq_puts(m, ",errors=continue"); -+ else if (opts->errors == EXFAT_ERRORS_PANIC) -+ seq_puts(m, ",errors=panic"); -+ else -+ seq_puts(m, ",errors=remount-ro"); -+ if (opts->discard) -+ seq_puts(m, ",discard"); -+ if (opts->time_offset) -+ seq_printf(m, ",time_offset=%d", opts->time_offset); -+ return 0; -+} -+ -+static struct inode *exfat_alloc_inode(struct super_block *sb) -+{ -+ struct exfat_inode_info *ei; -+ -+ ei = kmem_cache_alloc(exfat_inode_cachep, GFP_NOFS); -+ if (!ei) -+ return NULL; -+ -+ init_rwsem(&ei->truncate_lock); -+ return &ei->vfs_inode; -+} -+ -+static void exfat_free_inode(struct inode *inode) -+{ -+ kmem_cache_free(exfat_inode_cachep, EXFAT_I(inode)); -+} -+ -+static const struct super_operations exfat_sops = { -+ .alloc_inode = exfat_alloc_inode, -+ .free_inode = exfat_free_inode, -+ .write_inode = exfat_write_inode, -+ .evict_inode = exfat_evict_inode, -+ .put_super = exfat_put_super, -+ .sync_fs = exfat_sync_fs, -+ .statfs = exfat_statfs, -+ .show_options = exfat_show_options, -+}; -+ -+enum { -+ Opt_uid, -+ Opt_gid, -+ Opt_umask, -+ Opt_dmask, -+ Opt_fmask, -+ Opt_allow_utime, -+ Opt_charset, -+ Opt_errors, -+ Opt_discard, -+ Opt_time_offset, -+}; -+ -+static const struct fs_parameter_spec exfat_param_specs[] = { -+ fsparam_u32("uid", Opt_uid), -+ fsparam_u32("gid", Opt_gid), -+ fsparam_u32oct("umask", Opt_umask), -+ fsparam_u32oct("dmask", Opt_dmask), -+ fsparam_u32oct("fmask", Opt_fmask), -+ fsparam_u32oct("allow_utime", Opt_allow_utime), -+ fsparam_string("iocharset", Opt_charset), -+ fsparam_enum("errors", Opt_errors), -+ fsparam_flag("discard", Opt_discard), -+ fsparam_s32("time_offset", Opt_time_offset), -+ {} -+}; -+ -+static const struct fs_parameter_enum exfat_param_enums[] = { -+ { Opt_errors, "continue", EXFAT_ERRORS_CONT }, -+ { Opt_errors, "panic", EXFAT_ERRORS_PANIC }, -+ { Opt_errors, "remount-ro", EXFAT_ERRORS_RO }, -+ {} -+}; -+ -+static const struct fs_parameter_description exfat_parameters = { -+ .name = "exfat", -+ .specs = exfat_param_specs, -+ .enums = exfat_param_enums, -+}; -+ -+static int exfat_parse_param(struct fs_context *fc, struct fs_parameter *param) -+{ -+ struct exfat_sb_info *sbi = fc->s_fs_info; -+ struct exfat_mount_options *opts = &sbi->options; -+ struct fs_parse_result result; -+ int opt; -+ -+ opt = fs_parse(fc, &exfat_parameters, param, &result); -+ if (opt < 0) -+ return opt; -+ -+ switch (opt) { -+ case Opt_uid: -+ opts->fs_uid = make_kuid(current_user_ns(), result.uint_32); -+ break; -+ case Opt_gid: -+ opts->fs_gid = make_kgid(current_user_ns(), result.uint_32); -+ break; -+ case Opt_umask: -+ opts->fs_fmask = result.uint_32; -+ opts->fs_dmask = result.uint_32; -+ break; -+ case Opt_dmask: -+ opts->fs_dmask = result.uint_32; -+ break; -+ case Opt_fmask: -+ opts->fs_fmask = result.uint_32; -+ break; -+ case Opt_allow_utime: -+ opts->allow_utime = result.uint_32 & 0022; -+ break; -+ case Opt_charset: -+ exfat_free_iocharset(sbi); -+ opts->iocharset = kstrdup(param->string, GFP_KERNEL); -+ if (!opts->iocharset) -+ return -ENOMEM; -+ break; -+ case Opt_errors: -+ opts->errors = result.uint_32; -+ break; -+ case Opt_discard: -+ opts->discard = 1; -+ break; -+ case Opt_time_offset: -+ /* -+ * Make the limit 24 just in case someone invents something -+ * unusual. -+ */ -+ if (result.int_32 < -24 * 60 || result.int_32 > 24 * 60) -+ return -EINVAL; -+ opts->time_offset = result.int_32; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static void exfat_hash_init(struct super_block *sb) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ int i; -+ -+ spin_lock_init(&sbi->inode_hash_lock); -+ for (i = 0; i < EXFAT_HASH_SIZE; i++) -+ INIT_HLIST_HEAD(&sbi->inode_hashtable[i]); -+} -+ -+static int exfat_read_root(struct inode *inode) -+{ -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ struct exfat_chain cdir; -+ int num_subdirs, num_clu = 0; -+ -+ exfat_chain_set(&ei->dir, sbi->root_dir, 0, ALLOC_FAT_CHAIN); -+ ei->entry = -1; -+ ei->start_clu = sbi->root_dir; -+ ei->flags = ALLOC_FAT_CHAIN; -+ ei->type = TYPE_DIR; -+ ei->version = 0; -+ ei->rwoffset = 0; -+ ei->hint_bmap.off = EXFAT_EOF_CLUSTER; -+ ei->hint_stat.eidx = 0; -+ ei->hint_stat.clu = sbi->root_dir; -+ ei->hint_femp.eidx = EXFAT_HINT_NONE; -+ -+ exfat_chain_set(&cdir, sbi->root_dir, 0, ALLOC_FAT_CHAIN); -+ if (exfat_count_num_clusters(sb, &cdir, &num_clu)) -+ return -EIO; -+ i_size_write(inode, num_clu << sbi->cluster_size_bits); -+ -+ num_subdirs = exfat_count_dir_entries(sb, &cdir); -+ if (num_subdirs < 0) -+ return -EIO; -+ set_nlink(inode, num_subdirs + EXFAT_MIN_SUBDIR); -+ -+ inode->i_uid = sbi->options.fs_uid; -+ inode->i_gid = sbi->options.fs_gid; -+ inode_inc_iversion(inode); -+ inode->i_generation = 0; -+ inode->i_mode = exfat_make_mode(sbi, ATTR_SUBDIR, 0777); -+ inode->i_op = &exfat_dir_inode_operations; -+ inode->i_fop = &exfat_dir_operations; -+ -+ inode->i_blocks = ((i_size_read(inode) + (sbi->cluster_size - 1)) -+ & ~(sbi->cluster_size - 1)) >> inode->i_blkbits; -+ EXFAT_I(inode)->i_pos = ((loff_t)sbi->root_dir << 32) | 0xffffffff; -+ EXFAT_I(inode)->i_size_aligned = i_size_read(inode); -+ EXFAT_I(inode)->i_size_ondisk = i_size_read(inode); -+ -+ exfat_save_attr(inode, ATTR_SUBDIR); -+ inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime = -+ current_time(inode); -+ exfat_cache_init_inode(inode); -+ return 0; -+} -+ -+static struct pbr *exfat_read_pbr_with_logical_sector(struct super_block *sb, -+ struct buffer_head **prev_bh) -+{ -+ struct pbr *p_pbr = (struct pbr *) (*prev_bh)->b_data; -+ unsigned short logical_sect = 0; -+ -+ logical_sect = 1 << p_pbr->bsx.f64.sect_size_bits; -+ -+ if (!is_power_of_2(logical_sect) || -+ logical_sect < 512 || logical_sect > 4096) { -+ exfat_msg(sb, KERN_ERR, "bogus logical sector size %u", -+ logical_sect); -+ return NULL; -+ } -+ -+ if (logical_sect < sb->s_blocksize) { -+ exfat_msg(sb, KERN_ERR, -+ "logical sector size too small for device (logical sector size = %u)", -+ logical_sect); -+ return NULL; -+ } -+ -+ if (logical_sect > sb->s_blocksize) { -+ struct buffer_head *bh = NULL; -+ -+ __brelse(*prev_bh); -+ *prev_bh = NULL; -+ -+ if (!sb_set_blocksize(sb, logical_sect)) { -+ exfat_msg(sb, KERN_ERR, -+ "unable to set blocksize %u", logical_sect); -+ return NULL; -+ } -+ bh = sb_bread(sb, 0); -+ if (!bh) { -+ exfat_msg(sb, KERN_ERR, -+ "unable to read boot sector (logical sector size = %lu)", -+ sb->s_blocksize); -+ return NULL; -+ } -+ -+ *prev_bh = bh; -+ p_pbr = (struct pbr *) bh->b_data; -+ } -+ return p_pbr; -+} -+ -+/* mount the file system volume */ -+static int __exfat_fill_super(struct super_block *sb) -+{ -+ int ret; -+ struct pbr *p_pbr; -+ struct pbr64 *p_bpb; -+ struct buffer_head *bh; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ -+ /* set block size to read super block */ -+ sb_min_blocksize(sb, 512); -+ -+ /* read boot sector */ -+ bh = sb_bread(sb, 0); -+ if (!bh) { -+ exfat_msg(sb, KERN_ERR, "unable to read boot sector"); -+ return -EIO; -+ } -+ -+ /* PRB is read */ -+ p_pbr = (struct pbr *)bh->b_data; -+ -+ /* check the validity of PBR */ -+ if (le16_to_cpu((p_pbr->signature)) != PBR_SIGNATURE) { -+ exfat_msg(sb, KERN_ERR, "invalid boot record signature"); -+ ret = -EINVAL; -+ goto free_bh; -+ } -+ -+ -+ /* check logical sector size */ -+ p_pbr = exfat_read_pbr_with_logical_sector(sb, &bh); -+ if (!p_pbr) { -+ ret = -EIO; -+ goto free_bh; -+ } -+ -+ /* -+ * res_zero field must be filled with zero to prevent mounting -+ * from FAT volume. -+ */ -+ if (memchr_inv(p_pbr->bpb.f64.res_zero, 0, -+ sizeof(p_pbr->bpb.f64.res_zero))) { -+ ret = -EINVAL; -+ goto free_bh; -+ } -+ -+ p_bpb = (struct pbr64 *)p_pbr; -+ if (!p_bpb->bsx.num_fats) { -+ exfat_msg(sb, KERN_ERR, "bogus number of FAT structure"); -+ ret = -EINVAL; -+ goto free_bh; -+ } -+ -+ sbi->sect_per_clus = 1 << p_bpb->bsx.sect_per_clus_bits; -+ sbi->sect_per_clus_bits = p_bpb->bsx.sect_per_clus_bits; -+ sbi->cluster_size_bits = sbi->sect_per_clus_bits + sb->s_blocksize_bits; -+ sbi->cluster_size = 1 << sbi->cluster_size_bits; -+ sbi->num_FAT_sectors = le32_to_cpu(p_bpb->bsx.fat_length); -+ sbi->FAT1_start_sector = le32_to_cpu(p_bpb->bsx.fat_offset); -+ sbi->FAT2_start_sector = p_bpb->bsx.num_fats == 1 ? -+ sbi->FAT1_start_sector : -+ sbi->FAT1_start_sector + sbi->num_FAT_sectors; -+ sbi->data_start_sector = le32_to_cpu(p_bpb->bsx.clu_offset); -+ sbi->num_sectors = le64_to_cpu(p_bpb->bsx.vol_length); -+ /* because the cluster index starts with 2 */ -+ sbi->num_clusters = le32_to_cpu(p_bpb->bsx.clu_count) + -+ EXFAT_RESERVED_CLUSTERS; -+ -+ sbi->root_dir = le32_to_cpu(p_bpb->bsx.root_cluster); -+ sbi->dentries_per_clu = 1 << -+ (sbi->cluster_size_bits - DENTRY_SIZE_BITS); -+ -+ sbi->vol_flag = le16_to_cpu(p_bpb->bsx.vol_flags); -+ sbi->clu_srch_ptr = EXFAT_FIRST_CLUSTER; -+ sbi->used_clusters = EXFAT_CLUSTERS_UNTRACKED; -+ -+ if (le16_to_cpu(p_bpb->bsx.vol_flags) & VOL_DIRTY) { -+ sbi->vol_flag |= VOL_DIRTY; -+ exfat_msg(sb, KERN_WARNING, -+ "Volume was not properly unmounted. Some data may be corrupt. Please run fsck."); -+ } -+ -+ /* exFAT file size is limited by a disk volume size */ -+ sb->s_maxbytes = (u64)(sbi->num_clusters - EXFAT_RESERVED_CLUSTERS) << -+ sbi->cluster_size_bits; -+ -+ ret = exfat_create_upcase_table(sb); -+ if (ret) { -+ exfat_msg(sb, KERN_ERR, "failed to load upcase table"); -+ goto free_bh; -+ } -+ -+ ret = exfat_load_bitmap(sb); -+ if (ret) { -+ exfat_msg(sb, KERN_ERR, "failed to load alloc-bitmap"); -+ goto free_upcase_table; -+ } -+ -+ ret = exfat_count_used_clusters(sb, &sbi->used_clusters); -+ if (ret) { -+ exfat_msg(sb, KERN_ERR, "failed to scan clusters"); -+ goto free_alloc_bitmap; -+ } -+ -+ return 0; -+ -+free_alloc_bitmap: -+ exfat_free_bitmap(sbi); -+free_upcase_table: -+ exfat_free_upcase_table(sbi); -+free_bh: -+ brelse(bh); -+ return ret; -+} -+ -+static int exfat_fill_super(struct super_block *sb, struct fs_context *fc) -+{ -+ struct exfat_sb_info *sbi = sb->s_fs_info; -+ struct exfat_mount_options *opts = &sbi->options; -+ struct inode *root_inode; -+ int err; -+ -+ if (opts->allow_utime == (unsigned short)-1) -+ opts->allow_utime = ~opts->fs_dmask & 0022; -+ -+ if (opts->discard) { -+ struct request_queue *q = bdev_get_queue(sb->s_bdev); -+ -+ if (!blk_queue_discard(q)) -+ exfat_msg(sb, KERN_WARNING, -+ "mounting with \"discard\" option, but the device does not support discard"); -+ opts->discard = 0; -+ } -+ -+ sb->s_flags |= SB_NODIRATIME; -+ sb->s_magic = EXFAT_SUPER_MAGIC; -+ sb->s_op = &exfat_sops; -+ -+ sb->s_time_gran = 1; -+ sb->s_time_min = EXFAT_MIN_TIMESTAMP_SECS; -+ sb->s_time_max = EXFAT_MAX_TIMESTAMP_SECS; -+ -+ err = __exfat_fill_super(sb); -+ if (err) { -+ exfat_msg(sb, KERN_ERR, "failed to recognize exfat type"); -+ goto check_nls_io; -+ } -+ -+ /* set up enough so that it can read an inode */ -+ exfat_hash_init(sb); -+ -+ if (!strcmp(sbi->options.iocharset, "utf8")) -+ opts->utf8 = 1; -+ else { -+ sbi->nls_io = load_nls(sbi->options.iocharset); -+ if (!sbi->nls_io) { -+ exfat_msg(sb, KERN_ERR, "IO charset %s not found", -+ sbi->options.iocharset); -+ err = -EINVAL; -+ goto free_table; -+ } -+ } -+ -+ if (sbi->options.utf8) -+ sb->s_d_op = &exfat_utf8_dentry_ops; -+ else -+ sb->s_d_op = &exfat_dentry_ops; -+ -+ root_inode = new_inode(sb); -+ if (!root_inode) { -+ exfat_msg(sb, KERN_ERR, "failed to allocate root inode."); -+ err = -ENOMEM; -+ goto free_table; -+ } -+ -+ root_inode->i_ino = EXFAT_ROOT_INO; -+ inode_set_iversion(root_inode, 1); -+ err = exfat_read_root(root_inode); -+ if (err) { -+ exfat_msg(sb, KERN_ERR, "failed to initialize root inode."); -+ goto put_inode; -+ } -+ -+ exfat_hash_inode(root_inode, EXFAT_I(root_inode)->i_pos); -+ insert_inode_hash(root_inode); -+ -+ sb->s_root = d_make_root(root_inode); -+ if (!sb->s_root) { -+ exfat_msg(sb, KERN_ERR, "failed to get the root dentry"); -+ err = -ENOMEM; -+ goto put_inode; -+ } -+ -+ return 0; -+ -+put_inode: -+ iput(root_inode); -+ sb->s_root = NULL; -+ -+free_table: -+ exfat_free_upcase_table(sbi); -+ exfat_free_bitmap(sbi); -+ -+check_nls_io: -+ unload_nls(sbi->nls_io); -+ exfat_free_iocharset(sbi); -+ sb->s_fs_info = NULL; -+ kfree(sbi); -+ return err; -+} -+ -+static int exfat_get_tree(struct fs_context *fc) -+{ -+ return get_tree_bdev(fc, exfat_fill_super); -+} -+ -+static void exfat_free(struct fs_context *fc) -+{ -+ kfree(fc->s_fs_info); -+} -+ -+static const struct fs_context_operations exfat_context_ops = { -+ .parse_param = exfat_parse_param, -+ .get_tree = exfat_get_tree, -+ .free = exfat_free, -+}; -+ -+static int exfat_init_fs_context(struct fs_context *fc) -+{ -+ struct exfat_sb_info *sbi; -+ -+ sbi = kzalloc(sizeof(struct exfat_sb_info), GFP_KERNEL); -+ if (!sbi) -+ return -ENOMEM; -+ -+ mutex_init(&sbi->s_lock); -+ ratelimit_state_init(&sbi->ratelimit, DEFAULT_RATELIMIT_INTERVAL, -+ DEFAULT_RATELIMIT_BURST); -+ -+ sbi->options.fs_uid = current_uid(); -+ sbi->options.fs_gid = current_gid(); -+ sbi->options.fs_fmask = current->fs->umask; -+ sbi->options.fs_dmask = current->fs->umask; -+ sbi->options.allow_utime = -1; -+ sbi->options.iocharset = exfat_default_iocharset; -+ sbi->options.errors = EXFAT_ERRORS_RO; -+ -+ fc->s_fs_info = sbi; -+ fc->ops = &exfat_context_ops; -+ return 0; -+} -+ -+static struct file_system_type exfat_fs_type = { -+ .owner = THIS_MODULE, -+ .name = "exfat", -+ .init_fs_context = exfat_init_fs_context, -+ .parameters = &exfat_parameters, -+ .kill_sb = kill_block_super, -+ .fs_flags = FS_REQUIRES_DEV, -+}; -+ -+static void exfat_inode_init_once(void *foo) -+{ -+ struct exfat_inode_info *ei = (struct exfat_inode_info *)foo; -+ -+ INIT_HLIST_NODE(&ei->i_hash_fat); -+ inode_init_once(&ei->vfs_inode); -+} -+ -+static int __init init_exfat_fs(void) -+{ -+ int err; -+ -+ err = exfat_cache_init(); -+ if (err) -+ return err; -+ -+ exfat_inode_cachep = kmem_cache_create("exfat_inode_cache", -+ sizeof(struct exfat_inode_info), -+ 0, SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, -+ exfat_inode_init_once); -+ if (!exfat_inode_cachep) { -+ err = -ENOMEM; -+ goto shutdown_cache; -+ } -+ -+ err = register_filesystem(&exfat_fs_type); -+ if (err) -+ goto destroy_cache; -+ -+ return 0; -+ -+destroy_cache: -+ kmem_cache_destroy(exfat_inode_cachep); -+shutdown_cache: -+ exfat_cache_shutdown(); -+ return err; -+} -+ -+static void __exit exit_exfat_fs(void) -+{ -+ /* -+ * Make sure all delayed rcu free inodes are flushed before we -+ * destroy cache. -+ */ -+ rcu_barrier(); -+ kmem_cache_destroy(exfat_inode_cachep); -+ unregister_filesystem(&exfat_fs_type); -+ exfat_cache_shutdown(); -+} -+ -+module_init(init_exfat_fs); -+module_exit(exit_exfat_fs); -+ -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("exFAT filesystem support"); -+MODULE_AUTHOR("Samsung Electronics Co., Ltd."); --- -2.25.1 - diff --git a/kernel/kernel/files/patches/mageia/fs-exfat-fix-discard-support.patch b/kernel/kernel/files/patches/mageia/fs-exfat-fix-discard-support.patch deleted file mode 100644 index 5de9917c..00000000 --- a/kernel/kernel/files/patches/mageia/fs-exfat-fix-discard-support.patch +++ /dev/null @@ -1,32 +0,0 @@ -From: =?UTF-8?q?Pali=20Roh=C3=A1r?= -Subject: [PATCH 4/4] exfat: Fix discard support -Date: Tue, 17 Mar 2020 23:25:55 +0100 - -Discard support was always unconditionally disabled. Now it is disabled -only in the case when blk_queue_discard() returns false. - -Signed-off-by: Pali Rohár ---- - fs/exfat/super.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/fs/exfat/super.c b/fs/exfat/super.c -index 16ed202ef527..30e914ad17b5 100644 ---- a/fs/exfat/super.c -+++ b/fs/exfat/super.c -@@ -531,10 +531,11 @@ static int exfat_fill_super(struct super_block *sb, struct fs_context *fc) - if (opts->discard) { - struct request_queue *q = bdev_get_queue(sb->s_bdev); - -- if (!blk_queue_discard(q)) -+ if (!blk_queue_discard(q)) { - exfat_msg(sb, KERN_WARNING, - "mounting with \"discard\" option, but the device does not support discard"); -- opts->discard = 0; -+ opts->discard = 0; -+ } - } - - sb->s_flags |= SB_NODIRATIME; --- -2.20.1 diff --git a/kernel/kernel/files/patches/mageia/fs-exfat-remove-from-staging.patch b/kernel/kernel/files/patches/mageia/fs-exfat-remove-from-staging.patch deleted file mode 100644 index 25268372..00000000 --- a/kernel/kernel/files/patches/mageia/fs-exfat-remove-from-staging.patch +++ /dev/null @@ -1,9152 +0,0 @@ - -This removes the staging driver in favour of the one being merged upstream in 5.7 - -Signed-off-by: Thomas Backlund - ---- - MAINTAINERS | 6 - drivers/staging/Kconfig | 2 - drivers/staging/Makefile | 1 - drivers/staging/exfat/Kconfig | 41 -- - drivers/staging/exfat/Makefile | 10 - drivers/staging/exfat/TODO | 69 --- - drivers/staging/exfat/exfat.h | 824 ---------------------------------------- - drivers/staging/exfat/exfat_blkdev.c | 136 ------ - drivers/staging/exfat/exfat_cache.c | 555 --------------------------- - drivers/staging/exfat/exfat_core.c | 2582 -------------------------------------------------------------------------------------------------------------------------------- - drivers/staging/exfat/exfat_nls.c | 212 ---------- - drivers/staging/exfat/exfat_super.c | 3883 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - drivers/staging/exfat/exfat_upcase.c | 740 ------------------------------------ - 13 files changed, 9061 deletions(-) - -diff -Nurp linux-5.6.3.orig/drivers/staging/exfat/exfat_blkdev.c linux-5.6.3/drivers/staging/exfat/exfat_blkdev.c ---- linux-5.6.3.orig/drivers/staging/exfat/exfat_blkdev.c 2020-03-30 01:25:41.000000000 +0300 -+++ linux-5.6.3/drivers/staging/exfat/exfat_blkdev.c 1970-01-01 02:00:00.000000000 +0200 -@@ -1,136 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0-or-later --/* -- * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -- */ -- --#include --#include --#include --#include "exfat.h" -- --void exfat_bdev_open(struct super_block *sb) --{ -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- if (p_bd->opened) -- return; -- -- p_bd->sector_size = bdev_logical_block_size(sb->s_bdev); -- p_bd->sector_size_bits = ilog2(p_bd->sector_size); -- p_bd->sector_size_mask = p_bd->sector_size - 1; -- p_bd->num_sectors = i_size_read(sb->s_bdev->bd_inode) >> -- p_bd->sector_size_bits; -- p_bd->opened = true; --} -- --void exfat_bdev_close(struct super_block *sb) --{ -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- p_bd->opened = false; --} -- --int exfat_bdev_read(struct super_block *sb, sector_t secno, struct buffer_head **bh, -- u32 num_secs, bool read) --{ -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); --#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- long flags = sbi->debug_flags; -- -- if (flags & EXFAT_DEBUGFLAGS_ERROR_RW) -- return -EIO; --#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */ -- -- if (!p_bd->opened) -- return -ENODEV; -- -- if (*bh) -- __brelse(*bh); -- -- if (read) -- *bh = __bread(sb->s_bdev, secno, -- num_secs << p_bd->sector_size_bits); -- else -- *bh = __getblk(sb->s_bdev, secno, -- num_secs << p_bd->sector_size_bits); -- -- if (*bh) -- return 0; -- -- WARN(!p_fs->dev_ejected, -- "[EXFAT] No bh, device seems wrong or to be ejected.\n"); -- -- return -EIO; --} -- --int exfat_bdev_write(struct super_block *sb, sector_t secno, struct buffer_head *bh, -- u32 num_secs, bool sync) --{ -- s32 count; -- struct buffer_head *bh2; -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); --#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- long flags = sbi->debug_flags; -- -- if (flags & EXFAT_DEBUGFLAGS_ERROR_RW) -- return -EIO; --#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */ -- -- if (!p_bd->opened) -- return -ENODEV; -- -- if (secno == bh->b_blocknr) { -- lock_buffer(bh); -- set_buffer_uptodate(bh); -- mark_buffer_dirty(bh); -- unlock_buffer(bh); -- if (sync && (sync_dirty_buffer(bh) != 0)) -- return -EIO; -- } else { -- count = num_secs << p_bd->sector_size_bits; -- -- bh2 = __getblk(sb->s_bdev, secno, count); -- if (!bh2) -- goto no_bh; -- -- lock_buffer(bh2); -- memcpy(bh2->b_data, bh->b_data, count); -- set_buffer_uptodate(bh2); -- mark_buffer_dirty(bh2); -- unlock_buffer(bh2); -- if (sync && (sync_dirty_buffer(bh2) != 0)) { -- __brelse(bh2); -- goto no_bh; -- } -- __brelse(bh2); -- } -- -- return 0; -- --no_bh: -- WARN(!p_fs->dev_ejected, -- "[EXFAT] No bh, device seems wrong or to be ejected.\n"); -- -- return -EIO; --} -- --int exfat_bdev_sync(struct super_block *sb) --{ -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); --#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- long flags = sbi->debug_flags; -- -- if (flags & EXFAT_DEBUGFLAGS_ERROR_RW) -- return -EIO; --#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */ -- -- if (!p_bd->opened) -- return -ENODEV; -- -- return sync_blockdev(sb->s_bdev); --} -diff -Nurp linux-5.6.3.orig/drivers/staging/exfat/exfat_cache.c linux-5.6.3/drivers/staging/exfat/exfat_cache.c ---- linux-5.6.3.orig/drivers/staging/exfat/exfat_cache.c 2020-03-30 01:25:41.000000000 +0300 -+++ linux-5.6.3/drivers/staging/exfat/exfat_cache.c 1970-01-01 02:00:00.000000000 +0200 -@@ -1,555 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0-or-later --/* -- * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -- */ -- --#include --#include --#include --#include "exfat.h" -- --#define LOCKBIT 0x01 --#define DIRTYBIT 0x02 -- --/* Local variables */ --static DEFINE_MUTEX(f_mutex); --static DEFINE_MUTEX(b_mutex); -- --static struct buf_cache_t *FAT_cache_find(struct super_block *sb, sector_t sec) --{ -- s32 off; -- struct buf_cache_t *bp, *hp; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- off = (sec + -- (sec >> p_fs->sectors_per_clu_bits)) & (FAT_CACHE_HASH_SIZE - 1); -- -- hp = &p_fs->FAT_cache_hash_list[off]; -- for (bp = hp->hash_next; bp != hp; bp = bp->hash_next) { -- if ((bp->drv == p_fs->drv) && (bp->sec == sec)) { -- WARN(!bp->buf_bh, -- "[EXFAT] FAT_cache has no bh. It will make system panic.\n"); -- -- touch_buffer(bp->buf_bh); -- return bp; -- } -- } -- return NULL; --} -- --static void push_to_mru(struct buf_cache_t *bp, struct buf_cache_t *list) --{ -- bp->next = list->next; -- bp->prev = list; -- list->next->prev = bp; -- list->next = bp; --} -- --static void push_to_lru(struct buf_cache_t *bp, struct buf_cache_t *list) --{ -- bp->prev = list->prev; -- bp->next = list; -- list->prev->next = bp; -- list->prev = bp; --} -- --static void move_to_mru(struct buf_cache_t *bp, struct buf_cache_t *list) --{ -- bp->prev->next = bp->next; -- bp->next->prev = bp->prev; -- push_to_mru(bp, list); --} -- --static void move_to_lru(struct buf_cache_t *bp, struct buf_cache_t *list) --{ -- bp->prev->next = bp->next; -- bp->next->prev = bp->prev; -- push_to_lru(bp, list); --} -- --static struct buf_cache_t *FAT_cache_get(struct super_block *sb, sector_t sec) --{ -- struct buf_cache_t *bp; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- bp = p_fs->FAT_cache_lru_list.prev; -- -- move_to_mru(bp, &p_fs->FAT_cache_lru_list); -- return bp; --} -- --static void FAT_cache_insert_hash(struct super_block *sb, -- struct buf_cache_t *bp) --{ -- s32 off; -- struct buf_cache_t *hp; -- struct fs_info_t *p_fs; -- -- p_fs = &(EXFAT_SB(sb)->fs_info); -- off = (bp->sec + -- (bp->sec >> p_fs->sectors_per_clu_bits)) & -- (FAT_CACHE_HASH_SIZE - 1); -- -- hp = &p_fs->FAT_cache_hash_list[off]; -- bp->hash_next = hp->hash_next; -- bp->hash_prev = hp; -- hp->hash_next->hash_prev = bp; -- hp->hash_next = bp; --} -- --static void FAT_cache_remove_hash(struct buf_cache_t *bp) --{ -- (bp->hash_prev)->hash_next = bp->hash_next; -- (bp->hash_next)->hash_prev = bp->hash_prev; --} -- --static void buf_cache_insert_hash(struct super_block *sb, -- struct buf_cache_t *bp) --{ -- s32 off; -- struct buf_cache_t *hp; -- struct fs_info_t *p_fs; -- -- p_fs = &(EXFAT_SB(sb)->fs_info); -- off = (bp->sec + -- (bp->sec >> p_fs->sectors_per_clu_bits)) & -- (BUF_CACHE_HASH_SIZE - 1); -- -- hp = &p_fs->buf_cache_hash_list[off]; -- bp->hash_next = hp->hash_next; -- bp->hash_prev = hp; -- hp->hash_next->hash_prev = bp; -- hp->hash_next = bp; --} -- --static void buf_cache_remove_hash(struct buf_cache_t *bp) --{ -- (bp->hash_prev)->hash_next = bp->hash_next; -- (bp->hash_next)->hash_prev = bp->hash_prev; --} -- --void exfat_buf_init(struct super_block *sb) --{ -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- int i; -- -- /* LRU list */ -- p_fs->FAT_cache_lru_list.next = &p_fs->FAT_cache_lru_list; -- p_fs->FAT_cache_lru_list.prev = &p_fs->FAT_cache_lru_list; -- -- for (i = 0; i < FAT_CACHE_SIZE; i++) { -- p_fs->FAT_cache_array[i].drv = -1; -- p_fs->FAT_cache_array[i].sec = ~0; -- p_fs->FAT_cache_array[i].flag = 0; -- p_fs->FAT_cache_array[i].buf_bh = NULL; -- p_fs->FAT_cache_array[i].prev = NULL; -- p_fs->FAT_cache_array[i].next = NULL; -- push_to_mru(&p_fs->FAT_cache_array[i], -- &p_fs->FAT_cache_lru_list); -- } -- -- p_fs->buf_cache_lru_list.next = &p_fs->buf_cache_lru_list; -- p_fs->buf_cache_lru_list.prev = &p_fs->buf_cache_lru_list; -- -- for (i = 0; i < BUF_CACHE_SIZE; i++) { -- p_fs->buf_cache_array[i].drv = -1; -- p_fs->buf_cache_array[i].sec = ~0; -- p_fs->buf_cache_array[i].flag = 0; -- p_fs->buf_cache_array[i].buf_bh = NULL; -- p_fs->buf_cache_array[i].prev = NULL; -- p_fs->buf_cache_array[i].next = NULL; -- push_to_mru(&p_fs->buf_cache_array[i], -- &p_fs->buf_cache_lru_list); -- } -- -- /* HASH list */ -- for (i = 0; i < FAT_CACHE_HASH_SIZE; i++) { -- p_fs->FAT_cache_hash_list[i].drv = -1; -- p_fs->FAT_cache_hash_list[i].sec = ~0; -- p_fs->FAT_cache_hash_list[i].hash_next = -- &p_fs->FAT_cache_hash_list[i]; -- p_fs->FAT_cache_hash_list[i].hash_prev = -- &p_fs->FAT_cache_hash_list[i]; -- } -- -- for (i = 0; i < FAT_CACHE_SIZE; i++) -- FAT_cache_insert_hash(sb, &p_fs->FAT_cache_array[i]); -- -- for (i = 0; i < BUF_CACHE_HASH_SIZE; i++) { -- p_fs->buf_cache_hash_list[i].drv = -1; -- p_fs->buf_cache_hash_list[i].sec = ~0; -- p_fs->buf_cache_hash_list[i].hash_next = -- &p_fs->buf_cache_hash_list[i]; -- p_fs->buf_cache_hash_list[i].hash_prev = -- &p_fs->buf_cache_hash_list[i]; -- } -- -- for (i = 0; i < BUF_CACHE_SIZE; i++) -- buf_cache_insert_hash(sb, &p_fs->buf_cache_array[i]); --} -- --void exfat_buf_shutdown(struct super_block *sb) --{ --} -- --static int __exfat_fat_read(struct super_block *sb, u32 loc, u32 *content) --{ -- s32 off; -- u32 _content; -- sector_t sec; -- u8 *fat_sector, *fat_entry; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- sec = p_fs->FAT1_start_sector + -- (loc >> (p_bd->sector_size_bits - 2)); -- off = (loc << 2) & p_bd->sector_size_mask; -- -- fat_sector = exfat_fat_getblk(sb, sec); -- if (!fat_sector) -- return -1; -- -- fat_entry = &fat_sector[off]; -- _content = GET32_A(fat_entry); -- -- if (_content >= CLUSTER_32(0xFFFFFFF8)) { -- *content = CLUSTER_32(~0); -- return 0; -- } -- *content = CLUSTER_32(_content); -- return 0; --} -- --/* in : sb, loc -- * out: content -- * returns 0 on success -- * -1 on error -- */ --int exfat_fat_read(struct super_block *sb, u32 loc, u32 *content) --{ -- s32 ret; -- -- mutex_lock(&f_mutex); -- ret = __exfat_fat_read(sb, loc, content); -- mutex_unlock(&f_mutex); -- -- return ret; --} -- --static s32 __exfat_fat_write(struct super_block *sb, u32 loc, u32 content) --{ -- s32 off; -- sector_t sec; -- u8 *fat_sector, *fat_entry; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- sec = p_fs->FAT1_start_sector + (loc >> -- (p_bd->sector_size_bits - 2)); -- off = (loc << 2) & p_bd->sector_size_mask; -- -- fat_sector = exfat_fat_getblk(sb, sec); -- if (!fat_sector) -- return -1; -- -- fat_entry = &fat_sector[off]; -- -- SET32_A(fat_entry, content); -- -- exfat_fat_modify(sb, sec); -- return 0; --} -- --int exfat_fat_write(struct super_block *sb, u32 loc, u32 content) --{ -- s32 ret; -- -- mutex_lock(&f_mutex); -- ret = __exfat_fat_write(sb, loc, content); -- mutex_unlock(&f_mutex); -- -- return ret; --} -- --u8 *exfat_fat_getblk(struct super_block *sb, sector_t sec) --{ -- struct buf_cache_t *bp; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- bp = FAT_cache_find(sb, sec); -- if (bp) { -- move_to_mru(bp, &p_fs->FAT_cache_lru_list); -- return bp->buf_bh->b_data; -- } -- -- bp = FAT_cache_get(sb, sec); -- -- FAT_cache_remove_hash(bp); -- -- bp->drv = p_fs->drv; -- bp->sec = sec; -- bp->flag = 0; -- -- FAT_cache_insert_hash(sb, bp); -- -- if (sector_read(sb, sec, &bp->buf_bh, 1) != 0) { -- FAT_cache_remove_hash(bp); -- bp->drv = -1; -- bp->sec = ~0; -- bp->flag = 0; -- bp->buf_bh = NULL; -- -- move_to_lru(bp, &p_fs->FAT_cache_lru_list); -- return NULL; -- } -- -- return bp->buf_bh->b_data; --} -- --void exfat_fat_modify(struct super_block *sb, sector_t sec) --{ -- struct buf_cache_t *bp; -- -- bp = FAT_cache_find(sb, sec); -- if (bp) -- sector_write(sb, sec, bp->buf_bh, 0); --} -- --void exfat_fat_release_all(struct super_block *sb) --{ -- struct buf_cache_t *bp; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- mutex_lock(&f_mutex); -- -- bp = p_fs->FAT_cache_lru_list.next; -- while (bp != &p_fs->FAT_cache_lru_list) { -- if (bp->drv == p_fs->drv) { -- bp->drv = -1; -- bp->sec = ~0; -- bp->flag = 0; -- -- if (bp->buf_bh) { -- __brelse(bp->buf_bh); -- bp->buf_bh = NULL; -- } -- } -- bp = bp->next; -- } -- -- mutex_unlock(&f_mutex); --} -- --void exfat_fat_sync(struct super_block *sb) --{ -- struct buf_cache_t *bp; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- mutex_lock(&f_mutex); -- -- bp = p_fs->FAT_cache_lru_list.next; -- while (bp != &p_fs->FAT_cache_lru_list) { -- if ((bp->drv == p_fs->drv) && (bp->flag & DIRTYBIT)) { -- sync_dirty_buffer(bp->buf_bh); -- bp->flag &= ~(DIRTYBIT); -- } -- bp = bp->next; -- } -- -- mutex_unlock(&f_mutex); --} -- --static struct buf_cache_t *buf_cache_find(struct super_block *sb, sector_t sec) --{ -- s32 off; -- struct buf_cache_t *bp, *hp; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- off = (sec + (sec >> p_fs->sectors_per_clu_bits)) & -- (BUF_CACHE_HASH_SIZE - 1); -- -- hp = &p_fs->buf_cache_hash_list[off]; -- for (bp = hp->hash_next; bp != hp; bp = bp->hash_next) { -- if ((bp->drv == p_fs->drv) && (bp->sec == sec)) { -- touch_buffer(bp->buf_bh); -- return bp; -- } -- } -- return NULL; --} -- --static struct buf_cache_t *buf_cache_get(struct super_block *sb, sector_t sec) --{ -- struct buf_cache_t *bp; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- bp = p_fs->buf_cache_lru_list.prev; -- while (bp->flag & LOCKBIT) -- bp = bp->prev; -- -- move_to_mru(bp, &p_fs->buf_cache_lru_list); -- return bp; --} -- --static u8 *__exfat_buf_getblk(struct super_block *sb, sector_t sec) --{ -- struct buf_cache_t *bp; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- bp = buf_cache_find(sb, sec); -- if (bp) { -- move_to_mru(bp, &p_fs->buf_cache_lru_list); -- return bp->buf_bh->b_data; -- } -- -- bp = buf_cache_get(sb, sec); -- -- buf_cache_remove_hash(bp); -- -- bp->drv = p_fs->drv; -- bp->sec = sec; -- bp->flag = 0; -- -- buf_cache_insert_hash(sb, bp); -- -- if (sector_read(sb, sec, &bp->buf_bh, 1) != 0) { -- buf_cache_remove_hash(bp); -- bp->drv = -1; -- bp->sec = ~0; -- bp->flag = 0; -- bp->buf_bh = NULL; -- -- move_to_lru(bp, &p_fs->buf_cache_lru_list); -- return NULL; -- } -- -- return bp->buf_bh->b_data; --} -- --u8 *exfat_buf_getblk(struct super_block *sb, sector_t sec) --{ -- u8 *buf; -- -- mutex_lock(&b_mutex); -- buf = __exfat_buf_getblk(sb, sec); -- mutex_unlock(&b_mutex); -- -- return buf; --} -- --void exfat_buf_modify(struct super_block *sb, sector_t sec) --{ -- struct buf_cache_t *bp; -- -- mutex_lock(&b_mutex); -- -- bp = buf_cache_find(sb, sec); -- if (likely(bp)) -- sector_write(sb, sec, bp->buf_bh, 0); -- -- WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%llu).\n", -- (unsigned long long)sec); -- -- mutex_unlock(&b_mutex); --} -- --void exfat_buf_lock(struct super_block *sb, sector_t sec) --{ -- struct buf_cache_t *bp; -- -- mutex_lock(&b_mutex); -- -- bp = buf_cache_find(sb, sec); -- if (likely(bp)) -- bp->flag |= LOCKBIT; -- -- WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%llu).\n", -- (unsigned long long)sec); -- -- mutex_unlock(&b_mutex); --} -- --void exfat_buf_unlock(struct super_block *sb, sector_t sec) --{ -- struct buf_cache_t *bp; -- -- mutex_lock(&b_mutex); -- -- bp = buf_cache_find(sb, sec); -- if (likely(bp)) -- bp->flag &= ~(LOCKBIT); -- -- WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%llu).\n", -- (unsigned long long)sec); -- -- mutex_unlock(&b_mutex); --} -- --void exfat_buf_release(struct super_block *sb, sector_t sec) --{ -- struct buf_cache_t *bp; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- mutex_lock(&b_mutex); -- -- bp = buf_cache_find(sb, sec); -- if (likely(bp)) { -- bp->drv = -1; -- bp->sec = ~0; -- bp->flag = 0; -- -- if (bp->buf_bh) { -- __brelse(bp->buf_bh); -- bp->buf_bh = NULL; -- } -- -- move_to_lru(bp, &p_fs->buf_cache_lru_list); -- } -- -- mutex_unlock(&b_mutex); --} -- --void exfat_buf_release_all(struct super_block *sb) --{ -- struct buf_cache_t *bp; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- mutex_lock(&b_mutex); -- -- bp = p_fs->buf_cache_lru_list.next; -- while (bp != &p_fs->buf_cache_lru_list) { -- if (bp->drv == p_fs->drv) { -- bp->drv = -1; -- bp->sec = ~0; -- bp->flag = 0; -- -- if (bp->buf_bh) { -- __brelse(bp->buf_bh); -- bp->buf_bh = NULL; -- } -- } -- bp = bp->next; -- } -- -- mutex_unlock(&b_mutex); --} -- --void exfat_buf_sync(struct super_block *sb) --{ -- struct buf_cache_t *bp; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- mutex_lock(&b_mutex); -- -- bp = p_fs->buf_cache_lru_list.next; -- while (bp != &p_fs->buf_cache_lru_list) { -- if ((bp->drv == p_fs->drv) && (bp->flag & DIRTYBIT)) { -- sync_dirty_buffer(bp->buf_bh); -- bp->flag &= ~(DIRTYBIT); -- } -- bp = bp->next; -- } -- -- mutex_unlock(&b_mutex); --} -diff -Nurp linux-5.6.3.orig/drivers/staging/exfat/exfat_core.c linux-5.6.3/drivers/staging/exfat/exfat_core.c ---- linux-5.6.3.orig/drivers/staging/exfat/exfat_core.c 2020-03-30 01:25:41.000000000 +0300 -+++ linux-5.6.3/drivers/staging/exfat/exfat_core.c 1970-01-01 02:00:00.000000000 +0200 -@@ -1,2582 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0-or-later --/* -- * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -- */ -- --#include --#include --#include --#include --#include --#include --#include "exfat.h" -- --static void __set_sb_dirty(struct super_block *sb) --{ -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- -- sbi->s_dirt = 1; --} -- --static u8 name_buf[MAX_PATH_LENGTH * MAX_CHARSET_SIZE]; -- --static u8 free_bit[] = { -- 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, /* 0 ~ 19 */ -- 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, /* 20 ~ 39 */ -- 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, /* 40 ~ 59 */ -- 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* 60 ~ 79 */ -- 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, /* 80 ~ 99 */ -- 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, /* 100 ~ 119 */ -- 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, /* 120 ~ 139 */ -- 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, /* 140 ~ 159 */ -- 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, /* 160 ~ 179 */ -- 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, /* 180 ~ 199 */ -- 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, /* 200 ~ 219 */ -- 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* 220 ~ 239 */ -- 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 /* 240 ~ 254 */ --}; -- --static u8 used_bit[] = { -- 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, /* 0 ~ 19 */ -- 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, /* 20 ~ 39 */ -- 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, /* 40 ~ 59 */ -- 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, /* 60 ~ 79 */ -- 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, /* 80 ~ 99 */ -- 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, /* 100 ~ 119 */ -- 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, /* 120 ~ 139 */ -- 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 140 ~ 159 */ -- 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, /* 160 ~ 179 */ -- 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, /* 180 ~ 199 */ -- 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, /* 200 ~ 219 */ -- 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 220 ~ 239 */ -- 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 /* 240 ~ 255 */ --}; -- --#define BITMAP_LOC(v) ((v) >> 3) --#define BITMAP_SHIFT(v) ((v) & 0x07) -- --static inline s32 exfat_bitmap_test(u8 *bitmap, int i) --{ -- u8 data; -- -- data = bitmap[BITMAP_LOC(i)]; -- if ((data >> BITMAP_SHIFT(i)) & 0x01) -- return 1; -- return 0; --} -- --static inline void exfat_bitmap_set(u8 *bitmap, int i) --{ -- bitmap[BITMAP_LOC(i)] |= (0x01 << BITMAP_SHIFT(i)); --} -- --static inline void exfat_bitmap_clear(u8 *bitmap, int i) --{ -- bitmap[BITMAP_LOC(i)] &= ~(0x01 << BITMAP_SHIFT(i)); --} -- --/* -- * File System Management Functions -- */ -- --void fs_set_vol_flags(struct super_block *sb, u32 new_flag) --{ -- struct pbr_sector_t *p_pbr; -- struct bpbex_t *p_bpb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- if (p_fs->vol_flag == new_flag) -- return; -- -- p_fs->vol_flag = new_flag; -- -- if (!p_fs->pbr_bh) { -- if (sector_read(sb, p_fs->PBR_sector, -- &p_fs->pbr_bh, 1) != 0) -- return; -- } -- -- p_pbr = (struct pbr_sector_t *)p_fs->pbr_bh->b_data; -- p_bpb = (struct bpbex_t *)p_pbr->bpb; -- SET16(p_bpb->vol_flags, (u16)new_flag); -- -- /* XXX duyoung -- * what can we do here? (cuz fs_set_vol_flags() is void) -- */ -- if ((new_flag == VOL_DIRTY) && (!buffer_dirty(p_fs->pbr_bh))) -- sector_write(sb, p_fs->PBR_sector, p_fs->pbr_bh, 1); -- else -- sector_write(sb, p_fs->PBR_sector, p_fs->pbr_bh, 0); --} -- --void fs_error(struct super_block *sb) --{ -- struct exfat_mount_options *opts = &EXFAT_SB(sb)->options; -- -- if (opts->errors == EXFAT_ERRORS_PANIC) { -- panic("[EXFAT] Filesystem panic from previous error\n"); -- } else if ((opts->errors == EXFAT_ERRORS_RO) && !sb_rdonly(sb)) { -- sb->s_flags |= SB_RDONLY; -- pr_err("[EXFAT] Filesystem has been set read-only\n"); -- } --} -- --/* -- * Cluster Management Functions -- */ -- --static s32 clear_cluster(struct super_block *sb, u32 clu) --{ -- sector_t s, n; -- s32 ret = 0; -- struct buffer_head *tmp_bh = NULL; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- if (clu == CLUSTER_32(0)) { /* FAT16 root_dir */ -- s = p_fs->root_start_sector; -- n = p_fs->data_start_sector; -- } else { -- s = START_SECTOR(clu); -- n = s + p_fs->sectors_per_clu; -- } -- -- for (; s < n; s++) { -- ret = sector_read(sb, s, &tmp_bh, 0); -- if (ret != 0) -- return ret; -- -- memset((char *)tmp_bh->b_data, 0x0, p_bd->sector_size); -- ret = sector_write(sb, s, tmp_bh, 0); -- if (ret != 0) -- break; -- } -- -- brelse(tmp_bh); -- return ret; --} -- --static s32 set_alloc_bitmap(struct super_block *sb, u32 clu) --{ -- int i, b; -- sector_t sector; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- i = clu >> (p_bd->sector_size_bits + 3); -- b = clu & ((p_bd->sector_size << 3) - 1); -- -- sector = START_SECTOR(p_fs->map_clu) + i; -- -- exfat_bitmap_set((u8 *)p_fs->vol_amap[i]->b_data, b); -- -- return sector_write(sb, sector, p_fs->vol_amap[i], 0); --} -- --static s32 clr_alloc_bitmap(struct super_block *sb, u32 clu) --{ -- int i, b; -- sector_t sector; --#ifdef CONFIG_STAGING_EXFAT_DISCARD -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- struct exfat_mount_options *opts = &sbi->options; -- int ret; --#endif /* CONFIG_STAGING_EXFAT_DISCARD */ -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- i = clu >> (p_bd->sector_size_bits + 3); -- b = clu & ((p_bd->sector_size << 3) - 1); -- -- sector = START_SECTOR(p_fs->map_clu) + i; -- -- exfat_bitmap_clear((u8 *)p_fs->vol_amap[i]->b_data, b); -- --#ifdef CONFIG_STAGING_EXFAT_DISCARD -- if (opts->discard) { -- ret = sb_issue_discard(sb, START_SECTOR(clu), -- (1 << p_fs->sectors_per_clu_bits), -- GFP_NOFS, 0); -- if (ret == -EOPNOTSUPP) { -- pr_warn("discard not supported by device, disabling"); -- opts->discard = 0; -- } else { -- return ret; -- } -- } --#endif /* CONFIG_STAGING_EXFAT_DISCARD */ -- -- return sector_write(sb, sector, p_fs->vol_amap[i], 0); --} -- --static u32 test_alloc_bitmap(struct super_block *sb, u32 clu) --{ -- int i, map_i, map_b; -- u32 clu_base, clu_free; -- u8 k, clu_mask; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- clu_base = (clu & ~(0x7)) + 2; -- clu_mask = (1 << (clu - clu_base + 2)) - 1; -- -- map_i = clu >> (p_bd->sector_size_bits + 3); -- map_b = (clu >> 3) & p_bd->sector_size_mask; -- -- for (i = 2; i < p_fs->num_clusters; i += 8) { -- k = *(((u8 *)p_fs->vol_amap[map_i]->b_data) + map_b); -- if (clu_mask > 0) { -- k |= clu_mask; -- clu_mask = 0; -- } -- if (k < 0xFF) { -- clu_free = clu_base + free_bit[k]; -- if (clu_free < p_fs->num_clusters) -- return clu_free; -- } -- clu_base += 8; -- -- if (((++map_b) >= p_bd->sector_size) || -- (clu_base >= p_fs->num_clusters)) { -- if ((++map_i) >= p_fs->map_sectors) { -- clu_base = 2; -- map_i = 0; -- } -- map_b = 0; -- } -- } -- -- return CLUSTER_32(~0); --} -- --s32 exfat_alloc_cluster(struct super_block *sb, s32 num_alloc, -- struct chain_t *p_chain) --{ -- s32 num_clusters = 0; -- u32 hint_clu, new_clu, last_clu = CLUSTER_32(~0); -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- hint_clu = p_chain->dir; -- if (hint_clu == CLUSTER_32(~0)) { -- hint_clu = test_alloc_bitmap(sb, p_fs->clu_srch_ptr - 2); -- if (hint_clu == CLUSTER_32(~0)) -- return 0; -- } else if (hint_clu >= p_fs->num_clusters) { -- hint_clu = 2; -- p_chain->flags = 0x01; -- } -- -- __set_sb_dirty(sb); -- -- p_chain->dir = CLUSTER_32(~0); -- -- while ((new_clu = test_alloc_bitmap(sb, hint_clu - 2)) != CLUSTER_32(~0)) { -- if (new_clu != hint_clu) { -- if (p_chain->flags == 0x03) { -- exfat_chain_cont_cluster(sb, p_chain->dir, -- num_clusters); -- p_chain->flags = 0x01; -- } -- } -- -- if (set_alloc_bitmap(sb, new_clu - 2) != 0) -- return -EIO; -- -- num_clusters++; -- -- if (p_chain->flags == 0x01) { -- if (exfat_fat_write(sb, new_clu, CLUSTER_32(~0)) < 0) -- return -EIO; -- } -- -- if (p_chain->dir == CLUSTER_32(~0)) { -- p_chain->dir = new_clu; -- } else { -- if (p_chain->flags == 0x01) { -- if (exfat_fat_write(sb, last_clu, new_clu) < 0) -- return -EIO; -- } -- } -- last_clu = new_clu; -- -- if ((--num_alloc) == 0) { -- p_fs->clu_srch_ptr = hint_clu; -- if (p_fs->used_clusters != UINT_MAX) -- p_fs->used_clusters += num_clusters; -- -- p_chain->size += num_clusters; -- return num_clusters; -- } -- -- hint_clu = new_clu + 1; -- if (hint_clu >= p_fs->num_clusters) { -- hint_clu = 2; -- -- if (p_chain->flags == 0x03) { -- exfat_chain_cont_cluster(sb, p_chain->dir, -- num_clusters); -- p_chain->flags = 0x01; -- } -- } -- } -- -- p_fs->clu_srch_ptr = hint_clu; -- if (p_fs->used_clusters != UINT_MAX) -- p_fs->used_clusters += num_clusters; -- -- p_chain->size += num_clusters; -- return num_clusters; --} -- --void exfat_free_cluster(struct super_block *sb, struct chain_t *p_chain, -- s32 do_relse) --{ -- s32 num_clusters = 0; -- u32 clu; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- int i; -- sector_t sector; -- -- if ((p_chain->dir == CLUSTER_32(0)) || (p_chain->dir == CLUSTER_32(~0))) -- return; -- -- if (p_chain->size <= 0) { -- pr_err("[EXFAT] free_cluster : skip free-req clu:%u, because of zero-size truncation\n", -- p_chain->dir); -- return; -- } -- -- __set_sb_dirty(sb); -- clu = p_chain->dir; -- -- if (p_chain->flags == 0x03) { -- do { -- if (do_relse) { -- sector = START_SECTOR(clu); -- for (i = 0; i < p_fs->sectors_per_clu; i++) -- exfat_buf_release(sb, sector + i); -- } -- -- if (clr_alloc_bitmap(sb, clu - 2) != 0) -- break; -- clu++; -- -- num_clusters++; -- } while (num_clusters < p_chain->size); -- } else { -- do { -- if (p_fs->dev_ejected) -- break; -- -- if (do_relse) { -- sector = START_SECTOR(clu); -- for (i = 0; i < p_fs->sectors_per_clu; i++) -- exfat_buf_release(sb, sector + i); -- } -- -- if (clr_alloc_bitmap(sb, clu - 2) != 0) -- break; -- -- if (exfat_fat_read(sb, clu, &clu) == -1) -- break; -- num_clusters++; -- } while ((clu != CLUSTER_32(0)) && (clu != CLUSTER_32(~0))); -- } -- -- if (p_fs->used_clusters != UINT_MAX) -- p_fs->used_clusters -= num_clusters; --} -- --static u32 find_last_cluster(struct super_block *sb, struct chain_t *p_chain) --{ -- u32 clu, next; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- clu = p_chain->dir; -- -- if (p_chain->flags == 0x03) { -- clu += p_chain->size - 1; -- } else { -- while ((exfat_fat_read(sb, clu, &next) == 0) && -- (next != CLUSTER_32(~0))) { -- if (p_fs->dev_ejected) -- break; -- clu = next; -- } -- } -- -- return clu; --} -- --s32 count_num_clusters(struct super_block *sb, struct chain_t *p_chain) --{ -- int i, count = 0; -- u32 clu; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- if ((p_chain->dir == CLUSTER_32(0)) || (p_chain->dir == CLUSTER_32(~0))) -- return 0; -- -- clu = p_chain->dir; -- -- if (p_chain->flags == 0x03) { -- count = p_chain->size; -- } else { -- for (i = 2; i < p_fs->num_clusters; i++) { -- count++; -- if (exfat_fat_read(sb, clu, &clu) != 0) -- return 0; -- if (clu == CLUSTER_32(~0)) -- break; -- } -- } -- -- return count; --} -- --s32 exfat_count_used_clusters(struct super_block *sb) --{ -- int i, map_i, map_b, count = 0; -- u8 k; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- map_i = 0; -- map_b = 0; -- -- for (i = 2; i < p_fs->num_clusters; i += 8) { -- k = *(((u8 *)p_fs->vol_amap[map_i]->b_data) + map_b); -- count += used_bit[k]; -- -- if ((++map_b) >= p_bd->sector_size) { -- map_i++; -- map_b = 0; -- } -- } -- -- return count; --} -- --void exfat_chain_cont_cluster(struct super_block *sb, u32 chain, s32 len) --{ -- if (len == 0) -- return; -- -- while (len > 1) { -- if (exfat_fat_write(sb, chain, chain + 1) < 0) -- break; -- chain++; -- len--; -- } -- exfat_fat_write(sb, chain, CLUSTER_32(~0)); --} -- --/* -- * Allocation Bitmap Management Functions -- */ -- --s32 load_alloc_bitmap(struct super_block *sb) --{ -- int i, j, ret; -- u32 map_size; -- u32 type; -- sector_t sector; -- struct chain_t clu; -- struct bmap_dentry_t *ep; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- clu.dir = p_fs->root_dir; -- clu.flags = 0x01; -- -- while (clu.dir != CLUSTER_32(~0)) { -- if (p_fs->dev_ejected) -- break; -- -- for (i = 0; i < p_fs->dentries_per_clu; i++) { -- ep = (struct bmap_dentry_t *)get_entry_in_dir(sb, &clu, -- i, NULL); -- if (!ep) -- return -ENOENT; -- -- type = exfat_get_entry_type((struct dentry_t *)ep); -- -- if (type == TYPE_UNUSED) -- break; -- if (type != TYPE_BITMAP) -- continue; -- -- if (ep->flags == 0x0) { -- p_fs->map_clu = GET32_A(ep->start_clu); -- map_size = (u32)GET64_A(ep->size); -- -- p_fs->map_sectors = ((map_size - 1) >> p_bd->sector_size_bits) + 1; -- -- p_fs->vol_amap = kmalloc_array(p_fs->map_sectors, -- sizeof(struct buffer_head *), -- GFP_KERNEL); -- if (!p_fs->vol_amap) -- return -ENOMEM; -- -- sector = START_SECTOR(p_fs->map_clu); -- -- for (j = 0; j < p_fs->map_sectors; j++) { -- p_fs->vol_amap[j] = NULL; -- ret = sector_read(sb, sector + j, &p_fs->vol_amap[j], 1); -- if (ret != 0) { -- /* release all buffers and free vol_amap */ -- i = 0; -- while (i < j) -- brelse(p_fs->vol_amap[i++]); -- -- kfree(p_fs->vol_amap); -- p_fs->vol_amap = NULL; -- return ret; -- } -- } -- -- p_fs->pbr_bh = NULL; -- return 0; -- } -- } -- -- if (exfat_fat_read(sb, clu.dir, &clu.dir) != 0) -- return -EIO; -- } -- -- return -EFSCORRUPTED; --} -- --void free_alloc_bitmap(struct super_block *sb) --{ -- int i; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- brelse(p_fs->pbr_bh); -- -- for (i = 0; i < p_fs->map_sectors; i++) -- __brelse(p_fs->vol_amap[i]); -- -- kfree(p_fs->vol_amap); -- p_fs->vol_amap = NULL; --} -- --void sync_alloc_bitmap(struct super_block *sb) --{ -- int i; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- if (!p_fs->vol_amap) -- return; -- -- for (i = 0; i < p_fs->map_sectors; i++) -- sync_dirty_buffer(p_fs->vol_amap[i]); --} -- --/* -- * Upcase table Management Functions -- */ --static s32 __load_upcase_table(struct super_block *sb, sector_t sector, -- u32 num_sectors, u32 utbl_checksum) --{ -- int i, ret = -EINVAL; -- u32 j; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- struct buffer_head *tmp_bh = NULL; -- sector_t end_sector = num_sectors + sector; -- -- bool skip = false; -- u32 index = 0; -- u16 uni = 0; -- u16 **upcase_table; -- -- u32 checksum = 0; -- -- upcase_table = kmalloc_array(UTBL_COL_COUNT, sizeof(u16 *), GFP_KERNEL); -- p_fs->vol_utbl = upcase_table; -- if (!upcase_table) -- return -ENOMEM; -- memset(upcase_table, 0, UTBL_COL_COUNT * sizeof(u16 *)); -- -- while (sector < end_sector) { -- ret = sector_read(sb, sector, &tmp_bh, 1); -- if (ret != 0) { -- pr_debug("sector read (0x%llX)fail\n", -- (unsigned long long)sector); -- goto error; -- } -- sector++; -- -- for (i = 0; i < p_bd->sector_size && index <= 0xFFFF; i += 2) { -- uni = GET16(((u8 *)tmp_bh->b_data) + i); -- -- checksum = ((checksum & 1) ? 0x80000000 : 0) + -- (checksum >> 1) + *(((u8 *)tmp_bh->b_data) + -- i); -- checksum = ((checksum & 1) ? 0x80000000 : 0) + -- (checksum >> 1) + *(((u8 *)tmp_bh->b_data) + -- (i + 1)); -- -- if (skip) { -- pr_debug("skip from 0x%X ", index); -- index += uni; -- pr_debug("to 0x%X (amount of 0x%X)\n", -- index, uni); -- skip = false; -- } else if (uni == index) { -- index++; -- } else if (uni == 0xFFFF) { -- skip = true; -- } else { /* uni != index , uni != 0xFFFF */ -- u16 col_index = get_col_index(index); -- -- if (!upcase_table[col_index]) { -- pr_debug("alloc = 0x%X\n", col_index); -- upcase_table[col_index] = kmalloc_array(UTBL_ROW_COUNT, -- sizeof(u16), GFP_KERNEL); -- if (!upcase_table[col_index]) { -- ret = -ENOMEM; -- goto error; -- } -- -- for (j = 0; j < UTBL_ROW_COUNT; j++) -- upcase_table[col_index][j] = (col_index << LOW_INDEX_BIT) | j; -- } -- -- upcase_table[col_index][get_row_index(index)] = uni; -- index++; -- } -- } -- } -- if (index >= 0xFFFF && utbl_checksum == checksum) { -- if (tmp_bh) -- brelse(tmp_bh); -- return 0; -- } -- ret = -EINVAL; --error: -- if (tmp_bh) -- brelse(tmp_bh); -- free_upcase_table(sb); -- return ret; --} -- --static s32 __load_default_upcase_table(struct super_block *sb) --{ -- int i, ret = -EINVAL; -- u32 j; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- bool skip = false; -- u32 index = 0; -- u16 uni = 0; -- u16 **upcase_table; -- -- upcase_table = kmalloc_array(UTBL_COL_COUNT, sizeof(u16 *), GFP_KERNEL); -- p_fs->vol_utbl = upcase_table; -- if (!upcase_table) -- return -ENOMEM; -- memset(upcase_table, 0, UTBL_COL_COUNT * sizeof(u16 *)); -- -- for (i = 0; index <= 0xFFFF && i < NUM_UPCASE * 2; i += 2) { -- uni = GET16(uni_upcase + i); -- if (skip) { -- pr_debug("skip from 0x%X ", index); -- index += uni; -- pr_debug("to 0x%X (amount of 0x%X)\n", index, uni); -- skip = false; -- } else if (uni == index) { -- index++; -- } else if (uni == 0xFFFF) { -- skip = true; -- } else { /* uni != index , uni != 0xFFFF */ -- u16 col_index = get_col_index(index); -- -- if (!upcase_table[col_index]) { -- pr_debug("alloc = 0x%X\n", col_index); -- upcase_table[col_index] = kmalloc_array(UTBL_ROW_COUNT, -- sizeof(u16), -- GFP_KERNEL); -- if (!upcase_table[col_index]) { -- ret = -ENOMEM; -- goto error; -- } -- -- for (j = 0; j < UTBL_ROW_COUNT; j++) -- upcase_table[col_index][j] = (col_index << LOW_INDEX_BIT) | j; -- } -- -- upcase_table[col_index][get_row_index(index)] = uni; -- index++; -- } -- } -- -- if (index >= 0xFFFF) -- return 0; -- --error: -- /* FATAL error: default upcase table has error */ -- free_upcase_table(sb); -- return ret; --} -- --s32 load_upcase_table(struct super_block *sb) --{ -- int i; -- u32 tbl_clu, tbl_size; -- sector_t sector; -- u32 type, num_sectors; -- struct chain_t clu; -- struct case_dentry_t *ep; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- clu.dir = p_fs->root_dir; -- clu.flags = 0x01; -- -- if (p_fs->dev_ejected) -- return -EIO; -- -- while (clu.dir != CLUSTER_32(~0)) { -- for (i = 0; i < p_fs->dentries_per_clu; i++) { -- ep = (struct case_dentry_t *)get_entry_in_dir(sb, &clu, -- i, NULL); -- if (!ep) -- return -ENOENT; -- -- type = exfat_get_entry_type((struct dentry_t *)ep); -- -- if (type == TYPE_UNUSED) -- break; -- if (type != TYPE_UPCASE) -- continue; -- -- tbl_clu = GET32_A(ep->start_clu); -- tbl_size = (u32)GET64_A(ep->size); -- -- sector = START_SECTOR(tbl_clu); -- num_sectors = ((tbl_size - 1) >> p_bd->sector_size_bits) + 1; -- if (__load_upcase_table(sb, sector, num_sectors, -- GET32_A(ep->checksum)) != 0) -- break; -- return 0; -- } -- if (exfat_fat_read(sb, clu.dir, &clu.dir) != 0) -- return -EIO; -- } -- /* load default upcase table */ -- return __load_default_upcase_table(sb); --} -- --void free_upcase_table(struct super_block *sb) --{ -- u32 i; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- u16 **upcase_table; -- -- upcase_table = p_fs->vol_utbl; -- for (i = 0; i < UTBL_COL_COUNT; i++) -- kfree(upcase_table[i]); -- -- kfree(p_fs->vol_utbl); -- p_fs->vol_utbl = NULL; --} -- --/* -- * Directory Entry Management Functions -- */ -- --u32 exfat_get_entry_type(struct dentry_t *p_entry) --{ -- struct file_dentry_t *ep = (struct file_dentry_t *)p_entry; -- -- if (ep->type == 0x0) { -- return TYPE_UNUSED; -- } else if (ep->type < 0x80) { -- return TYPE_DELETED; -- } else if (ep->type == 0x80) { -- return TYPE_INVALID; -- } else if (ep->type < 0xA0) { -- if (ep->type == 0x81) { -- return TYPE_BITMAP; -- } else if (ep->type == 0x82) { -- return TYPE_UPCASE; -- } else if (ep->type == 0x83) { -- return TYPE_VOLUME; -- } else if (ep->type == 0x85) { -- if (GET16_A(ep->attr) & ATTR_SUBDIR) -- return TYPE_DIR; -- else -- return TYPE_FILE; -- } -- return TYPE_CRITICAL_PRI; -- } else if (ep->type < 0xC0) { -- if (ep->type == 0xA0) -- return TYPE_GUID; -- else if (ep->type == 0xA1) -- return TYPE_PADDING; -- else if (ep->type == 0xA2) -- return TYPE_ACLTAB; -- return TYPE_BENIGN_PRI; -- } else if (ep->type < 0xE0) { -- if (ep->type == 0xC0) -- return TYPE_STREAM; -- else if (ep->type == 0xC1) -- return TYPE_EXTEND; -- else if (ep->type == 0xC2) -- return TYPE_ACL; -- return TYPE_CRITICAL_SEC; -- } -- -- return TYPE_BENIGN_SEC; --} -- --static void exfat_set_entry_type(struct dentry_t *p_entry, u32 type) --{ -- struct file_dentry_t *ep = (struct file_dentry_t *)p_entry; -- -- if (type == TYPE_UNUSED) { -- ep->type = 0x0; -- } else if (type == TYPE_DELETED) { -- ep->type &= ~0x80; -- } else if (type == TYPE_STREAM) { -- ep->type = 0xC0; -- } else if (type == TYPE_EXTEND) { -- ep->type = 0xC1; -- } else if (type == TYPE_BITMAP) { -- ep->type = 0x81; -- } else if (type == TYPE_UPCASE) { -- ep->type = 0x82; -- } else if (type == TYPE_VOLUME) { -- ep->type = 0x83; -- } else if (type == TYPE_DIR) { -- ep->type = 0x85; -- SET16_A(ep->attr, ATTR_SUBDIR); -- } else if (type == TYPE_FILE) { -- ep->type = 0x85; -- SET16_A(ep->attr, ATTR_ARCHIVE); -- } else if (type == TYPE_SYMLINK) { -- ep->type = 0x85; -- SET16_A(ep->attr, ATTR_ARCHIVE | ATTR_SYMLINK); -- } --} -- --u32 exfat_get_entry_attr(struct dentry_t *p_entry) --{ -- struct file_dentry_t *ep = (struct file_dentry_t *)p_entry; -- -- return (u32)GET16_A(ep->attr); --} -- --void exfat_set_entry_attr(struct dentry_t *p_entry, u32 attr) --{ -- struct file_dentry_t *ep = (struct file_dentry_t *)p_entry; -- -- SET16_A(ep->attr, (u16)attr); --} -- --u8 exfat_get_entry_flag(struct dentry_t *p_entry) --{ -- struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry; -- -- return ep->flags; --} -- --void exfat_set_entry_flag(struct dentry_t *p_entry, u8 flags) --{ -- struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry; -- -- ep->flags = flags; --} -- --u32 exfat_get_entry_clu0(struct dentry_t *p_entry) --{ -- struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry; -- -- return GET32_A(ep->start_clu); --} -- --void exfat_set_entry_clu0(struct dentry_t *p_entry, u32 start_clu) --{ -- struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry; -- -- SET32_A(ep->start_clu, start_clu); --} -- --u64 exfat_get_entry_size(struct dentry_t *p_entry) --{ -- struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry; -- -- return GET64_A(ep->valid_size); --} -- --void exfat_set_entry_size(struct dentry_t *p_entry, u64 size) --{ -- struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry; -- -- SET64_A(ep->valid_size, size); -- SET64_A(ep->size, size); --} -- --void exfat_get_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp, -- u8 mode) --{ -- u16 t = 0x00, d = 0x21; -- struct file_dentry_t *ep = (struct file_dentry_t *)p_entry; -- -- switch (mode) { -- case TM_CREATE: -- t = GET16_A(ep->create_time); -- d = GET16_A(ep->create_date); -- break; -- case TM_MODIFY: -- t = GET16_A(ep->modify_time); -- d = GET16_A(ep->modify_date); -- break; -- case TM_ACCESS: -- t = GET16_A(ep->access_time); -- d = GET16_A(ep->access_date); -- break; -- } -- -- tp->sec = (t & 0x001F) << 1; -- tp->min = (t >> 5) & 0x003F; -- tp->hour = (t >> 11); -- tp->day = (d & 0x001F); -- tp->mon = (d >> 5) & 0x000F; -- tp->year = (d >> 9); --} -- --void exfat_set_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp, -- u8 mode) --{ -- u16 t, d; -- struct file_dentry_t *ep = (struct file_dentry_t *)p_entry; -- -- t = (tp->hour << 11) | (tp->min << 5) | (tp->sec >> 1); -- d = (tp->year << 9) | (tp->mon << 5) | tp->day; -- -- switch (mode) { -- case TM_CREATE: -- SET16_A(ep->create_time, t); -- SET16_A(ep->create_date, d); -- break; -- case TM_MODIFY: -- SET16_A(ep->modify_time, t); -- SET16_A(ep->modify_date, d); -- break; -- case TM_ACCESS: -- SET16_A(ep->access_time, t); -- SET16_A(ep->access_date, d); -- break; -- } --} -- --static void init_file_entry(struct file_dentry_t *ep, u32 type) --{ -- struct timestamp_t tm, *tp; -- -- exfat_set_entry_type((struct dentry_t *)ep, type); -- -- tp = tm_current(&tm); -- exfat_set_entry_time((struct dentry_t *)ep, tp, TM_CREATE); -- exfat_set_entry_time((struct dentry_t *)ep, tp, TM_MODIFY); -- exfat_set_entry_time((struct dentry_t *)ep, tp, TM_ACCESS); -- ep->create_time_ms = 0; -- ep->modify_time_ms = 0; -- ep->access_time_ms = 0; --} -- --static void init_strm_entry(struct strm_dentry_t *ep, u8 flags, u32 start_clu, u64 size) --{ -- exfat_set_entry_type((struct dentry_t *)ep, TYPE_STREAM); -- ep->flags = flags; -- SET32_A(ep->start_clu, start_clu); -- SET64_A(ep->valid_size, size); -- SET64_A(ep->size, size); --} -- --static void init_name_entry(struct name_dentry_t *ep, u16 *uniname) --{ -- int i; -- -- exfat_set_entry_type((struct dentry_t *)ep, TYPE_EXTEND); -- ep->flags = 0x0; -- -- for (i = 0; i < 30; i++, i++) { -- SET16_A(ep->unicode_0_14 + i, *uniname); -- if (*uniname == 0x0) -- break; -- uniname++; -- } --} -- --static s32 exfat_init_dir_entry(struct super_block *sb, struct chain_t *p_dir, -- s32 entry, u32 type, u32 start_clu, u64 size) --{ -- sector_t sector; -- u8 flags; -- struct file_dentry_t *file_ep; -- struct strm_dentry_t *strm_ep; -- -- flags = (type == TYPE_FILE) ? 0x01 : 0x03; -- -- /* we cannot use get_entry_set_in_dir here because file ep is not initialized yet */ -- file_ep = (struct file_dentry_t *)get_entry_in_dir(sb, p_dir, entry, -- §or); -- if (!file_ep) -- return -ENOENT; -- -- strm_ep = (struct strm_dentry_t *)get_entry_in_dir(sb, p_dir, entry + 1, -- §or); -- if (!strm_ep) -- return -ENOENT; -- -- init_file_entry(file_ep, type); -- exfat_buf_modify(sb, sector); -- -- init_strm_entry(strm_ep, flags, start_clu, size); -- exfat_buf_modify(sb, sector); -- -- return 0; --} -- --static s32 exfat_init_ext_entry(struct super_block *sb, struct chain_t *p_dir, -- s32 entry, s32 num_entries, -- struct uni_name_t *p_uniname, -- struct dos_name_t *p_dosname) --{ -- int i; -- sector_t sector; -- u16 *uniname = p_uniname->name; -- struct file_dentry_t *file_ep; -- struct strm_dentry_t *strm_ep; -- struct name_dentry_t *name_ep; -- -- file_ep = (struct file_dentry_t *)get_entry_in_dir(sb, p_dir, entry, -- §or); -- if (!file_ep) -- return -ENOENT; -- -- file_ep->num_ext = (u8)(num_entries - 1); -- exfat_buf_modify(sb, sector); -- -- strm_ep = (struct strm_dentry_t *)get_entry_in_dir(sb, p_dir, entry + 1, -- §or); -- if (!strm_ep) -- return -ENOENT; -- -- strm_ep->name_len = p_uniname->name_len; -- SET16_A(strm_ep->name_hash, p_uniname->name_hash); -- exfat_buf_modify(sb, sector); -- -- for (i = 2; i < num_entries; i++) { -- name_ep = (struct name_dentry_t *)get_entry_in_dir(sb, p_dir, -- entry + i, -- §or); -- if (!name_ep) -- return -ENOENT; -- -- init_name_entry(name_ep, uniname); -- exfat_buf_modify(sb, sector); -- uniname += 15; -- } -- -- update_dir_checksum(sb, p_dir, entry); -- -- return 0; --} -- --void exfat_delete_dir_entry(struct super_block *sb, struct chain_t *p_dir, -- s32 entry, s32 order, s32 num_entries) --{ -- int i; -- sector_t sector; -- struct dentry_t *ep; -- -- for (i = order; i < num_entries; i++) { -- ep = get_entry_in_dir(sb, p_dir, entry + i, §or); -- if (!ep) -- return; -- -- exfat_set_entry_type(ep, TYPE_DELETED); -- exfat_buf_modify(sb, sector); -- } --} -- --void update_dir_checksum(struct super_block *sb, struct chain_t *p_dir, -- s32 entry) --{ -- int i, num_entries; -- sector_t sector; -- u16 chksum; -- struct file_dentry_t *file_ep; -- struct dentry_t *ep; -- -- file_ep = (struct file_dentry_t *)get_entry_in_dir(sb, p_dir, entry, -- §or); -- if (!file_ep) -- return; -- -- exfat_buf_lock(sb, sector); -- -- num_entries = (s32)file_ep->num_ext + 1; -- chksum = calc_checksum_2byte((void *)file_ep, DENTRY_SIZE, 0, -- CS_DIR_ENTRY); -- -- for (i = 1; i < num_entries; i++) { -- ep = get_entry_in_dir(sb, p_dir, entry + i, NULL); -- if (!ep) { -- exfat_buf_unlock(sb, sector); -- return; -- } -- -- chksum = calc_checksum_2byte((void *)ep, DENTRY_SIZE, chksum, -- CS_DEFAULT); -- } -- -- SET16_A(file_ep->checksum, chksum); -- exfat_buf_modify(sb, sector); -- exfat_buf_unlock(sb, sector); --} -- --static s32 __write_partial_entries_in_entry_set(struct super_block *sb, -- struct entry_set_cache_t *es, -- sector_t sec, s32 off, u32 count) --{ -- s32 num_entries, buf_off = (off - es->offset); -- u32 remaining_byte_in_sector, copy_entries; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- u32 clu; -- u8 *buf, *esbuf = (u8 *)&es->__buf; -- -- pr_debug("%s entered es %p sec %llu off %d count %d\n", -- __func__, es, (unsigned long long)sec, off, count); -- num_entries = count; -- -- while (num_entries) { -- /* white per sector base */ -- remaining_byte_in_sector = (1 << p_bd->sector_size_bits) - off; -- copy_entries = min_t(s32, -- remaining_byte_in_sector >> DENTRY_SIZE_BITS, -- num_entries); -- buf = exfat_buf_getblk(sb, sec); -- if (!buf) -- goto err_out; -- pr_debug("es->buf %p buf_off %u\n", esbuf, buf_off); -- pr_debug("copying %d entries from %p to sector %llu\n", -- copy_entries, (esbuf + buf_off), -- (unsigned long long)sec); -- memcpy(buf + off, esbuf + buf_off, -- copy_entries << DENTRY_SIZE_BITS); -- exfat_buf_modify(sb, sec); -- num_entries -= copy_entries; -- -- if (num_entries) { -- /* get next sector */ -- if (IS_LAST_SECTOR_IN_CLUSTER(sec)) { -- clu = GET_CLUSTER_FROM_SECTOR(sec); -- if (es->alloc_flag == 0x03) { -- clu++; -- } else { -- if (exfat_fat_read(sb, clu, &clu) == -1) -- goto err_out; -- } -- sec = START_SECTOR(clu); -- } else { -- sec++; -- } -- off = 0; -- buf_off += copy_entries << DENTRY_SIZE_BITS; -- } -- } -- -- pr_debug("%s exited successfully\n", __func__); -- return 0; --err_out: -- pr_debug("%s failed\n", __func__); -- return -EINVAL; --} -- --/* write back all entries in entry set */ --static s32 write_whole_entry_set(struct super_block *sb, struct entry_set_cache_t *es) --{ -- return __write_partial_entries_in_entry_set(sb, es, es->sector, -- es->offset, -- es->num_entries); --} -- --void update_dir_checksum_with_entry_set(struct super_block *sb, -- struct entry_set_cache_t *es) --{ -- struct dentry_t *ep; -- u16 chksum = 0; -- s32 chksum_type = CS_DIR_ENTRY, i; -- -- ep = (struct dentry_t *)&es->__buf; -- for (i = 0; i < es->num_entries; i++) { -- pr_debug("%s ep %p\n", __func__, ep); -- chksum = calc_checksum_2byte((void *)ep, DENTRY_SIZE, chksum, -- chksum_type); -- ep++; -- chksum_type = CS_DEFAULT; -- } -- -- ep = (struct dentry_t *)&es->__buf; -- SET16_A(((struct file_dentry_t *)ep)->checksum, chksum); -- write_whole_entry_set(sb, es); --} -- --static s32 _walk_fat_chain(struct super_block *sb, struct chain_t *p_dir, -- s32 byte_offset, u32 *clu) --{ -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- s32 clu_offset; -- u32 cur_clu; -- -- clu_offset = byte_offset >> p_fs->cluster_size_bits; -- cur_clu = p_dir->dir; -- -- if (p_dir->flags == 0x03) { -- cur_clu += clu_offset; -- } else { -- while (clu_offset > 0) { -- if (exfat_fat_read(sb, cur_clu, &cur_clu) == -1) -- return -EIO; -- clu_offset--; -- } -- } -- -- if (clu) -- *clu = cur_clu; -- return 0; --} -- --static s32 find_location(struct super_block *sb, struct chain_t *p_dir, s32 entry, -- sector_t *sector, s32 *offset) --{ -- s32 off, ret; -- u32 clu = 0; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- off = entry << DENTRY_SIZE_BITS; -- -- if (p_dir->dir == CLUSTER_32(0)) { /* FAT16 root_dir */ -- *offset = off & p_bd->sector_size_mask; -- *sector = off >> p_bd->sector_size_bits; -- *sector += p_fs->root_start_sector; -- } else { -- ret = _walk_fat_chain(sb, p_dir, off, &clu); -- if (ret != 0) -- return ret; -- -- /* byte offset in cluster */ -- off &= p_fs->cluster_size - 1; -- -- /* byte offset in sector */ -- *offset = off & p_bd->sector_size_mask; -- -- /* sector offset in cluster */ -- *sector = off >> p_bd->sector_size_bits; -- *sector += START_SECTOR(clu); -- } -- return 0; --} -- --struct dentry_t *get_entry_in_dir(struct super_block *sb, struct chain_t *p_dir, -- s32 entry, sector_t *sector) --{ -- s32 off; -- sector_t sec; -- u8 *buf; -- -- if (find_location(sb, p_dir, entry, &sec, &off) != 0) -- return NULL; -- -- buf = exfat_buf_getblk(sb, sec); -- -- if (!buf) -- return NULL; -- -- if (sector) -- *sector = sec; -- return (struct dentry_t *)(buf + off); --} -- --/* returns a set of dentries for a file or dir. -- * Note that this is a copy (dump) of dentries so that user should call write_entry_set() -- * to apply changes made in this entry set to the real device. -- * in: -- * sb+p_dir+entry: indicates a file/dir -- * type: specifies how many dentries should be included. -- * out: -- * file_ep: will point the first dentry(= file dentry) on success -- * return: -- * pointer of entry set on success, -- * NULL on failure. -- */ -- --#define ES_MODE_STARTED 0 --#define ES_MODE_GET_FILE_ENTRY 1 --#define ES_MODE_GET_STRM_ENTRY 2 --#define ES_MODE_GET_NAME_ENTRY 3 --#define ES_MODE_GET_CRITICAL_SEC_ENTRY 4 --struct entry_set_cache_t *get_entry_set_in_dir(struct super_block *sb, -- struct chain_t *p_dir, s32 entry, -- u32 type, -- struct dentry_t **file_ep) --{ -- s32 off, ret, byte_offset; -- u32 clu = 0; -- sector_t sec; -- u32 entry_type; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- struct entry_set_cache_t *es = NULL; -- struct dentry_t *ep, *pos; -- u8 *buf; -- u8 num_entries; -- s32 mode = ES_MODE_STARTED; -- size_t bufsize; -- -- pr_debug("%s entered p_dir dir %u flags %x size %d\n", -- __func__, p_dir->dir, p_dir->flags, p_dir->size); -- -- byte_offset = entry << DENTRY_SIZE_BITS; -- ret = _walk_fat_chain(sb, p_dir, byte_offset, &clu); -- if (ret != 0) -- return NULL; -- -- /* byte offset in cluster */ -- byte_offset &= p_fs->cluster_size - 1; -- -- /* byte offset in sector */ -- off = byte_offset & p_bd->sector_size_mask; -- -- /* sector offset in cluster */ -- sec = byte_offset >> p_bd->sector_size_bits; -- sec += START_SECTOR(clu); -- -- buf = exfat_buf_getblk(sb, sec); -- if (!buf) -- goto err_out; -- -- ep = (struct dentry_t *)(buf + off); -- entry_type = exfat_get_entry_type(ep); -- -- if ((entry_type != TYPE_FILE) && (entry_type != TYPE_DIR)) -- goto err_out; -- -- if (type == ES_ALL_ENTRIES) -- num_entries = ((struct file_dentry_t *)ep)->num_ext + 1; -- else -- num_entries = type; -- -- bufsize = offsetof(struct entry_set_cache_t, __buf) + (num_entries) * -- sizeof(struct dentry_t); -- pr_debug("%s: trying to kmalloc %zx bytes for %d entries\n", __func__, -- bufsize, num_entries); -- es = kmalloc(bufsize, GFP_KERNEL); -- if (!es) -- goto err_out; -- -- es->num_entries = num_entries; -- es->sector = sec; -- es->offset = off; -- es->alloc_flag = p_dir->flags; -- -- pos = (struct dentry_t *)&es->__buf; -- -- while (num_entries) { -- /* -- * instead of copying whole sector, we will check every entry. -- * this will provide minimum stablity and consistency. -- */ -- entry_type = exfat_get_entry_type(ep); -- -- if ((entry_type == TYPE_UNUSED) || (entry_type == TYPE_DELETED)) -- goto err_out; -- -- switch (mode) { -- case ES_MODE_STARTED: -- if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR)) -- mode = ES_MODE_GET_FILE_ENTRY; -- else -- goto err_out; -- break; -- case ES_MODE_GET_FILE_ENTRY: -- if (entry_type == TYPE_STREAM) -- mode = ES_MODE_GET_STRM_ENTRY; -- else -- goto err_out; -- break; -- case ES_MODE_GET_STRM_ENTRY: -- if (entry_type == TYPE_EXTEND) -- mode = ES_MODE_GET_NAME_ENTRY; -- else -- goto err_out; -- break; -- case ES_MODE_GET_NAME_ENTRY: -- if (entry_type == TYPE_EXTEND) -- break; -- else if (entry_type == TYPE_STREAM) -- goto err_out; -- else if (entry_type & TYPE_CRITICAL_SEC) -- mode = ES_MODE_GET_CRITICAL_SEC_ENTRY; -- else -- goto err_out; -- break; -- case ES_MODE_GET_CRITICAL_SEC_ENTRY: -- if ((entry_type == TYPE_EXTEND) || -- (entry_type == TYPE_STREAM)) -- goto err_out; -- else if ((entry_type & TYPE_CRITICAL_SEC) != -- TYPE_CRITICAL_SEC) -- goto err_out; -- break; -- } -- -- memcpy(pos, ep, sizeof(struct dentry_t)); -- -- if (--num_entries == 0) -- break; -- -- if (((off + DENTRY_SIZE) & p_bd->sector_size_mask) < -- (off & p_bd->sector_size_mask)) { -- /* get the next sector */ -- if (IS_LAST_SECTOR_IN_CLUSTER(sec)) { -- if (es->alloc_flag == 0x03) { -- clu++; -- } else { -- if (exfat_fat_read(sb, clu, &clu) == -1) -- goto err_out; -- } -- sec = START_SECTOR(clu); -- } else { -- sec++; -- } -- buf = exfat_buf_getblk(sb, sec); -- if (!buf) -- goto err_out; -- off = 0; -- ep = (struct dentry_t *)(buf); -- } else { -- ep++; -- off += DENTRY_SIZE; -- } -- pos++; -- } -- -- if (file_ep) -- *file_ep = (struct dentry_t *)&es->__buf; -- -- pr_debug("%s exiting es %p sec %llu offset %d flags %d, num_entries %u buf ptr %p\n", -- __func__, es, (unsigned long long)es->sector, es->offset, -- es->alloc_flag, es->num_entries, &es->__buf); -- return es; --err_out: -- pr_debug("%s exited NULL (es %p)\n", __func__, es); -- kfree(es); -- return NULL; --} -- --void release_entry_set(struct entry_set_cache_t *es) --{ -- pr_debug("%s es=%p\n", __func__, es); -- kfree(es); --} -- --/* search EMPTY CONTINUOUS "num_entries" entries */ --static s32 search_deleted_or_unused_entry(struct super_block *sb, -- struct chain_t *p_dir, -- s32 num_entries) --{ -- int i, dentry, num_empty = 0; -- s32 dentries_per_clu; -- u32 type; -- struct chain_t clu; -- struct dentry_t *ep; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ -- dentries_per_clu = p_fs->dentries_in_root; -- else -- dentries_per_clu = p_fs->dentries_per_clu; -- -- if (p_fs->hint_uentry.dir == p_dir->dir) { -- if (p_fs->hint_uentry.entry == -1) -- return -1; -- -- clu.dir = p_fs->hint_uentry.clu.dir; -- clu.size = p_fs->hint_uentry.clu.size; -- clu.flags = p_fs->hint_uentry.clu.flags; -- -- dentry = p_fs->hint_uentry.entry; -- } else { -- p_fs->hint_uentry.entry = -1; -- -- clu.dir = p_dir->dir; -- clu.size = p_dir->size; -- clu.flags = p_dir->flags; -- -- dentry = 0; -- } -- -- while (clu.dir != CLUSTER_32(~0)) { -- if (p_fs->dev_ejected) -- break; -- -- if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ -- i = dentry % dentries_per_clu; -- else -- i = dentry & (dentries_per_clu - 1); -- -- for (; i < dentries_per_clu; i++, dentry++) { -- ep = get_entry_in_dir(sb, &clu, i, NULL); -- if (!ep) -- return -1; -- -- type = exfat_get_entry_type(ep); -- -- if (type == TYPE_UNUSED) { -- num_empty++; -- if (p_fs->hint_uentry.entry == -1) { -- p_fs->hint_uentry.dir = p_dir->dir; -- p_fs->hint_uentry.entry = dentry; -- -- p_fs->hint_uentry.clu.dir = clu.dir; -- p_fs->hint_uentry.clu.size = clu.size; -- p_fs->hint_uentry.clu.flags = clu.flags; -- } -- } else if (type == TYPE_DELETED) { -- num_empty++; -- } else { -- num_empty = 0; -- } -- -- if (num_empty >= num_entries) { -- p_fs->hint_uentry.dir = CLUSTER_32(~0); -- p_fs->hint_uentry.entry = -1; -- -- if (p_fs->vol_type == EXFAT) -- return dentry - (num_entries - 1); -- else -- return dentry; -- } -- } -- -- if (p_dir->dir == CLUSTER_32(0)) -- break; /* FAT16 root_dir */ -- -- if (clu.flags == 0x03) { -- if ((--clu.size) > 0) -- clu.dir++; -- else -- clu.dir = CLUSTER_32(~0); -- } else { -- if (exfat_fat_read(sb, clu.dir, &clu.dir) != 0) -- return -1; -- } -- } -- -- return -1; --} -- --static s32 find_empty_entry(struct inode *inode, struct chain_t *p_dir, s32 num_entries) --{ -- s32 ret, dentry; -- u32 last_clu; -- sector_t sector; -- u64 size = 0; -- struct chain_t clu; -- struct dentry_t *ep = NULL; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct file_id_t *fid = &(EXFAT_I(inode)->fid); -- -- if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ -- return search_deleted_or_unused_entry(sb, p_dir, num_entries); -- -- while ((dentry = search_deleted_or_unused_entry(sb, p_dir, num_entries)) < 0) { -- if (p_fs->dev_ejected) -- break; -- -- if (p_dir->dir != p_fs->root_dir) -- size = i_size_read(inode); -- -- last_clu = find_last_cluster(sb, p_dir); -- clu.dir = last_clu + 1; -- clu.size = 0; -- clu.flags = p_dir->flags; -- -- /* (1) allocate a cluster */ -- ret = exfat_alloc_cluster(sb, 1, &clu); -- if (ret < 1) -- return -EIO; -- -- if (clear_cluster(sb, clu.dir) != 0) -- return -EIO; -- -- /* (2) append to the FAT chain */ -- if (clu.flags != p_dir->flags) { -- exfat_chain_cont_cluster(sb, p_dir->dir, p_dir->size); -- p_dir->flags = 0x01; -- p_fs->hint_uentry.clu.flags = 0x01; -- } -- if (clu.flags == 0x01) -- if (exfat_fat_write(sb, last_clu, clu.dir) < 0) -- return -EIO; -- -- if (p_fs->hint_uentry.entry == -1) { -- p_fs->hint_uentry.dir = p_dir->dir; -- p_fs->hint_uentry.entry = p_dir->size << (p_fs->cluster_size_bits - DENTRY_SIZE_BITS); -- -- p_fs->hint_uentry.clu.dir = clu.dir; -- p_fs->hint_uentry.clu.size = 0; -- p_fs->hint_uentry.clu.flags = clu.flags; -- } -- p_fs->hint_uentry.clu.size++; -- p_dir->size++; -- -- /* (3) update the directory entry */ -- if (p_dir->dir != p_fs->root_dir) { -- size += p_fs->cluster_size; -- -- ep = get_entry_in_dir(sb, &fid->dir, -- fid->entry + 1, §or); -- if (!ep) -- return -ENOENT; -- exfat_set_entry_size(ep, size); -- exfat_set_entry_flag(ep, p_dir->flags); -- exfat_buf_modify(sb, sector); -- -- update_dir_checksum(sb, &fid->dir, -- fid->entry); -- } -- -- i_size_write(inode, i_size_read(inode) + p_fs->cluster_size); -- EXFAT_I(inode)->mmu_private += p_fs->cluster_size; -- EXFAT_I(inode)->fid.size += p_fs->cluster_size; -- EXFAT_I(inode)->fid.flags = p_dir->flags; -- inode->i_blocks += 1 << (p_fs->cluster_size_bits - 9); -- } -- -- return dentry; --} -- --static s32 extract_uni_name_from_name_entry(struct name_dentry_t *ep, u16 *uniname, -- s32 order) --{ -- int i, len = 0; -- -- for (i = 0; i < 30; i += 2) { -- *uniname = GET16_A(ep->unicode_0_14 + i); -- if (*uniname == 0x0) -- return len; -- uniname++; -- len++; -- } -- -- *uniname = 0x0; -- return len; --} -- --/* return values of exfat_find_dir_entry() -- * >= 0 : return dir entiry position with the name in dir -- * -1 : (root dir, ".") it is the root dir itself -- * -2 : entry with the name does not exist -- */ --s32 exfat_find_dir_entry(struct super_block *sb, struct chain_t *p_dir, -- struct uni_name_t *p_uniname, s32 num_entries, -- struct dos_name_t *p_dosname, u32 type) --{ -- int i = 0, dentry = 0, num_ext_entries = 0, len, step; -- s32 order = 0; -- bool is_feasible_entry = false; -- s32 dentries_per_clu, num_empty = 0; -- u32 entry_type; -- u16 entry_uniname[16], *uniname = NULL, unichar; -- struct chain_t clu; -- struct dentry_t *ep; -- struct file_dentry_t *file_ep; -- struct strm_dentry_t *strm_ep; -- struct name_dentry_t *name_ep; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- if (p_dir->dir == p_fs->root_dir) { -- if ((!nls_uniname_cmp(sb, p_uniname->name, -- (u16 *)UNI_CUR_DIR_NAME)) || -- (!nls_uniname_cmp(sb, p_uniname->name, -- (u16 *)UNI_PAR_DIR_NAME))) -- return -1; // special case, root directory itself -- } -- -- if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ -- dentries_per_clu = p_fs->dentries_in_root; -- else -- dentries_per_clu = p_fs->dentries_per_clu; -- -- clu.dir = p_dir->dir; -- clu.size = p_dir->size; -- clu.flags = p_dir->flags; -- -- p_fs->hint_uentry.dir = p_dir->dir; -- p_fs->hint_uentry.entry = -1; -- -- while (clu.dir != CLUSTER_32(~0)) { -- if (p_fs->dev_ejected) -- break; -- -- while (i < dentries_per_clu) { -- ep = get_entry_in_dir(sb, &clu, i, NULL); -- if (!ep) -- return -2; -- -- entry_type = exfat_get_entry_type(ep); -- step = 1; -- -- if ((entry_type == TYPE_UNUSED) || (entry_type == TYPE_DELETED)) { -- is_feasible_entry = false; -- -- if (p_fs->hint_uentry.entry == -1) { -- num_empty++; -- -- if (num_empty == 1) { -- p_fs->hint_uentry.clu.dir = clu.dir; -- p_fs->hint_uentry.clu.size = clu.size; -- p_fs->hint_uentry.clu.flags = clu.flags; -- } -- if ((num_empty >= num_entries) || (entry_type == TYPE_UNUSED)) -- p_fs->hint_uentry.entry = dentry - (num_empty - 1); -- } -- -- if (entry_type == TYPE_UNUSED) -- return -2; -- } else { -- num_empty = 0; -- -- if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR)) { -- file_ep = (struct file_dentry_t *)ep; -- if ((type == TYPE_ALL) || (type == entry_type)) { -- num_ext_entries = file_ep->num_ext; -- is_feasible_entry = true; -- } else { -- is_feasible_entry = false; -- step = file_ep->num_ext + 1; -- } -- } else if (entry_type == TYPE_STREAM) { -- if (is_feasible_entry) { -- strm_ep = (struct strm_dentry_t *)ep; -- if (p_uniname->name_hash == GET16_A(strm_ep->name_hash) && -- p_uniname->name_len == strm_ep->name_len) { -- order = 1; -- } else { -- is_feasible_entry = false; -- step = num_ext_entries; -- } -- } -- } else if (entry_type == TYPE_EXTEND) { -- if (is_feasible_entry) { -- name_ep = (struct name_dentry_t *)ep; -- -- if ((++order) == 2) -- uniname = p_uniname->name; -- else -- uniname += 15; -- -- len = extract_uni_name_from_name_entry(name_ep, -- entry_uniname, order); -- -- unichar = *(uniname + len); -- *(uniname + len) = 0x0; -- -- if (nls_uniname_cmp(sb, uniname, entry_uniname)) { -- is_feasible_entry = false; -- step = num_ext_entries - order + 1; -- } else if (order == num_ext_entries) { -- p_fs->hint_uentry.dir = CLUSTER_32(~0); -- p_fs->hint_uentry.entry = -1; -- return dentry - (num_ext_entries); -- } -- -- *(uniname + len) = unichar; -- } -- } else { -- is_feasible_entry = false; -- } -- } -- -- i += step; -- dentry += step; -- } -- -- i -= dentries_per_clu; -- -- if (p_dir->dir == CLUSTER_32(0)) -- break; /* FAT16 root_dir */ -- -- if (clu.flags == 0x03) { -- if ((--clu.size) > 0) -- clu.dir++; -- else -- clu.dir = CLUSTER_32(~0); -- } else { -- if (exfat_fat_read(sb, clu.dir, &clu.dir) != 0) -- return -2; -- } -- } -- -- return -2; --} -- --s32 exfat_count_ext_entries(struct super_block *sb, struct chain_t *p_dir, -- s32 entry, struct dentry_t *p_entry) --{ -- int i, count = 0; -- u32 type; -- struct file_dentry_t *file_ep = (struct file_dentry_t *)p_entry; -- struct dentry_t *ext_ep; -- -- for (i = 0, entry++; i < file_ep->num_ext; i++, entry++) { -- ext_ep = get_entry_in_dir(sb, p_dir, entry, NULL); -- if (!ext_ep) -- return -1; -- -- type = exfat_get_entry_type(ext_ep); -- if ((type == TYPE_EXTEND) || (type == TYPE_STREAM)) -- count++; -- else -- return count; -- } -- -- return count; --} -- --s32 count_dos_name_entries(struct super_block *sb, struct chain_t *p_dir, -- u32 type) --{ -- int i, count = 0; -- s32 dentries_per_clu; -- u32 entry_type; -- struct chain_t clu; -- struct dentry_t *ep; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ -- dentries_per_clu = p_fs->dentries_in_root; -- else -- dentries_per_clu = p_fs->dentries_per_clu; -- -- clu.dir = p_dir->dir; -- clu.size = p_dir->size; -- clu.flags = p_dir->flags; -- -- while (clu.dir != CLUSTER_32(~0)) { -- if (p_fs->dev_ejected) -- break; -- -- for (i = 0; i < dentries_per_clu; i++) { -- ep = get_entry_in_dir(sb, &clu, i, NULL); -- if (!ep) -- return -ENOENT; -- -- entry_type = exfat_get_entry_type(ep); -- -- if (entry_type == TYPE_UNUSED) -- return count; -- if (!(type & TYPE_CRITICAL_PRI) && -- !(type & TYPE_BENIGN_PRI)) -- continue; -- -- if ((type == TYPE_ALL) || (type == entry_type)) -- count++; -- } -- -- if (p_dir->dir == CLUSTER_32(0)) -- break; /* FAT16 root_dir */ -- -- if (clu.flags == 0x03) { -- if ((--clu.size) > 0) -- clu.dir++; -- else -- clu.dir = CLUSTER_32(~0); -- } else { -- if (exfat_fat_read(sb, clu.dir, &clu.dir) != 0) -- return -EIO; -- } -- } -- -- return count; --} -- --bool is_dir_empty(struct super_block *sb, struct chain_t *p_dir) --{ -- int i, count = 0; -- s32 dentries_per_clu; -- u32 type; -- struct chain_t clu; -- struct dentry_t *ep; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ -- dentries_per_clu = p_fs->dentries_in_root; -- else -- dentries_per_clu = p_fs->dentries_per_clu; -- -- clu.dir = p_dir->dir; -- clu.size = p_dir->size; -- clu.flags = p_dir->flags; -- -- while (clu.dir != CLUSTER_32(~0)) { -- if (p_fs->dev_ejected) -- break; -- -- for (i = 0; i < dentries_per_clu; i++) { -- ep = get_entry_in_dir(sb, &clu, i, NULL); -- if (!ep) -- break; -- -- type = exfat_get_entry_type(ep); -- -- if (type == TYPE_UNUSED) -- return true; -- if ((type != TYPE_FILE) && (type != TYPE_DIR)) -- continue; -- -- if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ -- return false; -- -- if (p_fs->vol_type == EXFAT) -- return false; -- if ((p_dir->dir == p_fs->root_dir) || ((++count) > 2)) -- return false; -- } -- -- if (p_dir->dir == CLUSTER_32(0)) -- break; /* FAT16 root_dir */ -- -- if (clu.flags == 0x03) { -- if ((--clu.size) > 0) -- clu.dir++; -- else -- clu.dir = CLUSTER_32(~0); -- } -- if (exfat_fat_read(sb, clu.dir, &clu.dir) != 0) -- break; -- } -- -- return true; --} -- --/* -- * Name Conversion Functions -- */ -- --/* input : dir, uni_name -- * output : num_of_entry, dos_name(format : aaaaaa~1.bbb) -- */ --s32 get_num_entries_and_dos_name(struct super_block *sb, struct chain_t *p_dir, -- struct uni_name_t *p_uniname, s32 *entries, -- struct dos_name_t *p_dosname) --{ -- s32 num_entries; -- -- num_entries = exfat_calc_num_entries(p_uniname); -- if (num_entries == 0) -- return -EINVAL; -- -- *entries = num_entries; -- -- return 0; --} -- --void exfat_get_uni_name_from_ext_entry(struct super_block *sb, -- struct chain_t *p_dir, s32 entry, -- u16 *uniname) --{ -- int i; -- struct dentry_t *ep; -- struct entry_set_cache_t *es; -- -- es = get_entry_set_in_dir(sb, p_dir, entry, ES_ALL_ENTRIES, &ep); -- if (!es || es->num_entries < 3) { -- if (es) -- release_entry_set(es); -- return; -- } -- -- ep += 2; -- -- /* -- * First entry : file entry -- * Second entry : stream-extension entry -- * Third entry : first file-name entry -- * So, the index of first file-name dentry should start from 2. -- */ -- for (i = 2; i < es->num_entries; i++, ep++) { -- if (exfat_get_entry_type(ep) == TYPE_EXTEND) -- extract_uni_name_from_name_entry((struct name_dentry_t *) -- ep, uniname, i); -- else -- goto out; -- uniname += 15; -- } -- --out: -- release_entry_set(es); --} -- --s32 exfat_calc_num_entries(struct uni_name_t *p_uniname) --{ -- s32 len; -- -- len = p_uniname->name_len; -- if (len == 0) -- return 0; -- -- /* 1 file entry + 1 stream entry + name entries */ -- return (len - 1) / 15 + 3; --} -- --u16 calc_checksum_2byte(void *data, s32 len, u16 chksum, s32 type) --{ -- int i; -- u8 *c = (u8 *)data; -- -- switch (type) { -- case CS_DIR_ENTRY: -- for (i = 0; i < len; i++, c++) { -- if ((i == 2) || (i == 3)) -- continue; -- chksum = (((chksum & 1) << 15) | -- ((chksum & 0xFFFE) >> 1)) + (u16)*c; -- } -- break; -- default -- : -- for (i = 0; i < len; i++, c++) -- chksum = (((chksum & 1) << 15) | -- ((chksum & 0xFFFE) >> 1)) + (u16)*c; -- } -- -- return chksum; --} -- --/* -- * Name Resolution Functions -- */ -- --/* return values of resolve_path() -- * > 0 : return the length of the path -- * < 0 : return error -- */ --s32 resolve_path(struct inode *inode, char *path, struct chain_t *p_dir, -- struct uni_name_t *p_uniname) --{ -- bool lossy = false; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct file_id_t *fid = &(EXFAT_I(inode)->fid); -- -- if (strscpy(name_buf, path, sizeof(name_buf)) < 0) -- return -EINVAL; -- -- nls_cstring_to_uniname(sb, p_uniname, name_buf, &lossy); -- if (lossy) -- return -EINVAL; -- -- fid->size = i_size_read(inode); -- -- p_dir->dir = fid->start_clu; -- p_dir->size = (s32)(fid->size >> p_fs->cluster_size_bits); -- p_dir->flags = fid->flags; -- -- return 0; --} -- --s32 exfat_mount(struct super_block *sb, struct pbr_sector_t *p_pbr) --{ -- struct bpbex_t *p_bpb = (struct bpbex_t *)p_pbr->bpb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- if (p_bpb->num_fats == 0) -- return -EFSCORRUPTED; -- -- p_fs->sectors_per_clu = 1 << p_bpb->sectors_per_clu_bits; -- p_fs->sectors_per_clu_bits = p_bpb->sectors_per_clu_bits; -- p_fs->cluster_size_bits = p_fs->sectors_per_clu_bits + -- p_bd->sector_size_bits; -- p_fs->cluster_size = 1 << p_fs->cluster_size_bits; -- -- p_fs->num_FAT_sectors = GET32(p_bpb->fat_length); -- -- p_fs->FAT1_start_sector = p_fs->PBR_sector + GET32(p_bpb->fat_offset); -- if (p_bpb->num_fats == 1) -- p_fs->FAT2_start_sector = p_fs->FAT1_start_sector; -- else -- p_fs->FAT2_start_sector = p_fs->FAT1_start_sector + -- p_fs->num_FAT_sectors; -- -- p_fs->root_start_sector = p_fs->PBR_sector + GET32(p_bpb->clu_offset); -- p_fs->data_start_sector = p_fs->root_start_sector; -- -- p_fs->num_sectors = GET64(p_bpb->vol_length); -- p_fs->num_clusters = GET32(p_bpb->clu_count) + 2; -- /* because the cluster index starts with 2 */ -- -- p_fs->vol_type = EXFAT; -- p_fs->vol_id = GET32(p_bpb->vol_serial); -- -- p_fs->root_dir = GET32(p_bpb->root_cluster); -- p_fs->dentries_in_root = 0; -- p_fs->dentries_per_clu = 1 << (p_fs->cluster_size_bits - -- DENTRY_SIZE_BITS); -- -- p_fs->vol_flag = (u32)GET16(p_bpb->vol_flags); -- p_fs->clu_srch_ptr = 2; -- p_fs->used_clusters = UINT_MAX; -- -- return 0; --} -- --s32 create_dir(struct inode *inode, struct chain_t *p_dir, -- struct uni_name_t *p_uniname, struct file_id_t *fid) --{ -- s32 ret, dentry, num_entries; -- u64 size; -- struct chain_t clu; -- struct dos_name_t dos_name; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- ret = get_num_entries_and_dos_name(sb, p_dir, p_uniname, &num_entries, -- &dos_name); -- if (ret) -- return ret; -- -- /* find_empty_entry must be called before alloc_cluster */ -- dentry = find_empty_entry(inode, p_dir, num_entries); -- if (dentry < 0) -- return -ENOSPC; -- -- clu.dir = CLUSTER_32(~0); -- clu.size = 0; -- clu.flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; -- -- /* (1) allocate a cluster */ -- ret = exfat_alloc_cluster(sb, 1, &clu); -- if (ret < 0) -- return ret; -- else if (ret == 0) -- return -ENOSPC; -- -- ret = clear_cluster(sb, clu.dir); -- if (ret != 0) -- return ret; -- -- size = p_fs->cluster_size; -- -- /* (2) update the directory entry */ -- /* make sub-dir entry in parent directory */ -- ret = exfat_init_dir_entry(sb, p_dir, dentry, TYPE_DIR, clu.dir, -- size); -- if (ret != 0) -- return ret; -- -- ret = exfat_init_ext_entry(sb, p_dir, dentry, num_entries, p_uniname, -- &dos_name); -- if (ret != 0) -- return ret; -- -- fid->dir.dir = p_dir->dir; -- fid->dir.size = p_dir->size; -- fid->dir.flags = p_dir->flags; -- fid->entry = dentry; -- -- fid->attr = ATTR_SUBDIR; -- fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; -- fid->size = size; -- fid->start_clu = clu.dir; -- -- fid->type = TYPE_DIR; -- fid->rwoffset = 0; -- fid->hint_last_off = -1; -- -- return 0; --} -- --s32 create_file(struct inode *inode, struct chain_t *p_dir, -- struct uni_name_t *p_uniname, u8 mode, struct file_id_t *fid) --{ -- s32 ret, dentry, num_entries; -- struct dos_name_t dos_name; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- ret = get_num_entries_and_dos_name(sb, p_dir, p_uniname, &num_entries, -- &dos_name); -- if (ret) -- return ret; -- -- /* find_empty_entry must be called before alloc_cluster() */ -- dentry = find_empty_entry(inode, p_dir, num_entries); -- if (dentry < 0) -- return -ENOSPC; -- -- /* (1) update the directory entry */ -- /* fill the dos name directory entry information of the created file. -- * the first cluster is not determined yet. (0) -- */ -- ret = exfat_init_dir_entry(sb, p_dir, dentry, TYPE_FILE | mode, -- CLUSTER_32(0), 0); -- if (ret != 0) -- return ret; -- -- ret = exfat_init_ext_entry(sb, p_dir, dentry, num_entries, p_uniname, -- &dos_name); -- if (ret != 0) -- return ret; -- -- fid->dir.dir = p_dir->dir; -- fid->dir.size = p_dir->size; -- fid->dir.flags = p_dir->flags; -- fid->entry = dentry; -- -- fid->attr = ATTR_ARCHIVE | mode; -- fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; -- fid->size = 0; -- fid->start_clu = CLUSTER_32(~0); -- -- fid->type = TYPE_FILE; -- fid->rwoffset = 0; -- fid->hint_last_off = -1; -- -- return 0; --} -- --void remove_file(struct inode *inode, struct chain_t *p_dir, s32 entry) --{ -- s32 num_entries; -- sector_t sector; -- struct dentry_t *ep; -- struct super_block *sb = inode->i_sb; -- -- ep = get_entry_in_dir(sb, p_dir, entry, §or); -- if (!ep) -- return; -- -- exfat_buf_lock(sb, sector); -- -- /* exfat_buf_lock() before call count_ext_entries() */ -- num_entries = exfat_count_ext_entries(sb, p_dir, entry, ep); -- if (num_entries < 0) { -- exfat_buf_unlock(sb, sector); -- return; -- } -- num_entries++; -- -- exfat_buf_unlock(sb, sector); -- -- /* (1) update the directory entry */ -- exfat_delete_dir_entry(sb, p_dir, entry, 0, num_entries); --} -- --s32 exfat_rename_file(struct inode *inode, struct chain_t *p_dir, s32 oldentry, -- struct uni_name_t *p_uniname, struct file_id_t *fid) --{ -- s32 ret, newentry = -1, num_old_entries, num_new_entries; -- sector_t sector_old, sector_new; -- struct dos_name_t dos_name; -- struct dentry_t *epold, *epnew; -- struct super_block *sb = inode->i_sb; -- -- epold = get_entry_in_dir(sb, p_dir, oldentry, §or_old); -- if (!epold) -- return -ENOENT; -- -- exfat_buf_lock(sb, sector_old); -- -- /* exfat_buf_lock() before call count_ext_entries() */ -- num_old_entries = exfat_count_ext_entries(sb, p_dir, oldentry, -- epold); -- if (num_old_entries < 0) { -- exfat_buf_unlock(sb, sector_old); -- return -ENOENT; -- } -- num_old_entries++; -- -- ret = get_num_entries_and_dos_name(sb, p_dir, p_uniname, -- &num_new_entries, &dos_name); -- if (ret) { -- exfat_buf_unlock(sb, sector_old); -- return ret; -- } -- -- if (num_old_entries < num_new_entries) { -- newentry = find_empty_entry(inode, p_dir, num_new_entries); -- if (newentry < 0) { -- exfat_buf_unlock(sb, sector_old); -- return -ENOSPC; -- } -- -- epnew = get_entry_in_dir(sb, p_dir, newentry, §or_new); -- if (!epnew) { -- exfat_buf_unlock(sb, sector_old); -- return -ENOENT; -- } -- -- memcpy((void *)epnew, (void *)epold, DENTRY_SIZE); -- if (exfat_get_entry_type(epnew) == TYPE_FILE) { -- exfat_set_entry_attr(epnew, -- exfat_get_entry_attr(epnew) | -- ATTR_ARCHIVE); -- fid->attr |= ATTR_ARCHIVE; -- } -- exfat_buf_modify(sb, sector_new); -- exfat_buf_unlock(sb, sector_old); -- -- epold = get_entry_in_dir(sb, p_dir, oldentry + 1, -- §or_old); -- exfat_buf_lock(sb, sector_old); -- epnew = get_entry_in_dir(sb, p_dir, newentry + 1, -- §or_new); -- -- if (!epold || !epnew) { -- exfat_buf_unlock(sb, sector_old); -- return -ENOENT; -- } -- -- memcpy((void *)epnew, (void *)epold, DENTRY_SIZE); -- exfat_buf_modify(sb, sector_new); -- exfat_buf_unlock(sb, sector_old); -- -- ret = exfat_init_ext_entry(sb, p_dir, newentry, -- num_new_entries, p_uniname, -- &dos_name); -- if (ret != 0) -- return ret; -- -- exfat_delete_dir_entry(sb, p_dir, oldentry, 0, -- num_old_entries); -- fid->entry = newentry; -- } else { -- if (exfat_get_entry_type(epold) == TYPE_FILE) { -- exfat_set_entry_attr(epold, -- exfat_get_entry_attr(epold) | -- ATTR_ARCHIVE); -- fid->attr |= ATTR_ARCHIVE; -- } -- exfat_buf_modify(sb, sector_old); -- exfat_buf_unlock(sb, sector_old); -- -- ret = exfat_init_ext_entry(sb, p_dir, oldentry, -- num_new_entries, p_uniname, -- &dos_name); -- if (ret != 0) -- return ret; -- -- exfat_delete_dir_entry(sb, p_dir, oldentry, num_new_entries, -- num_old_entries); -- } -- -- return 0; --} -- --s32 move_file(struct inode *inode, struct chain_t *p_olddir, s32 oldentry, -- struct chain_t *p_newdir, struct uni_name_t *p_uniname, -- struct file_id_t *fid) --{ -- s32 ret, newentry, num_new_entries, num_old_entries; -- sector_t sector_mov, sector_new; -- struct dos_name_t dos_name; -- struct dentry_t *epmov, *epnew; -- struct super_block *sb = inode->i_sb; -- -- epmov = get_entry_in_dir(sb, p_olddir, oldentry, §or_mov); -- if (!epmov) -- return -ENOENT; -- -- /* check if the source and target directory is the same */ -- if (exfat_get_entry_type(epmov) == TYPE_DIR && -- exfat_get_entry_clu0(epmov) == p_newdir->dir) -- return -EINVAL; -- -- exfat_buf_lock(sb, sector_mov); -- -- /* exfat_buf_lock() before call count_ext_entries() */ -- num_old_entries = exfat_count_ext_entries(sb, p_olddir, oldentry, -- epmov); -- if (num_old_entries < 0) { -- exfat_buf_unlock(sb, sector_mov); -- return -ENOENT; -- } -- num_old_entries++; -- -- ret = get_num_entries_and_dos_name(sb, p_newdir, p_uniname, -- &num_new_entries, &dos_name); -- if (ret) { -- exfat_buf_unlock(sb, sector_mov); -- return ret; -- } -- -- newentry = find_empty_entry(inode, p_newdir, num_new_entries); -- if (newentry < 0) { -- exfat_buf_unlock(sb, sector_mov); -- return -ENOSPC; -- } -- -- epnew = get_entry_in_dir(sb, p_newdir, newentry, §or_new); -- if (!epnew) { -- exfat_buf_unlock(sb, sector_mov); -- return -ENOENT; -- } -- -- memcpy((void *)epnew, (void *)epmov, DENTRY_SIZE); -- if (exfat_get_entry_type(epnew) == TYPE_FILE) { -- exfat_set_entry_attr(epnew, exfat_get_entry_attr(epnew) | -- ATTR_ARCHIVE); -- fid->attr |= ATTR_ARCHIVE; -- } -- exfat_buf_modify(sb, sector_new); -- exfat_buf_unlock(sb, sector_mov); -- -- epmov = get_entry_in_dir(sb, p_olddir, oldentry + 1, -- §or_mov); -- exfat_buf_lock(sb, sector_mov); -- epnew = get_entry_in_dir(sb, p_newdir, newentry + 1, -- §or_new); -- if (!epmov || !epnew) { -- exfat_buf_unlock(sb, sector_mov); -- return -ENOENT; -- } -- -- memcpy((void *)epnew, (void *)epmov, DENTRY_SIZE); -- exfat_buf_modify(sb, sector_new); -- exfat_buf_unlock(sb, sector_mov); -- -- ret = exfat_init_ext_entry(sb, p_newdir, newentry, num_new_entries, -- p_uniname, &dos_name); -- if (ret != 0) -- return ret; -- -- exfat_delete_dir_entry(sb, p_olddir, oldentry, 0, num_old_entries); -- -- fid->dir.dir = p_newdir->dir; -- fid->dir.size = p_newdir->size; -- fid->dir.flags = p_newdir->flags; -- -- fid->entry = newentry; -- -- return 0; --} -- --/* -- * Sector Read/Write Functions -- */ -- --int sector_read(struct super_block *sb, sector_t sec, struct buffer_head **bh, -- bool read) --{ -- s32 ret = -EIO; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- if ((sec >= (p_fs->PBR_sector + p_fs->num_sectors)) && -- (p_fs->num_sectors > 0)) { -- pr_err("[EXFAT] %s: out of range error! (sec = %llu)\n", -- __func__, (unsigned long long)sec); -- fs_error(sb); -- return ret; -- } -- -- if (!p_fs->dev_ejected) { -- ret = exfat_bdev_read(sb, sec, bh, 1, read); -- if (ret != 0) -- p_fs->dev_ejected = 1; -- } -- -- return ret; --} -- --int sector_write(struct super_block *sb, sector_t sec, struct buffer_head *bh, -- bool sync) --{ -- s32 ret = -EIO; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- if (sec >= (p_fs->PBR_sector + p_fs->num_sectors) && -- (p_fs->num_sectors > 0)) { -- pr_err("[EXFAT] %s: out of range error! (sec = %llu)\n", -- __func__, (unsigned long long)sec); -- fs_error(sb); -- return ret; -- } -- -- if (!bh) { -- pr_err("[EXFAT] %s: bh is NULL!\n", __func__); -- fs_error(sb); -- return ret; -- } -- -- if (!p_fs->dev_ejected) { -- ret = exfat_bdev_write(sb, sec, bh, 1, sync); -- if (ret != 0) -- p_fs->dev_ejected = 1; -- } -- -- return ret; --} -- --int multi_sector_read(struct super_block *sb, sector_t sec, -- struct buffer_head **bh, s32 num_secs, bool read) --{ -- s32 ret = -EIO; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- if (((sec + num_secs) > (p_fs->PBR_sector + p_fs->num_sectors)) && -- (p_fs->num_sectors > 0)) { -- pr_err("[EXFAT] %s: out of range error! (sec = %llu, num_secs = %d)\n", -- __func__, (unsigned long long)sec, num_secs); -- fs_error(sb); -- return ret; -- } -- -- if (!p_fs->dev_ejected) { -- ret = exfat_bdev_read(sb, sec, bh, num_secs, read); -- if (ret != 0) -- p_fs->dev_ejected = 1; -- } -- -- return ret; --} -- --int multi_sector_write(struct super_block *sb, sector_t sec, -- struct buffer_head *bh, s32 num_secs, bool sync) --{ -- s32 ret = -EIO; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- if ((sec + num_secs) > (p_fs->PBR_sector + p_fs->num_sectors) && -- (p_fs->num_sectors > 0)) { -- pr_err("[EXFAT] %s: out of range error! (sec = %llu, num_secs = %d)\n", -- __func__, (unsigned long long)sec, num_secs); -- fs_error(sb); -- return ret; -- } -- if (!bh) { -- pr_err("[EXFAT] %s: bh is NULL!\n", __func__); -- fs_error(sb); -- return ret; -- } -- -- if (!p_fs->dev_ejected) { -- ret = exfat_bdev_write(sb, sec, bh, num_secs, sync); -- if (ret != 0) -- p_fs->dev_ejected = 1; -- } -- -- return ret; --} -diff -Nurp linux-5.6.3.orig/drivers/staging/exfat/exfat.h linux-5.6.3/drivers/staging/exfat/exfat.h ---- linux-5.6.3.orig/drivers/staging/exfat/exfat.h 2020-03-30 01:25:41.000000000 +0300 -+++ linux-5.6.3/drivers/staging/exfat/exfat.h 1970-01-01 02:00:00.000000000 +0200 -@@ -1,824 +0,0 @@ --/* SPDX-License-Identifier: GPL-2.0-or-later */ --/* -- * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -- */ -- --#ifndef _EXFAT_H --#define _EXFAT_H -- --#include --#include -- --#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG -- /* For Debugging Purpose */ -- /* IOCTL code 'f' used by -- * - file systems typically #0~0x1F -- * - embedded terminal devices #128~ -- * - exts for debugging purpose #99 -- * number 100 and 101 is available now but has possible conflicts -- */ --#define EXFAT_IOC_GET_DEBUGFLAGS _IOR('f', 100, long) --#define EXFAT_IOC_SET_DEBUGFLAGS _IOW('f', 101, long) -- --#define EXFAT_DEBUGFLAGS_INVALID_UMOUNT 0x01 --#define EXFAT_DEBUGFLAGS_ERROR_RW 0x02 --#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */ -- --#ifdef CONFIG_STAGING_EXFAT_DEBUG_MSG --#define DEBUG 1 --#else --#undef DEBUG --#endif -- --#define EFSCORRUPTED EUCLEAN /* Filesystem is corrupted */ -- --#define DENTRY_SIZE 32 /* dir entry size */ --#define DENTRY_SIZE_BITS 5 -- --/* PBR entries */ --#define PBR_SIGNATURE 0xAA55 --#define EXT_SIGNATURE 0xAA550000 --#define VOL_LABEL "NO NAME " /* size should be 11 */ --#define OEM_NAME "MSWIN4.1" /* size should be 8 */ --#define STR_FAT12 "FAT12 " /* size should be 8 */ --#define STR_FAT16 "FAT16 " /* size should be 8 */ --#define STR_FAT32 "FAT32 " /* size should be 8 */ --#define STR_EXFAT "EXFAT " /* size should be 8 */ --#define VOL_CLEAN 0x0000 --#define VOL_DIRTY 0x0002 -- --/* max number of clusters */ --#define FAT12_THRESHOLD 4087 /* 2^12 - 1 + 2 (clu 0 & 1) */ --#define FAT16_THRESHOLD 65527 /* 2^16 - 1 + 2 */ --#define FAT32_THRESHOLD 268435457 /* 2^28 - 1 + 2 */ --#define EXFAT_THRESHOLD 268435457 /* 2^28 - 1 + 2 */ -- --/* file types */ --#define TYPE_UNUSED 0x0000 --#define TYPE_DELETED 0x0001 --#define TYPE_INVALID 0x0002 --#define TYPE_CRITICAL_PRI 0x0100 --#define TYPE_BITMAP 0x0101 --#define TYPE_UPCASE 0x0102 --#define TYPE_VOLUME 0x0103 --#define TYPE_DIR 0x0104 --#define TYPE_FILE 0x011F --#define TYPE_SYMLINK 0x015F --#define TYPE_CRITICAL_SEC 0x0200 --#define TYPE_STREAM 0x0201 --#define TYPE_EXTEND 0x0202 --#define TYPE_ACL 0x0203 --#define TYPE_BENIGN_PRI 0x0400 --#define TYPE_GUID 0x0401 --#define TYPE_PADDING 0x0402 --#define TYPE_ACLTAB 0x0403 --#define TYPE_BENIGN_SEC 0x0800 --#define TYPE_ALL 0x0FFF -- --/* time modes */ --#define TM_CREATE 0 --#define TM_MODIFY 1 --#define TM_ACCESS 2 -- --/* checksum types */ --#define CS_DIR_ENTRY 0 --#define CS_PBR_SECTOR 1 --#define CS_DEFAULT 2 -- --#define CLUSTER_16(x) ((u16)(x)) --#define CLUSTER_32(x) ((u32)(x)) -- --#define START_SECTOR(x) \ -- ((((sector_t)((x) - 2)) << p_fs->sectors_per_clu_bits) + \ -- p_fs->data_start_sector) -- --#define IS_LAST_SECTOR_IN_CLUSTER(sec) \ -- ((((sec) - p_fs->data_start_sector + 1) & \ -- ((1 << p_fs->sectors_per_clu_bits) - 1)) == 0) -- --#define GET_CLUSTER_FROM_SECTOR(sec) \ -- ((u32)((((sec) - p_fs->data_start_sector) >> \ -- p_fs->sectors_per_clu_bits) + 2)) -- --#define GET16(p_src) \ -- (((u16)(p_src)[0]) | (((u16)(p_src)[1]) << 8)) --#define GET32(p_src) \ -- (((u32)(p_src)[0]) | (((u32)(p_src)[1]) << 8) | \ -- (((u32)(p_src)[2]) << 16) | (((u32)(p_src)[3]) << 24)) --#define GET64(p_src) \ -- (((u64)(p_src)[0]) | (((u64)(p_src)[1]) << 8) | \ -- (((u64)(p_src)[2]) << 16) | (((u64)(p_src)[3]) << 24) | \ -- (((u64)(p_src)[4]) << 32) | (((u64)(p_src)[5]) << 40) | \ -- (((u64)(p_src)[6]) << 48) | (((u64)(p_src)[7]) << 56)) -- --#define SET16(p_dst, src) \ -- do { \ -- (p_dst)[0] = (u8)(src); \ -- (p_dst)[1] = (u8)(((u16)(src)) >> 8); \ -- } while (0) --#define SET32(p_dst, src) \ -- do { \ -- (p_dst)[0] = (u8)(src); \ -- (p_dst)[1] = (u8)(((u32)(src)) >> 8); \ -- (p_dst)[2] = (u8)(((u32)(src)) >> 16); \ -- (p_dst)[3] = (u8)(((u32)(src)) >> 24); \ -- } while (0) --#define SET64(p_dst, src) \ -- do { \ -- (p_dst)[0] = (u8)(src); \ -- (p_dst)[1] = (u8)(((u64)(src)) >> 8); \ -- (p_dst)[2] = (u8)(((u64)(src)) >> 16); \ -- (p_dst)[3] = (u8)(((u64)(src)) >> 24); \ -- (p_dst)[4] = (u8)(((u64)(src)) >> 32); \ -- (p_dst)[5] = (u8)(((u64)(src)) >> 40); \ -- (p_dst)[6] = (u8)(((u64)(src)) >> 48); \ -- (p_dst)[7] = (u8)(((u64)(src)) >> 56); \ -- } while (0) -- --#ifdef __LITTLE_ENDIAN --#define GET16_A(p_src) (*((u16 *)(p_src))) --#define GET32_A(p_src) (*((u32 *)(p_src))) --#define GET64_A(p_src) (*((u64 *)(p_src))) --#define SET16_A(p_dst, src) (*((u16 *)(p_dst)) = (u16)(src)) --#define SET32_A(p_dst, src) (*((u32 *)(p_dst)) = (u32)(src)) --#define SET64_A(p_dst, src) (*((u64 *)(p_dst)) = (u64)(src)) --#else /* BIG_ENDIAN */ --#define GET16_A(p_src) GET16(p_src) --#define GET32_A(p_src) GET32(p_src) --#define GET64_A(p_src) GET64(p_src) --#define SET16_A(p_dst, src) SET16(p_dst, src) --#define SET32_A(p_dst, src) SET32(p_dst, src) --#define SET64_A(p_dst, src) SET64(p_dst, src) --#endif -- --/* cache size (in number of sectors) */ --/* (should be an exponential value of 2) */ --#define FAT_CACHE_SIZE 128 --#define FAT_CACHE_HASH_SIZE 64 --#define BUF_CACHE_SIZE 256 --#define BUF_CACHE_HASH_SIZE 64 -- --/* Upcase table macro */ --#define HIGH_INDEX_BIT (8) --#define HIGH_INDEX_MASK (0xFF00) --#define LOW_INDEX_BIT (16 - HIGH_INDEX_BIT) --#define UTBL_ROW_COUNT BIT(LOW_INDEX_BIT) --#define UTBL_COL_COUNT BIT(HIGH_INDEX_BIT) -- --static inline u16 get_col_index(u16 i) --{ -- return i >> LOW_INDEX_BIT; --} -- --static inline u16 get_row_index(u16 i) --{ -- return i & ~HIGH_INDEX_MASK; --} -- --#define EXFAT_SUPER_MAGIC (0x2011BAB0L) --#define EXFAT_ROOT_INO 1 -- --/* FAT types */ --#define FAT12 0x01 /* FAT12 */ --#define FAT16 0x0E /* Win95 FAT16 (LBA) */ --#define FAT32 0x0C /* Win95 FAT32 (LBA) */ --#define EXFAT 0x07 /* exFAT */ -- --/* file name lengths */ --#define MAX_CHARSET_SIZE 3 /* max size of multi-byte character */ --#define MAX_PATH_DEPTH 15 /* max depth of path name */ --#define MAX_NAME_LENGTH 256 /* max len of filename including NULL */ --#define MAX_PATH_LENGTH 260 /* max len of pathname including NULL */ --#define DOS_NAME_LENGTH 11 /* DOS filename length excluding NULL */ --#define DOS_PATH_LENGTH 80 /* DOS pathname length excluding NULL */ -- --/* file attributes */ --#define ATTR_NORMAL 0x0000 --#define ATTR_READONLY 0x0001 --#define ATTR_HIDDEN 0x0002 --#define ATTR_SYSTEM 0x0004 --#define ATTR_VOLUME 0x0008 --#define ATTR_SUBDIR 0x0010 --#define ATTR_ARCHIVE 0x0020 --#define ATTR_SYMLINK 0x0040 --#define ATTR_EXTEND 0x000F --#define ATTR_RWMASK 0x007E -- --/* file creation modes */ --#define FM_REGULAR 0x00 --#define FM_SYMLINK 0x40 -- --#define NUM_UPCASE 2918 -- --#define DOS_CUR_DIR_NAME ". " --#define DOS_PAR_DIR_NAME ".. " -- --#ifdef __LITTLE_ENDIAN --#define UNI_CUR_DIR_NAME ".\0" --#define UNI_PAR_DIR_NAME ".\0.\0" --#else --#define UNI_CUR_DIR_NAME "\0." --#define UNI_PAR_DIR_NAME "\0.\0." --#endif -- --struct date_time_t { -- u16 Year; -- u16 Month; -- u16 Day; -- u16 Hour; -- u16 Minute; -- u16 Second; -- u16 MilliSecond; --}; -- --struct part_info_t { -- u32 Offset; /* start sector number of the partition */ -- u32 Size; /* in sectors */ --}; -- --struct dev_info_t { -- u32 SecSize; /* sector size in bytes */ -- u32 DevSize; /* block device size in sectors */ --}; -- --struct vol_info_t { -- u32 FatType; -- u32 ClusterSize; -- u32 NumClusters; -- u32 FreeClusters; -- u32 UsedClusters; --}; -- --/* directory structure */ --struct chain_t { -- u32 dir; -- s32 size; -- u8 flags; --}; -- --struct file_id_t { -- struct chain_t dir; -- s32 entry; -- u32 type; -- u32 attr; -- u32 start_clu; -- u64 size; -- u8 flags; -- s64 rwoffset; -- s32 hint_last_off; -- u32 hint_last_clu; --}; -- --struct dir_entry_t { -- char Name[MAX_NAME_LENGTH * MAX_CHARSET_SIZE]; -- -- /* used only for FAT12/16/32, not used for exFAT */ -- char ShortName[DOS_NAME_LENGTH + 2]; -- -- u32 Attr; -- u64 Size; -- u32 NumSubdirs; -- struct date_time_t CreateTimestamp; -- struct date_time_t ModifyTimestamp; -- struct date_time_t AccessTimestamp; --}; -- --struct timestamp_t { -- u16 sec; /* 0 ~ 59 */ -- u16 min; /* 0 ~ 59 */ -- u16 hour; /* 0 ~ 23 */ -- u16 day; /* 1 ~ 31 */ -- u16 mon; /* 1 ~ 12 */ -- u16 year; /* 0 ~ 127 (since 1980) */ --}; -- --/* MS_DOS FAT partition boot record (512 bytes) */ --struct pbr_sector_t { -- u8 jmp_boot[3]; -- u8 oem_name[8]; -- u8 bpb[109]; -- u8 boot_code[390]; -- u8 signature[2]; --}; -- --/* MS-DOS FAT12/16 BIOS parameter block (51 bytes) */ --struct bpb16_t { -- u8 sector_size[2]; -- u8 sectors_per_clu; -- u8 num_reserved[2]; -- u8 num_fats; -- u8 num_root_entries[2]; -- u8 num_sectors[2]; -- u8 media_type; -- u8 num_fat_sectors[2]; -- u8 sectors_in_track[2]; -- u8 num_heads[2]; -- u8 num_hid_sectors[4]; -- u8 num_huge_sectors[4]; -- -- u8 phy_drv_no; -- u8 reserved; -- u8 ext_signature; -- u8 vol_serial[4]; -- u8 vol_label[11]; -- u8 vol_type[8]; --}; -- --/* MS-DOS FAT32 BIOS parameter block (79 bytes) */ --struct bpb32_t { -- u8 sector_size[2]; -- u8 sectors_per_clu; -- u8 num_reserved[2]; -- u8 num_fats; -- u8 num_root_entries[2]; -- u8 num_sectors[2]; -- u8 media_type; -- u8 num_fat_sectors[2]; -- u8 sectors_in_track[2]; -- u8 num_heads[2]; -- u8 num_hid_sectors[4]; -- u8 num_huge_sectors[4]; -- u8 num_fat32_sectors[4]; -- u8 ext_flags[2]; -- u8 fs_version[2]; -- u8 root_cluster[4]; -- u8 fsinfo_sector[2]; -- u8 backup_sector[2]; -- u8 reserved[12]; -- -- u8 phy_drv_no; -- u8 ext_reserved; -- u8 ext_signature; -- u8 vol_serial[4]; -- u8 vol_label[11]; -- u8 vol_type[8]; --}; -- --/* MS-DOS EXFAT BIOS parameter block (109 bytes) */ --struct bpbex_t { -- u8 reserved1[53]; -- u8 vol_offset[8]; -- u8 vol_length[8]; -- u8 fat_offset[4]; -- u8 fat_length[4]; -- u8 clu_offset[4]; -- u8 clu_count[4]; -- u8 root_cluster[4]; -- u8 vol_serial[4]; -- u8 fs_version[2]; -- u8 vol_flags[2]; -- u8 sector_size_bits; -- u8 sectors_per_clu_bits; -- u8 num_fats; -- u8 phy_drv_no; -- u8 perc_in_use; -- u8 reserved2[7]; --}; -- --/* MS-DOS FAT file system information sector (512 bytes) */ --struct fsi_sector_t { -- u8 signature1[4]; -- u8 reserved1[480]; -- u8 signature2[4]; -- u8 free_cluster[4]; -- u8 next_cluster[4]; -- u8 reserved2[14]; -- u8 signature3[2]; --}; -- --/* MS-DOS FAT directory entry (32 bytes) */ --struct dentry_t { -- u8 dummy[32]; --}; -- --struct dos_dentry_t { -- u8 name[DOS_NAME_LENGTH]; -- u8 attr; -- u8 lcase; -- u8 create_time_ms; -- u8 create_time[2]; -- u8 create_date[2]; -- u8 access_date[2]; -- u8 start_clu_hi[2]; -- u8 modify_time[2]; -- u8 modify_date[2]; -- u8 start_clu_lo[2]; -- u8 size[4]; --}; -- --/* MS-DOS FAT extended directory entry (32 bytes) */ --struct ext_dentry_t { -- u8 order; -- u8 unicode_0_4[10]; -- u8 attr; -- u8 sysid; -- u8 checksum; -- u8 unicode_5_10[12]; -- u8 start_clu[2]; -- u8 unicode_11_12[4]; --}; -- --/* MS-DOS EXFAT file directory entry (32 bytes) */ --struct file_dentry_t { -- u8 type; -- u8 num_ext; -- u8 checksum[2]; -- u8 attr[2]; -- u8 reserved1[2]; -- u8 create_time[2]; -- u8 create_date[2]; -- u8 modify_time[2]; -- u8 modify_date[2]; -- u8 access_time[2]; -- u8 access_date[2]; -- u8 create_time_ms; -- u8 modify_time_ms; -- u8 access_time_ms; -- u8 reserved2[9]; --}; -- --/* MS-DOS EXFAT stream extension directory entry (32 bytes) */ --struct strm_dentry_t { -- u8 type; -- u8 flags; -- u8 reserved1; -- u8 name_len; -- u8 name_hash[2]; -- u8 reserved2[2]; -- u8 valid_size[8]; -- u8 reserved3[4]; -- u8 start_clu[4]; -- u8 size[8]; --}; -- --/* MS-DOS EXFAT file name directory entry (32 bytes) */ --struct name_dentry_t { -- u8 type; -- u8 flags; -- u8 unicode_0_14[30]; --}; -- --/* MS-DOS EXFAT allocation bitmap directory entry (32 bytes) */ --struct bmap_dentry_t { -- u8 type; -- u8 flags; -- u8 reserved[18]; -- u8 start_clu[4]; -- u8 size[8]; --}; -- --/* MS-DOS EXFAT up-case table directory entry (32 bytes) */ --struct case_dentry_t { -- u8 type; -- u8 reserved1[3]; -- u8 checksum[4]; -- u8 reserved2[12]; -- u8 start_clu[4]; -- u8 size[8]; --}; -- --/* MS-DOS EXFAT volume label directory entry (32 bytes) */ --struct volm_dentry_t { -- u8 type; -- u8 label_len; -- u8 unicode_0_10[22]; -- u8 reserved[8]; --}; -- --/* unused entry hint information */ --struct uentry_t { -- u32 dir; -- s32 entry; -- struct chain_t clu; --}; -- --/* DOS name structure */ --struct dos_name_t { -- u8 name[DOS_NAME_LENGTH]; -- u8 name_case; --}; -- --/* unicode name structure */ --struct uni_name_t { -- u16 name[MAX_NAME_LENGTH]; -- u16 name_hash; -- u8 name_len; --}; -- --struct buf_cache_t { -- struct buf_cache_t *next; -- struct buf_cache_t *prev; -- struct buf_cache_t *hash_next; -- struct buf_cache_t *hash_prev; -- s32 drv; -- sector_t sec; -- u32 flag; -- struct buffer_head *buf_bh; --}; -- --struct fs_info_t { -- u32 drv; /* drive ID */ -- u32 vol_type; /* volume FAT type */ -- u32 vol_id; /* volume serial number */ -- -- u64 num_sectors; /* num of sectors in volume */ -- u32 num_clusters; /* num of clusters in volume */ -- u32 cluster_size; /* cluster size in bytes */ -- u32 cluster_size_bits; -- u32 sectors_per_clu; /* cluster size in sectors */ -- u32 sectors_per_clu_bits; -- -- u32 PBR_sector; /* PBR sector */ -- u32 FAT1_start_sector; /* FAT1 start sector */ -- u32 FAT2_start_sector; /* FAT2 start sector */ -- u32 root_start_sector; /* root dir start sector */ -- u32 data_start_sector; /* data area start sector */ -- u32 num_FAT_sectors; /* num of FAT sectors */ -- -- u32 root_dir; /* root dir cluster */ -- u32 dentries_in_root; /* num of dentries in root dir */ -- u32 dentries_per_clu; /* num of dentries per cluster */ -- -- u32 vol_flag; /* volume dirty flag */ -- struct buffer_head *pbr_bh; /* PBR sector */ -- -- u32 map_clu; /* allocation bitmap start cluster */ -- u32 map_sectors; /* num of allocation bitmap sectors */ -- struct buffer_head **vol_amap; /* allocation bitmap */ -- -- u16 **vol_utbl; /* upcase table */ -- -- u32 clu_srch_ptr; /* cluster search pointer */ -- u32 used_clusters; /* number of used clusters */ -- struct uentry_t hint_uentry; /* unused entry hint information */ -- -- u32 dev_ejected; /* block device operation error flag */ -- -- struct mutex v_mutex; -- -- /* FAT cache */ -- struct buf_cache_t FAT_cache_array[FAT_CACHE_SIZE]; -- struct buf_cache_t FAT_cache_lru_list; -- struct buf_cache_t FAT_cache_hash_list[FAT_CACHE_HASH_SIZE]; -- -- /* buf cache */ -- struct buf_cache_t buf_cache_array[BUF_CACHE_SIZE]; -- struct buf_cache_t buf_cache_lru_list; -- struct buf_cache_t buf_cache_hash_list[BUF_CACHE_HASH_SIZE]; --}; -- --#define ES_2_ENTRIES 2 --#define ES_3_ENTRIES 3 --#define ES_ALL_ENTRIES 0 -- --struct entry_set_cache_t { -- /* sector number that contains file_entry */ -- sector_t sector; -- -- /* byte offset in the sector */ -- s32 offset; -- -- /* -- * flag in stream entry. -- * 01 for cluster chain, -- * 03 for contig. clusteres. -- */ -- s32 alloc_flag; -- -- u32 num_entries; -- -- /* __buf should be the last member */ -- void *__buf; --}; -- --#define EXFAT_ERRORS_CONT 1 /* ignore error and continue */ --#define EXFAT_ERRORS_PANIC 2 /* panic on error */ --#define EXFAT_ERRORS_RO 3 /* remount r/o on error */ -- --/* ioctl command */ --#define EXFAT_IOCTL_GET_VOLUME_ID _IOR('r', 0x12, __u32) -- --struct exfat_mount_options { -- kuid_t fs_uid; -- kgid_t fs_gid; -- unsigned short fs_fmask; -- unsigned short fs_dmask; -- -- /* permission for setting the [am]time */ -- unsigned short allow_utime; -- -- /* codepage for shortname conversions */ -- unsigned short codepage; -- -- /* charset for filename input/display */ -- char *iocharset; -- -- unsigned char casesensitive; -- -- /* on error: continue, panic, remount-ro */ -- unsigned char errors; --#ifdef CONFIG_STAGING_EXFAT_DISCARD -- /* flag on if -o dicard specified and device support discard() */ -- unsigned char discard; --#endif /* CONFIG_STAGING_EXFAT_DISCARD */ --}; -- --#define EXFAT_HASH_BITS 8 --#define EXFAT_HASH_SIZE BIT(EXFAT_HASH_BITS) -- --/* -- * EXFAT file system in-core superblock data -- */ --struct bd_info_t { -- s32 sector_size; /* in bytes */ -- s32 sector_size_bits; -- s32 sector_size_mask; -- -- /* total number of sectors in this block device */ -- s32 num_sectors; -- -- /* opened or not */ -- bool opened; --}; -- --struct exfat_sb_info { -- struct fs_info_t fs_info; -- struct bd_info_t bd_info; -- -- struct exfat_mount_options options; -- -- int s_dirt; -- struct mutex s_lock; -- struct nls_table *nls_disk; /* Codepage used on disk */ -- struct nls_table *nls_io; /* Charset used for input and display */ -- -- struct inode *fat_inode; -- -- spinlock_t inode_hash_lock; -- struct hlist_head inode_hashtable[EXFAT_HASH_SIZE]; --#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG -- long debug_flags; --#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */ --}; -- --/* -- * EXFAT file system inode data in memory -- */ --struct exfat_inode_info { -- struct file_id_t fid; -- char *target; -- /* NOTE: mmu_private is 64bits, so must hold ->i_mutex to access */ -- loff_t mmu_private; /* physically allocated size */ -- loff_t i_pos; /* on-disk position of directory entry or 0 */ -- struct hlist_node i_hash_fat; /* hash by i_location */ -- struct rw_semaphore truncate_lock; -- struct inode vfs_inode; -- struct rw_semaphore i_alloc_sem; /* protect bmap against truncate */ --}; -- --#define EXFAT_SB(sb) ((struct exfat_sb_info *)((sb)->s_fs_info)) -- --static inline struct exfat_inode_info *EXFAT_I(struct inode *inode) --{ -- return container_of(inode, struct exfat_inode_info, vfs_inode); --} -- --/* NLS management function */ --u16 nls_upper(struct super_block *sb, u16 a); --int nls_uniname_cmp(struct super_block *sb, u16 *a, u16 *b); --void nls_uniname_to_cstring(struct super_block *sb, u8 *p_cstring, -- struct uni_name_t *p_uniname); --void nls_cstring_to_uniname(struct super_block *sb, -- struct uni_name_t *p_uniname, u8 *p_cstring, -- bool *p_lossy); -- --/* buffer cache management */ --void exfat_buf_init(struct super_block *sb); --void exfat_buf_shutdown(struct super_block *sb); --int exfat_fat_read(struct super_block *sb, u32 loc, u32 *content); --s32 exfat_fat_write(struct super_block *sb, u32 loc, u32 content); --u8 *exfat_fat_getblk(struct super_block *sb, sector_t sec); --void exfat_fat_modify(struct super_block *sb, sector_t sec); --void exfat_fat_release_all(struct super_block *sb); --void exfat_fat_sync(struct super_block *sb); --u8 *exfat_buf_getblk(struct super_block *sb, sector_t sec); --void exfat_buf_modify(struct super_block *sb, sector_t sec); --void exfat_buf_lock(struct super_block *sb, sector_t sec); --void exfat_buf_unlock(struct super_block *sb, sector_t sec); --void exfat_buf_release(struct super_block *sb, sector_t sec); --void exfat_buf_release_all(struct super_block *sb); --void exfat_buf_sync(struct super_block *sb); -- --/* fs management functions */ --void fs_set_vol_flags(struct super_block *sb, u32 new_flag); --void fs_error(struct super_block *sb); -- --/* cluster management functions */ --s32 count_num_clusters(struct super_block *sb, struct chain_t *dir); --void exfat_chain_cont_cluster(struct super_block *sb, u32 chain, s32 len); -- --/* allocation bitmap management functions */ --s32 load_alloc_bitmap(struct super_block *sb); --void free_alloc_bitmap(struct super_block *sb); --void sync_alloc_bitmap(struct super_block *sb); -- --/* upcase table management functions */ --s32 load_upcase_table(struct super_block *sb); --void free_upcase_table(struct super_block *sb); -- --/* dir entry management functions */ --struct timestamp_t *tm_current(struct timestamp_t *tm); -- --struct dentry_t *get_entry_in_dir(struct super_block *sb, struct chain_t *p_dir, -- s32 entry, sector_t *sector); --struct entry_set_cache_t *get_entry_set_in_dir(struct super_block *sb, -- struct chain_t *p_dir, s32 entry, -- u32 type, -- struct dentry_t **file_ep); --void release_entry_set(struct entry_set_cache_t *es); --s32 count_dos_name_entries(struct super_block *sb, struct chain_t *p_dir, -- u32 type); --void update_dir_checksum(struct super_block *sb, struct chain_t *p_dir, -- s32 entry); --void update_dir_checksum_with_entry_set(struct super_block *sb, -- struct entry_set_cache_t *es); --bool is_dir_empty(struct super_block *sb, struct chain_t *p_dir); -- --/* name conversion functions */ --s32 get_num_entries_and_dos_name(struct super_block *sb, struct chain_t *p_dir, -- struct uni_name_t *p_uniname, s32 *entries, -- struct dos_name_t *p_dosname); --u16 calc_checksum_2byte(void *data, s32 len, u16 chksum, s32 type); -- --/* name resolution functions */ --s32 resolve_path(struct inode *inode, char *path, struct chain_t *p_dir, -- struct uni_name_t *p_uniname); -- --/* file operation functions */ --s32 exfat_mount(struct super_block *sb, struct pbr_sector_t *p_pbr); --s32 create_dir(struct inode *inode, struct chain_t *p_dir, -- struct uni_name_t *p_uniname, struct file_id_t *fid); --s32 create_file(struct inode *inode, struct chain_t *p_dir, -- struct uni_name_t *p_uniname, u8 mode, struct file_id_t *fid); --void remove_file(struct inode *inode, struct chain_t *p_dir, s32 entry); --s32 exfat_rename_file(struct inode *inode, struct chain_t *p_dir, s32 old_entry, -- struct uni_name_t *p_uniname, struct file_id_t *fid); --s32 move_file(struct inode *inode, struct chain_t *p_olddir, s32 oldentry, -- struct chain_t *p_newdir, struct uni_name_t *p_uniname, -- struct file_id_t *fid); -- --/* sector read/write functions */ --int sector_read(struct super_block *sb, sector_t sec, -- struct buffer_head **bh, bool read); --int sector_write(struct super_block *sb, sector_t sec, -- struct buffer_head *bh, bool sync); --int multi_sector_read(struct super_block *sb, sector_t sec, -- struct buffer_head **bh, s32 num_secs, bool read); --int multi_sector_write(struct super_block *sb, sector_t sec, -- struct buffer_head *bh, s32 num_secs, bool sync); -- --void exfat_bdev_open(struct super_block *sb); --void exfat_bdev_close(struct super_block *sb); --int exfat_bdev_read(struct super_block *sb, sector_t secno, -- struct buffer_head **bh, u32 num_secs, bool read); --int exfat_bdev_write(struct super_block *sb, sector_t secno, -- struct buffer_head *bh, u32 num_secs, bool sync); --int exfat_bdev_sync(struct super_block *sb); -- --/* cluster operation functions */ --s32 exfat_alloc_cluster(struct super_block *sb, s32 num_alloc, -- struct chain_t *p_chain); --void exfat_free_cluster(struct super_block *sb, struct chain_t *p_chain, -- s32 do_relse); --s32 exfat_count_used_clusters(struct super_block *sb); -- --/* dir operation functions */ --s32 exfat_find_dir_entry(struct super_block *sb, struct chain_t *p_dir, -- struct uni_name_t *p_uniname, s32 num_entries, -- struct dos_name_t *p_dosname, u32 type); --void exfat_delete_dir_entry(struct super_block *sb, struct chain_t *p_dir, -- s32 entry, s32 order, s32 num_entries); --void exfat_get_uni_name_from_ext_entry(struct super_block *sb, -- struct chain_t *p_dir, s32 entry, -- u16 *uniname); --s32 exfat_count_ext_entries(struct super_block *sb, struct chain_t *p_dir, -- s32 entry, struct dentry_t *p_entry); --s32 exfat_calc_num_entries(struct uni_name_t *p_uniname); -- --/* dir entry getter/setter */ --u32 exfat_get_entry_type(struct dentry_t *p_entry); --u32 exfat_get_entry_attr(struct dentry_t *p_entry); --void exfat_set_entry_attr(struct dentry_t *p_entry, u32 attr); --u8 exfat_get_entry_flag(struct dentry_t *p_entry); --void exfat_set_entry_flag(struct dentry_t *p_entry, u8 flags); --u32 exfat_get_entry_clu0(struct dentry_t *p_entry); --void exfat_set_entry_clu0(struct dentry_t *p_entry, u32 start_clu); --u64 exfat_get_entry_size(struct dentry_t *p_entry); --void exfat_set_entry_size(struct dentry_t *p_entry, u64 size); --void exfat_get_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp, -- u8 mode); --void exfat_set_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp, -- u8 mode); -- --extern const u8 uni_upcase[]; --#endif /* _EXFAT_H */ -diff -Nurp linux-5.6.3.orig/drivers/staging/exfat/exfat_nls.c linux-5.6.3/drivers/staging/exfat/exfat_nls.c ---- linux-5.6.3.orig/drivers/staging/exfat/exfat_nls.c 2020-03-30 01:25:41.000000000 +0300 -+++ linux-5.6.3/drivers/staging/exfat/exfat_nls.c 1970-01-01 02:00:00.000000000 +0200 -@@ -1,212 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0-or-later --/* -- * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -- */ -- --#include --#include --#include "exfat.h" -- --static u16 bad_uni_chars[] = { -- /* " * / : < > ? \ | */ -- 0x0022, 0x002A, 0x002F, 0x003A, -- 0x003C, 0x003E, 0x003F, 0x005C, 0x007C, -- 0 --}; -- --static int convert_ch_to_uni(struct nls_table *nls, u16 *uni, u8 *ch, -- bool *lossy) --{ -- int len; -- -- *uni = 0x0; -- -- if (ch[0] < 0x80) { -- *uni = (u16)ch[0]; -- return 1; -- } -- -- len = nls->char2uni(ch, NLS_MAX_CHARSET_SIZE, uni); -- if (len < 0) { -- /* conversion failed */ -- pr_info("%s: fail to use nls\n", __func__); -- if (lossy) -- *lossy = true; -- *uni = (u16)'_'; -- if (!strcmp(nls->charset, "utf8")) -- return 1; -- else -- return 2; -- } -- -- return len; --} -- --static int convert_uni_to_ch(struct nls_table *nls, u8 *ch, u16 uni, -- bool *lossy) --{ -- int len; -- -- ch[0] = 0x0; -- -- if (uni < 0x0080) { -- ch[0] = (u8)uni; -- return 1; -- } -- -- len = nls->uni2char(uni, ch, NLS_MAX_CHARSET_SIZE); -- if (len < 0) { -- /* conversion failed */ -- pr_info("%s: fail to use nls\n", __func__); -- if (lossy) -- *lossy = true; -- ch[0] = '_'; -- return 1; -- } -- -- return len; --} -- --u16 nls_upper(struct super_block *sb, u16 a) --{ -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- if (EXFAT_SB(sb)->options.casesensitive) -- return a; -- if (p_fs->vol_utbl && p_fs->vol_utbl[get_col_index(a)]) -- return p_fs->vol_utbl[get_col_index(a)][get_row_index(a)]; -- else -- return a; --} -- --static u16 *nls_wstrchr(u16 *str, u16 wchar) --{ -- while (*str) { -- if (*(str++) == wchar) -- return str; -- } -- -- return NULL; --} -- --int nls_uniname_cmp(struct super_block *sb, u16 *a, u16 *b) --{ -- int i; -- -- for (i = 0; i < MAX_NAME_LENGTH; i++, a++, b++) { -- if (nls_upper(sb, *a) != nls_upper(sb, *b)) -- return 1; -- if (*a == 0x0) -- return 0; -- } -- return 0; --} -- --void nls_uniname_to_cstring(struct super_block *sb, u8 *p_cstring, -- struct uni_name_t *p_uniname) --{ -- int i, j, len; -- u8 buf[MAX_CHARSET_SIZE]; -- u16 *uniname = p_uniname->name; -- struct nls_table *nls = EXFAT_SB(sb)->nls_io; -- -- if (!nls) { -- len = utf16s_to_utf8s(uniname, MAX_NAME_LENGTH, -- UTF16_HOST_ENDIAN, p_cstring, -- MAX_NAME_LENGTH); -- p_cstring[len] = 0; -- return; -- } -- -- i = 0; -- while (i < (MAX_NAME_LENGTH - 1)) { -- if (*uniname == (u16)'\0') -- break; -- -- len = convert_uni_to_ch(nls, buf, *uniname, NULL); -- -- if (len > 1) { -- for (j = 0; j < len; j++) -- *p_cstring++ = (char)*(buf + j); -- } else { /* len == 1 */ -- *p_cstring++ = (char)*buf; -- } -- -- uniname++; -- i++; -- } -- -- *p_cstring = '\0'; --} -- --void nls_cstring_to_uniname(struct super_block *sb, -- struct uni_name_t *p_uniname, u8 *p_cstring, -- bool *p_lossy) --{ -- int i, j; -- bool lossy = false; -- u8 *end_of_name; -- u8 upname[MAX_NAME_LENGTH * 2]; -- u16 *uniname = p_uniname->name; -- struct nls_table *nls = EXFAT_SB(sb)->nls_io; -- -- /* strip all trailing spaces */ -- end_of_name = p_cstring + strlen(p_cstring); -- -- while (*(--end_of_name) == ' ') { -- if (end_of_name < p_cstring) -- break; -- } -- *(++end_of_name) = '\0'; -- -- if (strcmp(p_cstring, ".") && strcmp(p_cstring, "..")) { -- /* strip all trailing periods */ -- while (*(--end_of_name) == '.') { -- if (end_of_name < p_cstring) -- break; -- } -- *(++end_of_name) = '\0'; -- } -- -- if (*p_cstring == '\0') -- lossy = true; -- -- if (!nls) { -- i = utf8s_to_utf16s(p_cstring, MAX_NAME_LENGTH, -- UTF16_HOST_ENDIAN, uniname, -- MAX_NAME_LENGTH); -- for (j = 0; j < i; j++) -- SET16_A(upname + j * 2, nls_upper(sb, uniname[j])); -- uniname[i] = '\0'; -- } else { -- i = 0; -- j = 0; -- while (j < (MAX_NAME_LENGTH - 1)) { -- if (*(p_cstring + i) == '\0') -- break; -- -- i += convert_ch_to_uni(nls, uniname, -- (u8 *)(p_cstring + i), &lossy); -- -- if ((*uniname < 0x0020) || -- nls_wstrchr(bad_uni_chars, *uniname)) -- lossy = true; -- -- SET16_A(upname + j * 2, nls_upper(sb, *uniname)); -- -- uniname++; -- j++; -- } -- -- if (*(p_cstring + i) != '\0') -- lossy = true; -- *uniname = (u16)'\0'; -- } -- -- p_uniname->name_len = j; -- p_uniname->name_hash = calc_checksum_2byte(upname, j << 1, 0, -- CS_DEFAULT); -- -- if (p_lossy) -- *p_lossy = lossy; --} -diff -Nurp linux-5.6.3.orig/drivers/staging/exfat/exfat_super.c linux-5.6.3/drivers/staging/exfat/exfat_super.c ---- linux-5.6.3.orig/drivers/staging/exfat/exfat_super.c 2020-03-30 01:25:41.000000000 +0300 -+++ linux-5.6.3/drivers/staging/exfat/exfat_super.c 1970-01-01 02:00:00.000000000 +0200 -@@ -1,3883 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0-or-later --/* -- * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -- */ -- --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include -- --#define EXFAT_VERSION "1.3.0" -- --#include "exfat.h" -- --static struct kmem_cache *exfat_inode_cachep; -- --static int exfat_default_codepage = CONFIG_STAGING_EXFAT_DEFAULT_CODEPAGE; --static char exfat_default_iocharset[] = CONFIG_STAGING_EXFAT_DEFAULT_IOCHARSET; -- --#define INC_IVERSION(x) (inode_inc_iversion(x)) --#define GET_IVERSION(x) (inode_peek_iversion_raw(x)) --#define SET_IVERSION(x, y) (inode_set_iversion(x, y)) -- --static struct inode *exfat_iget(struct super_block *sb, loff_t i_pos); --static int exfat_sync_inode(struct inode *inode); --static struct inode *exfat_build_inode(struct super_block *sb, -- struct file_id_t *fid, loff_t i_pos); --static int exfat_write_inode(struct inode *inode, -- struct writeback_control *wbc); --static void exfat_write_super(struct super_block *sb); -- --#define UNIX_SECS_1980 315532800L --#define UNIX_SECS_2108 4354819200L -- --/* Convert a FAT time/date pair to a UNIX date (seconds since 1 1 70). */ --static void exfat_time_fat2unix(struct timespec64 *ts, struct date_time_t *tp) --{ -- ts->tv_sec = mktime64(tp->Year + 1980, tp->Month + 1, tp->Day, -- tp->Hour, tp->Minute, tp->Second); -- -- ts->tv_nsec = tp->MilliSecond * NSEC_PER_MSEC; --} -- --/* Convert linear UNIX date to a FAT time/date pair. */ --static void exfat_time_unix2fat(struct timespec64 *ts, struct date_time_t *tp) --{ -- time64_t second = ts->tv_sec; -- struct tm tm; -- -- time64_to_tm(second, 0, &tm); -- -- if (second < UNIX_SECS_1980) { -- tp->MilliSecond = 0; -- tp->Second = 0; -- tp->Minute = 0; -- tp->Hour = 0; -- tp->Day = 1; -- tp->Month = 1; -- tp->Year = 0; -- return; -- } -- -- if (second >= UNIX_SECS_2108) { -- tp->MilliSecond = 999; -- tp->Second = 59; -- tp->Minute = 59; -- tp->Hour = 23; -- tp->Day = 31; -- tp->Month = 12; -- tp->Year = 127; -- return; -- } -- -- tp->MilliSecond = ts->tv_nsec / NSEC_PER_MSEC; -- tp->Second = tm.tm_sec; -- tp->Minute = tm.tm_min; -- tp->Hour = tm.tm_hour; -- tp->Day = tm.tm_mday; -- tp->Month = tm.tm_mon + 1; -- tp->Year = tm.tm_year + 1900 - 1980; --} -- --struct timestamp_t *tm_current(struct timestamp_t *tp) --{ -- time64_t second = ktime_get_real_seconds(); -- struct tm tm; -- -- time64_to_tm(second, 0, &tm); -- -- if (second < UNIX_SECS_1980) { -- tp->sec = 0; -- tp->min = 0; -- tp->hour = 0; -- tp->day = 1; -- tp->mon = 1; -- tp->year = 0; -- return tp; -- } -- -- if (second >= UNIX_SECS_2108) { -- tp->sec = 59; -- tp->min = 59; -- tp->hour = 23; -- tp->day = 31; -- tp->mon = 12; -- tp->year = 127; -- return tp; -- } -- -- tp->sec = tm.tm_sec; -- tp->min = tm.tm_min; -- tp->hour = tm.tm_hour; -- tp->day = tm.tm_mday; -- tp->mon = tm.tm_mon + 1; -- tp->year = tm.tm_year + 1900 - 1980; -- -- return tp; --} -- --static void __lock_super(struct super_block *sb) --{ -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- -- mutex_lock(&sbi->s_lock); --} -- --static void __unlock_super(struct super_block *sb) --{ -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- -- mutex_unlock(&sbi->s_lock); --} -- --static int __is_sb_dirty(struct super_block *sb) --{ -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- -- return sbi->s_dirt; --} -- --static void __set_sb_clean(struct super_block *sb) --{ -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- -- sbi->s_dirt = 0; --} -- --static int __exfat_revalidate(struct dentry *dentry) --{ -- return 0; --} -- --static int exfat_revalidate(struct dentry *dentry, unsigned int flags) --{ -- if (flags & LOOKUP_RCU) -- return -ECHILD; -- -- if (dentry->d_inode) -- return 1; -- return __exfat_revalidate(dentry); --} -- --static int exfat_revalidate_ci(struct dentry *dentry, unsigned int flags) --{ -- if (flags & LOOKUP_RCU) -- return -ECHILD; -- -- if (dentry->d_inode) -- return 1; -- -- if (!flags) -- return 0; -- -- if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) -- return 0; -- -- return __exfat_revalidate(dentry); --} -- --static unsigned int __exfat_striptail_len(unsigned int len, const char *name) --{ -- while (len && name[len - 1] == '.') -- len--; -- return len; --} -- --static unsigned int exfat_striptail_len(const struct qstr *qstr) --{ -- return __exfat_striptail_len(qstr->len, qstr->name); --} -- --static int exfat_d_hash(const struct dentry *dentry, struct qstr *qstr) --{ -- qstr->hash = full_name_hash(dentry, qstr->name, -- exfat_striptail_len(qstr)); -- return 0; --} -- --static int exfat_d_hashi(const struct dentry *dentry, struct qstr *qstr) --{ -- struct super_block *sb = dentry->d_sb; -- const unsigned char *name; -- unsigned int len; -- unsigned long hash; -- -- name = qstr->name; -- len = exfat_striptail_len(qstr); -- -- hash = init_name_hash(dentry); -- while (len--) -- hash = partial_name_hash(nls_upper(sb, *name++), hash); -- qstr->hash = end_name_hash(hash); -- -- return 0; --} -- --static int exfat_cmpi(const struct dentry *dentry, unsigned int len, -- const char *str, const struct qstr *name) --{ -- struct nls_table *t = EXFAT_SB(dentry->d_sb)->nls_io; -- unsigned int alen, blen; -- -- alen = exfat_striptail_len(name); -- blen = __exfat_striptail_len(len, str); -- if (alen == blen) { -- if (!t) { -- if (strncasecmp(name->name, str, alen) == 0) -- return 0; -- } else { -- if (nls_strnicmp(t, name->name, str, alen) == 0) -- return 0; -- } -- } -- return 1; --} -- --static int exfat_cmp(const struct dentry *dentry, unsigned int len, -- const char *str, const struct qstr *name) --{ -- unsigned int alen, blen; -- -- alen = exfat_striptail_len(name); -- blen = __exfat_striptail_len(len, str); -- if (alen == blen) { -- if (strncmp(name->name, str, alen) == 0) -- return 0; -- } -- return 1; --} -- --static const struct dentry_operations exfat_ci_dentry_ops = { -- .d_revalidate = exfat_revalidate_ci, -- .d_hash = exfat_d_hashi, -- .d_compare = exfat_cmpi, --}; -- --static const struct dentry_operations exfat_dentry_ops = { -- .d_revalidate = exfat_revalidate, -- .d_hash = exfat_d_hash, -- .d_compare = exfat_cmp, --}; -- --static DEFINE_MUTEX(z_mutex); -- --static inline void fs_sync(struct super_block *sb, bool do_sync) --{ -- if (do_sync) -- exfat_bdev_sync(sb); --} -- --/* -- * If ->i_mode can't hold S_IWUGO (i.e. ATTR_RO), we use ->i_attrs to -- * save ATTR_RO instead of ->i_mode. -- * -- * If it's directory and !sbi->options.rodir, ATTR_RO isn't read-only -- * bit, it's just used as flag for app. -- */ --static inline int exfat_mode_can_hold_ro(struct inode *inode) --{ -- struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); -- -- if (S_ISDIR(inode->i_mode)) -- return 0; -- -- if ((~sbi->options.fs_fmask) & 0222) -- return 1; -- return 0; --} -- --/* Convert attribute bits and a mask to the UNIX mode. */ --static inline mode_t exfat_make_mode(struct exfat_sb_info *sbi, u32 attr, -- mode_t mode) --{ -- if ((attr & ATTR_READONLY) && !(attr & ATTR_SUBDIR)) -- mode &= ~0222; -- -- if (attr & ATTR_SUBDIR) -- return (mode & ~sbi->options.fs_dmask) | S_IFDIR; -- else if (attr & ATTR_SYMLINK) -- return (mode & ~sbi->options.fs_dmask) | S_IFLNK; -- else -- return (mode & ~sbi->options.fs_fmask) | S_IFREG; --} -- --/* Return the FAT attribute byte for this inode */ --static inline u32 exfat_make_attr(struct inode *inode) --{ -- if (exfat_mode_can_hold_ro(inode) && !(inode->i_mode & 0222)) -- return (EXFAT_I(inode)->fid.attr) | ATTR_READONLY; -- else -- return EXFAT_I(inode)->fid.attr; --} -- --static inline void exfat_save_attr(struct inode *inode, u32 attr) --{ -- if (exfat_mode_can_hold_ro(inode)) -- EXFAT_I(inode)->fid.attr = attr & ATTR_RWMASK; -- else -- EXFAT_I(inode)->fid.attr = attr & (ATTR_RWMASK | ATTR_READONLY); --} -- --static int ffsMountVol(struct super_block *sb) --{ -- int i, ret; -- struct pbr_sector_t *p_pbr; -- struct buffer_head *tmp_bh = NULL; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- pr_info("[EXFAT] trying to mount...\n"); -- -- mutex_lock(&z_mutex); -- -- exfat_buf_init(sb); -- -- mutex_init(&p_fs->v_mutex); -- p_fs->dev_ejected = 0; -- -- /* open the block device */ -- exfat_bdev_open(sb); -- -- if (p_bd->sector_size < sb->s_blocksize) { -- printk(KERN_INFO "EXFAT: mount failed - sector size %d less than blocksize %ld\n", -- p_bd->sector_size, sb->s_blocksize); -- ret = -EINVAL; -- goto out; -- } -- if (p_bd->sector_size > sb->s_blocksize) -- sb_set_blocksize(sb, p_bd->sector_size); -- -- /* read Sector 0 */ -- if (sector_read(sb, 0, &tmp_bh, 1) != 0) { -- ret = -EIO; -- goto out; -- } -- -- p_fs->PBR_sector = 0; -- -- p_pbr = (struct pbr_sector_t *)tmp_bh->b_data; -- -- /* check the validity of PBR */ -- if (GET16_A(p_pbr->signature) != PBR_SIGNATURE) { -- brelse(tmp_bh); -- exfat_bdev_close(sb); -- ret = -EFSCORRUPTED; -- goto out; -- } -- -- /* fill fs_struct */ -- for (i = 0; i < 53; i++) -- if (p_pbr->bpb[i]) -- break; -- -- if (i < 53) { -- /* Not sure how we'd get here, but complain if it does */ -- ret = -EINVAL; -- pr_info("EXFAT: Attempted to mount VFAT filesystem\n"); -- goto out; -- } else { -- ret = exfat_mount(sb, p_pbr); -- } -- -- brelse(tmp_bh); -- -- if (ret) { -- exfat_bdev_close(sb); -- goto out; -- } -- -- ret = load_alloc_bitmap(sb); -- if (ret) { -- exfat_bdev_close(sb); -- goto out; -- } -- ret = load_upcase_table(sb); -- if (ret) { -- free_alloc_bitmap(sb); -- exfat_bdev_close(sb); -- goto out; -- } -- -- if (p_fs->dev_ejected) { -- free_upcase_table(sb); -- free_alloc_bitmap(sb); -- exfat_bdev_close(sb); -- ret = -EIO; -- goto out; -- } -- -- pr_info("[EXFAT] mounted successfully\n"); -- --out: -- mutex_unlock(&z_mutex); -- -- return ret; --} -- --static int ffsUmountVol(struct super_block *sb) --{ -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- int err = 0; -- -- pr_info("[EXFAT] trying to unmount...\n"); -- -- mutex_lock(&z_mutex); -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- fs_sync(sb, true); -- fs_set_vol_flags(sb, VOL_CLEAN); -- -- free_upcase_table(sb); -- free_alloc_bitmap(sb); -- -- exfat_fat_release_all(sb); -- exfat_buf_release_all(sb); -- -- /* close the block device */ -- exfat_bdev_close(sb); -- -- if (p_fs->dev_ejected) { -- pr_info("[EXFAT] unmounted with media errors. Device is already ejected.\n"); -- err = -EIO; -- } -- -- exfat_buf_shutdown(sb); -- -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- mutex_unlock(&z_mutex); -- -- pr_info("[EXFAT] unmounted successfully\n"); -- -- return err; --} -- --static int ffsGetVolInfo(struct super_block *sb, struct vol_info_t *info) --{ -- int err = 0; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- /* check the validity of pointer parameters */ -- if (!info) -- return -EINVAL; -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- if (p_fs->used_clusters == UINT_MAX) -- p_fs->used_clusters = exfat_count_used_clusters(sb); -- -- info->FatType = p_fs->vol_type; -- info->ClusterSize = p_fs->cluster_size; -- info->NumClusters = p_fs->num_clusters - 2; /* clu 0 & 1 */ -- info->UsedClusters = p_fs->used_clusters; -- info->FreeClusters = info->NumClusters - info->UsedClusters; -- -- if (p_fs->dev_ejected) -- err = -EIO; -- -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- return err; --} -- --static int ffsSyncVol(struct super_block *sb, bool do_sync) --{ -- int err = 0; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- /* synchronize the file system */ -- fs_sync(sb, do_sync); -- fs_set_vol_flags(sb, VOL_CLEAN); -- -- if (p_fs->dev_ejected) -- err = -EIO; -- -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- return err; --} -- --/*----------------------------------------------------------------------*/ --/* File Operation Functions */ --/*----------------------------------------------------------------------*/ -- --static int ffsLookupFile(struct inode *inode, char *path, struct file_id_t *fid) --{ -- int ret, dentry, num_entries; -- struct chain_t dir; -- struct uni_name_t uni_name; -- struct dos_name_t dos_name; -- struct dentry_t *ep, *ep2; -- struct entry_set_cache_t *es = NULL; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- pr_debug("%s entered\n", __func__); -- -- /* check the validity of pointer parameters */ -- if (!fid || !path || (*path == '\0')) -- return -EINVAL; -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- /* check the validity of directory name in the given pathname */ -- ret = resolve_path(inode, path, &dir, &uni_name); -- if (ret) -- goto out; -- -- ret = get_num_entries_and_dos_name(sb, &dir, &uni_name, &num_entries, -- &dos_name); -- if (ret) -- goto out; -- -- /* search the file name for directories */ -- dentry = exfat_find_dir_entry(sb, &dir, &uni_name, num_entries, -- &dos_name, TYPE_ALL); -- if (dentry < -1) { -- ret = -ENOENT; -- goto out; -- } -- -- fid->dir.dir = dir.dir; -- fid->dir.size = dir.size; -- fid->dir.flags = dir.flags; -- fid->entry = dentry; -- -- if (dentry == -1) { -- fid->type = TYPE_DIR; -- fid->rwoffset = 0; -- fid->hint_last_off = -1; -- -- fid->attr = ATTR_SUBDIR; -- fid->flags = 0x01; -- fid->size = 0; -- fid->start_clu = p_fs->root_dir; -- } else { -- es = get_entry_set_in_dir(sb, &dir, dentry, -- ES_2_ENTRIES, &ep); -- if (!es) { -- ret = -ENOENT; -- goto out; -- } -- ep2 = ep + 1; -- -- fid->type = exfat_get_entry_type(ep); -- fid->rwoffset = 0; -- fid->hint_last_off = -1; -- fid->attr = exfat_get_entry_attr(ep); -- -- fid->size = exfat_get_entry_size(ep2); -- if ((fid->type == TYPE_FILE) && (fid->size == 0)) { -- fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; -- fid->start_clu = CLUSTER_32(~0); -- } else { -- fid->flags = exfat_get_entry_flag(ep2); -- fid->start_clu = exfat_get_entry_clu0(ep2); -- } -- -- release_entry_set(es); -- } -- -- if (p_fs->dev_ejected) -- ret = -EIO; --out: -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- return ret; --} -- --static int ffsCreateFile(struct inode *inode, char *path, u8 mode, -- struct file_id_t *fid) --{ -- struct chain_t dir; -- struct uni_name_t uni_name; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- int ret = 0; -- -- /* check the validity of pointer parameters */ -- if (!fid || !path || (*path == '\0')) -- return -EINVAL; -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- /* check the validity of directory name in the given pathname */ -- ret = resolve_path(inode, path, &dir, &uni_name); -- if (ret) -- goto out; -- -- fs_set_vol_flags(sb, VOL_DIRTY); -- -- /* create a new file */ -- ret = create_file(inode, &dir, &uni_name, mode, fid); -- --#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC -- fs_sync(sb, true); -- fs_set_vol_flags(sb, VOL_CLEAN); --#endif -- -- if (p_fs->dev_ejected) -- ret = -EIO; -- --out: -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- return ret; --} -- --static int ffsReadFile(struct inode *inode, struct file_id_t *fid, void *buffer, -- u64 count, u64 *rcount) --{ -- s32 offset, sec_offset, clu_offset; -- u32 clu; -- int ret = 0; -- sector_t LogSector; -- u64 oneblkread, read_bytes; -- struct buffer_head *tmp_bh = NULL; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- /* check the validity of the given file id */ -- if (!fid) -- return -EINVAL; -- -- /* check the validity of pointer parameters */ -- if (!buffer) -- return -EINVAL; -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- /* check if the given file ID is opened */ -- if (fid->type != TYPE_FILE) { -- ret = -EPERM; -- goto out; -- } -- -- if (fid->rwoffset > fid->size) -- fid->rwoffset = fid->size; -- -- if (count > (fid->size - fid->rwoffset)) -- count = fid->size - fid->rwoffset; -- -- if (count == 0) { -- if (rcount) -- *rcount = 0; -- ret = 0; -- goto out; -- } -- -- read_bytes = 0; -- -- while (count > 0) { -- clu_offset = (s32)(fid->rwoffset >> p_fs->cluster_size_bits); -- clu = fid->start_clu; -- -- if (fid->flags == 0x03) { -- clu += clu_offset; -- } else { -- /* hint information */ -- if ((clu_offset > 0) && (fid->hint_last_off > 0) && -- (clu_offset >= fid->hint_last_off)) { -- clu_offset -= fid->hint_last_off; -- clu = fid->hint_last_clu; -- } -- -- while (clu_offset > 0) { -- /* clu = exfat_fat_read(sb, clu); */ -- if (exfat_fat_read(sb, clu, &clu) == -1) { -- ret = -EIO; -- goto out; -- } -- -- clu_offset--; -- } -- } -- -- /* hint information */ -- fid->hint_last_off = (s32)(fid->rwoffset >> -- p_fs->cluster_size_bits); -- fid->hint_last_clu = clu; -- -- /* byte offset in cluster */ -- offset = (s32)(fid->rwoffset & (p_fs->cluster_size - 1)); -- -- /* sector offset in cluster */ -- sec_offset = offset >> p_bd->sector_size_bits; -- -- /* byte offset in sector */ -- offset &= p_bd->sector_size_mask; -- -- LogSector = START_SECTOR(clu) + sec_offset; -- -- oneblkread = (u64)(p_bd->sector_size - offset); -- if (oneblkread > count) -- oneblkread = count; -- -- if ((offset == 0) && (oneblkread == p_bd->sector_size)) { -- if (sector_read(sb, LogSector, &tmp_bh, 1) != -- 0) -- goto err_out; -- memcpy((char *)buffer + read_bytes, -- (char *)tmp_bh->b_data, (s32)oneblkread); -- } else { -- if (sector_read(sb, LogSector, &tmp_bh, 1) != -- 0) -- goto err_out; -- memcpy((char *)buffer + read_bytes, -- (char *)tmp_bh->b_data + offset, -- (s32)oneblkread); -- } -- count -= oneblkread; -- read_bytes += oneblkread; -- fid->rwoffset += oneblkread; -- } -- brelse(tmp_bh); -- --/* How did this ever work and not leak a brlse()?? */ --err_out: -- /* set the size of read bytes */ -- if (rcount) -- *rcount = read_bytes; -- -- if (p_fs->dev_ejected) -- ret = -EIO; -- --out: -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- return ret; --} -- --static int ffsWriteFile(struct inode *inode, struct file_id_t *fid, -- void *buffer, u64 count, u64 *wcount) --{ -- bool modified = false; -- s32 offset, sec_offset, clu_offset; -- s32 num_clusters, num_alloc, num_alloced = (s32)~0; -- int ret = 0; -- u32 clu, last_clu; -- sector_t LogSector; -- u64 oneblkwrite, write_bytes; -- struct chain_t new_clu; -- struct timestamp_t tm; -- struct dentry_t *ep, *ep2; -- struct entry_set_cache_t *es = NULL; -- struct buffer_head *tmp_bh = NULL; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- /* check the validity of the given file id */ -- if (!fid) -- return -EINVAL; -- -- /* check the validity of pointer parameters */ -- if (!buffer) -- return -EINVAL; -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- /* check if the given file ID is opened */ -- if (fid->type != TYPE_FILE) { -- ret = -EPERM; -- goto out; -- } -- -- if (fid->rwoffset > fid->size) -- fid->rwoffset = fid->size; -- -- if (count == 0) { -- if (wcount) -- *wcount = 0; -- ret = 0; -- goto out; -- } -- -- fs_set_vol_flags(sb, VOL_DIRTY); -- -- if (fid->size == 0) -- num_clusters = 0; -- else -- num_clusters = (s32)((fid->size - 1) >> -- p_fs->cluster_size_bits) + 1; -- -- write_bytes = 0; -- -- while (count > 0) { -- clu_offset = (s32)(fid->rwoffset >> p_fs->cluster_size_bits); -- clu = fid->start_clu; -- last_clu = fid->start_clu; -- -- if (fid->flags == 0x03) { -- if ((clu_offset > 0) && (clu != CLUSTER_32(~0))) { -- last_clu += clu_offset - 1; -- -- if (clu_offset == num_clusters) -- clu = CLUSTER_32(~0); -- else -- clu += clu_offset; -- } -- } else { -- /* hint information */ -- if ((clu_offset > 0) && (fid->hint_last_off > 0) && -- (clu_offset >= fid->hint_last_off)) { -- clu_offset -= fid->hint_last_off; -- clu = fid->hint_last_clu; -- } -- -- while ((clu_offset > 0) && (clu != CLUSTER_32(~0))) { -- last_clu = clu; -- /* clu = exfat_fat_read(sb, clu); */ -- if (exfat_fat_read(sb, clu, &clu) == -1) { -- ret = -EIO; -- goto out; -- } -- clu_offset--; -- } -- } -- -- if (clu == CLUSTER_32(~0)) { -- num_alloc = (s32)((count - 1) >> -- p_fs->cluster_size_bits) + 1; -- new_clu.dir = (last_clu == CLUSTER_32(~0)) ? -- CLUSTER_32(~0) : last_clu + 1; -- new_clu.size = 0; -- new_clu.flags = fid->flags; -- -- /* (1) allocate a chain of clusters */ -- num_alloced = exfat_alloc_cluster(sb, -- num_alloc, -- &new_clu); -- if (num_alloced == 0) -- break; -- if (num_alloced < 0) { -- ret = num_alloced; -- goto out; -- } -- -- /* (2) append to the FAT chain */ -- if (last_clu == CLUSTER_32(~0)) { -- if (new_clu.flags == 0x01) -- fid->flags = 0x01; -- fid->start_clu = new_clu.dir; -- modified = true; -- } else { -- if (new_clu.flags != fid->flags) { -- exfat_chain_cont_cluster(sb, -- fid->start_clu, -- num_clusters); -- fid->flags = 0x01; -- modified = true; -- } -- if (new_clu.flags == 0x01) -- exfat_fat_write(sb, last_clu, new_clu.dir); -- } -- -- num_clusters += num_alloced; -- clu = new_clu.dir; -- } -- -- /* hint information */ -- fid->hint_last_off = (s32)(fid->rwoffset >> -- p_fs->cluster_size_bits); -- fid->hint_last_clu = clu; -- -- /* byte offset in cluster */ -- offset = (s32)(fid->rwoffset & (p_fs->cluster_size - 1)); -- -- /* sector offset in cluster */ -- sec_offset = offset >> p_bd->sector_size_bits; -- -- /* byte offset in sector */ -- offset &= p_bd->sector_size_mask; -- -- LogSector = START_SECTOR(clu) + sec_offset; -- -- oneblkwrite = (u64)(p_bd->sector_size - offset); -- if (oneblkwrite > count) -- oneblkwrite = count; -- -- if ((offset == 0) && (oneblkwrite == p_bd->sector_size)) { -- if (sector_read(sb, LogSector, &tmp_bh, 0) != -- 0) -- goto err_out; -- memcpy((char *)tmp_bh->b_data, -- (char *)buffer + write_bytes, (s32)oneblkwrite); -- if (sector_write(sb, LogSector, tmp_bh, 0) != -- 0) { -- brelse(tmp_bh); -- goto err_out; -- } -- } else { -- if ((offset > 0) || -- ((fid->rwoffset + oneblkwrite) < fid->size)) { -- if (sector_read(sb, LogSector, &tmp_bh, 1) != -- 0) -- goto err_out; -- } else { -- if (sector_read(sb, LogSector, &tmp_bh, 0) != -- 0) -- goto err_out; -- } -- -- memcpy((char *)tmp_bh->b_data + offset, -- (char *)buffer + write_bytes, (s32)oneblkwrite); -- if (sector_write(sb, LogSector, tmp_bh, 0) != -- 0) { -- brelse(tmp_bh); -- goto err_out; -- } -- } -- -- count -= oneblkwrite; -- write_bytes += oneblkwrite; -- fid->rwoffset += oneblkwrite; -- -- fid->attr |= ATTR_ARCHIVE; -- -- if (fid->size < fid->rwoffset) { -- fid->size = fid->rwoffset; -- modified = true; -- } -- } -- -- brelse(tmp_bh); -- -- /* (3) update the direcoty entry */ -- es = get_entry_set_in_dir(sb, &fid->dir, fid->entry, -- ES_ALL_ENTRIES, &ep); -- if (!es) -- goto err_out; -- ep2 = ep + 1; -- -- exfat_set_entry_time(ep, tm_current(&tm), TM_MODIFY); -- exfat_set_entry_attr(ep, fid->attr); -- -- if (modified) { -- if (exfat_get_entry_flag(ep2) != fid->flags) -- exfat_set_entry_flag(ep2, fid->flags); -- -- if (exfat_get_entry_size(ep2) != fid->size) -- exfat_set_entry_size(ep2, fid->size); -- -- if (exfat_get_entry_clu0(ep2) != fid->start_clu) -- exfat_set_entry_clu0(ep2, fid->start_clu); -- } -- -- update_dir_checksum_with_entry_set(sb, es); -- release_entry_set(es); -- --#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC -- fs_sync(sb, true); -- fs_set_vol_flags(sb, VOL_CLEAN); --#endif -- --err_out: -- /* set the size of written bytes */ -- if (wcount) -- *wcount = write_bytes; -- -- if (num_alloced == 0) -- ret = -ENOSPC; -- -- else if (p_fs->dev_ejected) -- ret = -EIO; -- --out: -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- return ret; --} -- --static int ffsTruncateFile(struct inode *inode, u64 old_size, u64 new_size) --{ -- s32 num_clusters; -- u32 last_clu = CLUSTER_32(0); -- int ret = 0; -- struct chain_t clu; -- struct timestamp_t tm; -- struct dentry_t *ep, *ep2; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct file_id_t *fid = &(EXFAT_I(inode)->fid); -- struct entry_set_cache_t *es = NULL; -- -- pr_debug("%s entered (inode %p size %llu)\n", __func__, inode, -- new_size); -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- /* check if the given file ID is opened */ -- if (fid->type != TYPE_FILE) { -- ret = -EPERM; -- goto out; -- } -- -- if (fid->size != old_size) { -- pr_err("[EXFAT] truncate : can't skip it because of size-mismatch(old:%lld->fid:%lld).\n", -- old_size, fid->size); -- } -- -- if (old_size <= new_size) { -- ret = 0; -- goto out; -- } -- -- fs_set_vol_flags(sb, VOL_DIRTY); -- -- clu.dir = fid->start_clu; -- clu.size = (s32)((old_size - 1) >> p_fs->cluster_size_bits) + 1; -- clu.flags = fid->flags; -- -- if (new_size > 0) { -- num_clusters = (s32)((new_size - 1) >> -- p_fs->cluster_size_bits) + 1; -- -- if (clu.flags == 0x03) { -- clu.dir += num_clusters; -- } else { -- while (num_clusters > 0) { -- last_clu = clu.dir; -- if (exfat_fat_read(sb, clu.dir, &clu.dir) == -1) { -- ret = -EIO; -- goto out; -- } -- num_clusters--; -- } -- } -- -- clu.size -= num_clusters; -- } -- -- fid->size = new_size; -- fid->attr |= ATTR_ARCHIVE; -- if (new_size == 0) { -- fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; -- fid->start_clu = CLUSTER_32(~0); -- } -- -- /* (1) update the directory entry */ -- es = get_entry_set_in_dir(sb, &fid->dir, fid->entry, -- ES_ALL_ENTRIES, &ep); -- if (!es) { -- ret = -ENOENT; -- goto out; -- } -- ep2 = ep + 1; -- -- exfat_set_entry_time(ep, tm_current(&tm), TM_MODIFY); -- exfat_set_entry_attr(ep, fid->attr); -- -- exfat_set_entry_size(ep2, new_size); -- if (new_size == 0) { -- exfat_set_entry_flag(ep2, 0x01); -- exfat_set_entry_clu0(ep2, CLUSTER_32(0)); -- } -- -- update_dir_checksum_with_entry_set(sb, es); -- release_entry_set(es); -- -- /* (2) cut off from the FAT chain */ -- if (last_clu != CLUSTER_32(0)) { -- if (fid->flags == 0x01) -- exfat_fat_write(sb, last_clu, CLUSTER_32(~0)); -- } -- -- /* (3) free the clusters */ -- exfat_free_cluster(sb, &clu, 0); -- -- /* hint information */ -- fid->hint_last_off = -1; -- if (fid->rwoffset > fid->size) -- fid->rwoffset = fid->size; -- --#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC -- fs_sync(sb, true); -- fs_set_vol_flags(sb, VOL_CLEAN); --#endif -- -- if (p_fs->dev_ejected) -- ret = -EIO; -- --out: -- pr_debug("%s exited (%d)\n", __func__, ret); -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- return ret; --} -- --static void update_parent_info(struct file_id_t *fid, -- struct inode *parent_inode) --{ -- struct fs_info_t *p_fs = &(EXFAT_SB(parent_inode->i_sb)->fs_info); -- struct file_id_t *parent_fid = &(EXFAT_I(parent_inode)->fid); -- -- if (unlikely((parent_fid->flags != fid->dir.flags) || -- (parent_fid->size != -- (fid->dir.size << p_fs->cluster_size_bits)) || -- (parent_fid->start_clu != fid->dir.dir))) { -- fid->dir.dir = parent_fid->start_clu; -- fid->dir.flags = parent_fid->flags; -- fid->dir.size = ((parent_fid->size + (p_fs->cluster_size - 1)) -- >> p_fs->cluster_size_bits); -- } --} -- --static int ffsMoveFile(struct inode *old_parent_inode, struct file_id_t *fid, -- struct inode *new_parent_inode, struct dentry *new_dentry) --{ -- s32 ret; -- s32 dentry; -- struct chain_t olddir, newdir; -- struct chain_t *p_dir = NULL; -- struct uni_name_t uni_name; -- struct dentry_t *ep; -- struct super_block *sb = old_parent_inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- u8 *new_path = (u8 *)new_dentry->d_name.name; -- struct inode *new_inode = new_dentry->d_inode; -- int num_entries; -- struct file_id_t *new_fid = NULL; -- s32 new_entry = 0; -- -- /* check the validity of the given file id */ -- if (!fid) -- return -EINVAL; -- -- /* check the validity of pointer parameters */ -- if (!new_path || (*new_path == '\0')) -- return -EINVAL; -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- update_parent_info(fid, old_parent_inode); -- -- olddir.dir = fid->dir.dir; -- olddir.size = fid->dir.size; -- olddir.flags = fid->dir.flags; -- -- dentry = fid->entry; -- -- /* check if the old file is "." or ".." */ -- if (p_fs->vol_type != EXFAT) { -- if ((olddir.dir != p_fs->root_dir) && (dentry < 2)) { -- ret = -EPERM; -- goto out2; -- } -- } -- -- ep = get_entry_in_dir(sb, &olddir, dentry, NULL); -- if (!ep) { -- ret = -ENOENT; -- goto out2; -- } -- -- if (exfat_get_entry_attr(ep) & ATTR_READONLY) { -- ret = -EPERM; -- goto out2; -- } -- -- /* check whether new dir is existing directory and empty */ -- if (new_inode) { -- u32 entry_type; -- -- ret = -ENOENT; -- new_fid = &EXFAT_I(new_inode)->fid; -- -- update_parent_info(new_fid, new_parent_inode); -- -- p_dir = &new_fid->dir; -- new_entry = new_fid->entry; -- ep = get_entry_in_dir(sb, p_dir, new_entry, NULL); -- if (!ep) -- goto out; -- -- entry_type = exfat_get_entry_type(ep); -- -- if (entry_type == TYPE_DIR) { -- struct chain_t new_clu; -- -- new_clu.dir = new_fid->start_clu; -- new_clu.size = (s32)((new_fid->size - 1) >> -- p_fs->cluster_size_bits) + 1; -- new_clu.flags = new_fid->flags; -- -- if (!is_dir_empty(sb, &new_clu)) { -- ret = -EEXIST; -- goto out; -- } -- } -- } -- -- /* check the validity of directory name in the given new pathname */ -- ret = resolve_path(new_parent_inode, new_path, &newdir, &uni_name); -- if (ret) -- goto out2; -- -- fs_set_vol_flags(sb, VOL_DIRTY); -- -- if (olddir.dir == newdir.dir) -- ret = exfat_rename_file(new_parent_inode, &olddir, dentry, -- &uni_name, fid); -- else -- ret = move_file(new_parent_inode, &olddir, dentry, &newdir, -- &uni_name, fid); -- -- if ((ret == 0) && new_inode) { -- /* delete entries of new_dir */ -- ep = get_entry_in_dir(sb, p_dir, new_entry, NULL); -- if (!ep) -- goto out; -- -- num_entries = exfat_count_ext_entries(sb, p_dir, -- new_entry, ep); -- if (num_entries < 0) -- goto out; -- exfat_delete_dir_entry(sb, p_dir, new_entry, 0, -- num_entries + 1); -- } --out: --#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC -- fs_sync(sb, true); -- fs_set_vol_flags(sb, VOL_CLEAN); --#endif -- -- if (p_fs->dev_ejected) -- ret = -EIO; --out2: -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- return ret; --} -- --static int ffsRemoveFile(struct inode *inode, struct file_id_t *fid) --{ -- s32 dentry; -- int ret = 0; -- struct chain_t dir, clu_to_free; -- struct dentry_t *ep; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- /* check the validity of the given file id */ -- if (!fid) -- return -EINVAL; -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- dir.dir = fid->dir.dir; -- dir.size = fid->dir.size; -- dir.flags = fid->dir.flags; -- -- dentry = fid->entry; -- -- ep = get_entry_in_dir(sb, &dir, dentry, NULL); -- if (!ep) { -- ret = -ENOENT; -- goto out; -- } -- -- if (exfat_get_entry_attr(ep) & ATTR_READONLY) { -- ret = -EPERM; -- goto out; -- } -- fs_set_vol_flags(sb, VOL_DIRTY); -- -- /* (1) update the directory entry */ -- remove_file(inode, &dir, dentry); -- -- clu_to_free.dir = fid->start_clu; -- clu_to_free.size = (s32)((fid->size - 1) >> p_fs->cluster_size_bits) + 1; -- clu_to_free.flags = fid->flags; -- -- /* (2) free the clusters */ -- exfat_free_cluster(sb, &clu_to_free, 0); -- -- fid->size = 0; -- fid->start_clu = CLUSTER_32(~0); -- fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; -- --#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC -- fs_sync(sb, true); -- fs_set_vol_flags(sb, VOL_CLEAN); --#endif -- -- if (p_fs->dev_ejected) -- ret = -EIO; --out: -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- return ret; --} -- --#if 0 --/* Not currently wired up */ --static int ffsSetAttr(struct inode *inode, u32 attr) --{ -- u32 type; -- int ret = 0; -- sector_t sector = 0; -- struct dentry_t *ep; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct file_id_t *fid = &(EXFAT_I(inode)->fid); -- u8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0; -- struct entry_set_cache_t *es = NULL; -- -- if (fid->attr == attr) { -- if (p_fs->dev_ejected) -- return -EIO; -- return 0; -- } -- -- if (is_dir) { -- if ((fid->dir.dir == p_fs->root_dir) && -- (fid->entry == -1)) { -- if (p_fs->dev_ejected) -- return -EIO; -- return 0; -- } -- } -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- /* get the directory entry of given file */ -- es = get_entry_set_in_dir(sb, &fid->dir, fid->entry, -- ES_ALL_ENTRIES, &ep); -- if (!es) { -- ret = -ENOENT; -- goto out; -- } -- -- type = exfat_get_entry_type(ep); -- -- if (((type == TYPE_FILE) && (attr & ATTR_SUBDIR)) || -- ((type == TYPE_DIR) && (!(attr & ATTR_SUBDIR)))) { -- if (p_fs->dev_ejected) -- ret = -EIO; -- else -- ret = -EINVAL; -- -- release_entry_set(es); -- goto out; -- } -- -- fs_set_vol_flags(sb, VOL_DIRTY); -- -- /* set the file attribute */ -- fid->attr = attr; -- exfat_set_entry_attr(ep, attr); -- -- update_dir_checksum_with_entry_set(sb, es); -- release_entry_set(es); -- --#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC -- fs_sync(sb, true); -- fs_set_vol_flags(sb, VOL_CLEAN); --#endif -- -- if (p_fs->dev_ejected) -- ret = -EIO; --out: -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- return ret; --} --#endif -- --static int ffsReadStat(struct inode *inode, struct dir_entry_t *info) --{ -- s32 count; -- int ret = 0; -- struct chain_t dir; -- struct uni_name_t uni_name; -- struct timestamp_t tm; -- struct dentry_t *ep, *ep2; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct file_id_t *fid = &(EXFAT_I(inode)->fid); -- struct entry_set_cache_t *es = NULL; -- u8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0; -- -- pr_debug("%s entered\n", __func__); -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- if (is_dir) { -- if ((fid->dir.dir == p_fs->root_dir) && -- (fid->entry == -1)) { -- info->Attr = ATTR_SUBDIR; -- memset((char *)&info->CreateTimestamp, 0, -- sizeof(struct date_time_t)); -- memset((char *)&info->ModifyTimestamp, 0, -- sizeof(struct date_time_t)); -- memset((char *)&info->AccessTimestamp, 0, -- sizeof(struct date_time_t)); -- strcpy(info->ShortName, "."); -- strcpy(info->Name, "."); -- -- dir.dir = p_fs->root_dir; -- dir.flags = 0x01; -- -- if (p_fs->root_dir == CLUSTER_32(0)) { -- /* FAT16 root_dir */ -- info->Size = p_fs->dentries_in_root << -- DENTRY_SIZE_BITS; -- } else { -- info->Size = count_num_clusters(sb, &dir) << -- p_fs->cluster_size_bits; -- } -- -- count = count_dos_name_entries(sb, &dir, TYPE_DIR); -- if (count < 0) { -- ret = count; /* propagate error upward */ -- goto out; -- } -- info->NumSubdirs = count; -- -- if (p_fs->dev_ejected) -- ret = -EIO; -- goto out; -- } -- } -- -- /* get the directory entry of given file or directory */ -- es = get_entry_set_in_dir(sb, &fid->dir, fid->entry, -- ES_2_ENTRIES, &ep); -- if (!es) { -- ret = -ENOENT; -- goto out; -- } -- ep2 = ep + 1; -- -- /* set FILE_INFO structure using the acquired struct dentry_t */ -- info->Attr = exfat_get_entry_attr(ep); -- -- exfat_get_entry_time(ep, &tm, TM_CREATE); -- info->CreateTimestamp.Year = tm.year; -- info->CreateTimestamp.Month = tm.mon; -- info->CreateTimestamp.Day = tm.day; -- info->CreateTimestamp.Hour = tm.hour; -- info->CreateTimestamp.Minute = tm.min; -- info->CreateTimestamp.Second = tm.sec; -- info->CreateTimestamp.MilliSecond = 0; -- -- exfat_get_entry_time(ep, &tm, TM_MODIFY); -- info->ModifyTimestamp.Year = tm.year; -- info->ModifyTimestamp.Month = tm.mon; -- info->ModifyTimestamp.Day = tm.day; -- info->ModifyTimestamp.Hour = tm.hour; -- info->ModifyTimestamp.Minute = tm.min; -- info->ModifyTimestamp.Second = tm.sec; -- info->ModifyTimestamp.MilliSecond = 0; -- -- memset((char *)&info->AccessTimestamp, 0, sizeof(struct date_time_t)); -- -- *uni_name.name = 0x0; -- /* XXX this is very bad for exfat cuz name is already included in es. -- * API should be revised -- */ -- exfat_get_uni_name_from_ext_entry(sb, &fid->dir, fid->entry, -- uni_name.name); -- nls_uniname_to_cstring(sb, info->Name, &uni_name); -- -- info->NumSubdirs = 2; -- -- info->Size = exfat_get_entry_size(ep2); -- -- release_entry_set(es); -- -- if (is_dir) { -- dir.dir = fid->start_clu; -- dir.flags = 0x01; -- -- if (info->Size == 0) -- info->Size = (u64)count_num_clusters(sb, &dir) << -- p_fs->cluster_size_bits; -- -- count = count_dos_name_entries(sb, &dir, TYPE_DIR); -- if (count < 0) { -- ret = count; /* propagate error upward */ -- goto out; -- } -- info->NumSubdirs += count; -- } -- -- if (p_fs->dev_ejected) -- ret = -EIO; -- --out: -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- pr_debug("%s exited successfully\n", __func__); -- return ret; --} -- --static int ffsWriteStat(struct inode *inode, struct dir_entry_t *info) --{ -- int ret = 0; -- struct timestamp_t tm; -- struct dentry_t *ep, *ep2; -- struct entry_set_cache_t *es = NULL; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct file_id_t *fid = &(EXFAT_I(inode)->fid); -- u8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0; -- -- pr_debug("%s entered (inode %p info %p\n", __func__, inode, info); -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- if (is_dir) { -- if ((fid->dir.dir == p_fs->root_dir) && -- (fid->entry == -1)) { -- if (p_fs->dev_ejected) -- ret = -EIO; -- ret = 0; -- goto out; -- } -- } -- -- fs_set_vol_flags(sb, VOL_DIRTY); -- -- /* get the directory entry of given file or directory */ -- es = get_entry_set_in_dir(sb, &fid->dir, fid->entry, -- ES_ALL_ENTRIES, &ep); -- if (!es) { -- ret = -ENOENT; -- goto out; -- } -- ep2 = ep + 1; -- -- exfat_set_entry_attr(ep, info->Attr); -- -- /* set FILE_INFO structure using the acquired struct dentry_t */ -- tm.sec = info->CreateTimestamp.Second; -- tm.min = info->CreateTimestamp.Minute; -- tm.hour = info->CreateTimestamp.Hour; -- tm.day = info->CreateTimestamp.Day; -- tm.mon = info->CreateTimestamp.Month; -- tm.year = info->CreateTimestamp.Year; -- exfat_set_entry_time(ep, &tm, TM_CREATE); -- -- tm.sec = info->ModifyTimestamp.Second; -- tm.min = info->ModifyTimestamp.Minute; -- tm.hour = info->ModifyTimestamp.Hour; -- tm.day = info->ModifyTimestamp.Day; -- tm.mon = info->ModifyTimestamp.Month; -- tm.year = info->ModifyTimestamp.Year; -- exfat_set_entry_time(ep, &tm, TM_MODIFY); -- -- exfat_set_entry_size(ep2, info->Size); -- -- update_dir_checksum_with_entry_set(sb, es); -- release_entry_set(es); -- -- if (p_fs->dev_ejected) -- ret = -EIO; -- --out: -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- pr_debug("%s exited (%d)\n", __func__, ret); -- -- return ret; --} -- --static int ffsMapCluster(struct inode *inode, s32 clu_offset, u32 *clu) --{ -- s32 num_clusters, num_alloced; -- bool modified = false; -- u32 last_clu; -- int ret = 0; -- struct chain_t new_clu; -- struct dentry_t *ep; -- struct entry_set_cache_t *es = NULL; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct file_id_t *fid = &(EXFAT_I(inode)->fid); -- -- /* check the validity of pointer parameters */ -- if (!clu) -- return -EINVAL; -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- fid->rwoffset = (s64)(clu_offset) << p_fs->cluster_size_bits; -- -- if (EXFAT_I(inode)->mmu_private == 0) -- num_clusters = 0; -- else -- num_clusters = (s32)((EXFAT_I(inode)->mmu_private - 1) >> -- p_fs->cluster_size_bits) + 1; -- -- *clu = last_clu = fid->start_clu; -- -- if (fid->flags == 0x03) { -- if ((clu_offset > 0) && (*clu != CLUSTER_32(~0))) { -- last_clu += clu_offset - 1; -- -- if (clu_offset == num_clusters) -- *clu = CLUSTER_32(~0); -- else -- *clu += clu_offset; -- } -- } else { -- /* hint information */ -- if ((clu_offset > 0) && (fid->hint_last_off > 0) && -- (clu_offset >= fid->hint_last_off)) { -- clu_offset -= fid->hint_last_off; -- *clu = fid->hint_last_clu; -- } -- -- while ((clu_offset > 0) && (*clu != CLUSTER_32(~0))) { -- last_clu = *clu; -- if (exfat_fat_read(sb, *clu, clu) == -1) { -- ret = -EIO; -- goto out; -- } -- clu_offset--; -- } -- } -- -- if (*clu == CLUSTER_32(~0)) { -- fs_set_vol_flags(sb, VOL_DIRTY); -- -- new_clu.dir = (last_clu == CLUSTER_32(~0)) ? CLUSTER_32(~0) : -- last_clu + 1; -- new_clu.size = 0; -- new_clu.flags = fid->flags; -- -- /* (1) allocate a cluster */ -- num_alloced = exfat_alloc_cluster(sb, 1, &new_clu); -- if (num_alloced < 0) { -- ret = -EIO; -- goto out; -- } else if (num_alloced == 0) { -- ret = -ENOSPC; -- goto out; -- } -- -- /* (2) append to the FAT chain */ -- if (last_clu == CLUSTER_32(~0)) { -- if (new_clu.flags == 0x01) -- fid->flags = 0x01; -- fid->start_clu = new_clu.dir; -- modified = true; -- } else { -- if (new_clu.flags != fid->flags) { -- exfat_chain_cont_cluster(sb, fid->start_clu, -- num_clusters); -- fid->flags = 0x01; -- modified = true; -- } -- if (new_clu.flags == 0x01) -- exfat_fat_write(sb, last_clu, new_clu.dir); -- } -- -- num_clusters += num_alloced; -- *clu = new_clu.dir; -- -- es = get_entry_set_in_dir(sb, &fid->dir, fid->entry, -- ES_ALL_ENTRIES, &ep); -- if (!es) { -- ret = -ENOENT; -- goto out; -- } -- /* get stream entry */ -- ep++; -- -- /* (3) update directory entry */ -- if (modified) { -- if (exfat_get_entry_flag(ep) != fid->flags) -- exfat_set_entry_flag(ep, fid->flags); -- -- if (exfat_get_entry_clu0(ep) != fid->start_clu) -- exfat_set_entry_clu0(ep, fid->start_clu); -- } -- -- update_dir_checksum_with_entry_set(sb, es); -- release_entry_set(es); -- -- /* add number of new blocks to inode */ -- inode->i_blocks += num_alloced << (p_fs->cluster_size_bits - 9); -- } -- -- /* hint information */ -- fid->hint_last_off = (s32)(fid->rwoffset >> p_fs->cluster_size_bits); -- fid->hint_last_clu = *clu; -- -- if (p_fs->dev_ejected) -- ret = -EIO; -- --out: -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- return ret; --} -- --/*----------------------------------------------------------------------*/ --/* Directory Operation Functions */ --/*----------------------------------------------------------------------*/ -- --static int ffsCreateDir(struct inode *inode, char *path, struct file_id_t *fid) --{ -- int ret = 0; -- struct chain_t dir; -- struct uni_name_t uni_name; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- pr_debug("%s entered\n", __func__); -- -- /* check the validity of pointer parameters */ -- if (!fid || !path || (*path == '\0')) -- return -EINVAL; -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- /* check the validity of directory name in the given old pathname */ -- ret = resolve_path(inode, path, &dir, &uni_name); -- if (ret) -- goto out; -- -- fs_set_vol_flags(sb, VOL_DIRTY); -- -- ret = create_dir(inode, &dir, &uni_name, fid); -- --#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC -- fs_sync(sb, true); -- fs_set_vol_flags(sb, VOL_CLEAN); --#endif -- -- if (p_fs->dev_ejected) -- ret = -EIO; --out: -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- return ret; --} -- --static int ffsReadDir(struct inode *inode, struct dir_entry_t *dir_entry) --{ -- int i, dentry, clu_offset; -- int ret = 0; -- s32 dentries_per_clu, dentries_per_clu_bits = 0; -- u32 type; -- sector_t sector; -- struct chain_t dir, clu; -- struct uni_name_t uni_name; -- struct timestamp_t tm; -- struct dentry_t *ep; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct file_id_t *fid = &(EXFAT_I(inode)->fid); -- -- /* check the validity of pointer parameters */ -- if (!dir_entry) -- return -EINVAL; -- -- /* check if the given file ID is opened */ -- if (fid->type != TYPE_DIR) -- return -ENOTDIR; -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- if (fid->entry == -1) { -- dir.dir = p_fs->root_dir; -- dir.flags = 0x01; -- } else { -- dir.dir = fid->start_clu; -- dir.size = (s32)(fid->size >> p_fs->cluster_size_bits); -- dir.flags = fid->flags; -- } -- -- dentry = (s32)fid->rwoffset; -- -- if (dir.dir == CLUSTER_32(0)) { -- /* FAT16 root_dir */ -- dentries_per_clu = p_fs->dentries_in_root; -- -- if (dentry == dentries_per_clu) { -- clu.dir = CLUSTER_32(~0); -- } else { -- clu.dir = dir.dir; -- clu.size = dir.size; -- clu.flags = dir.flags; -- } -- } else { -- dentries_per_clu = p_fs->dentries_per_clu; -- dentries_per_clu_bits = ilog2(dentries_per_clu); -- -- clu_offset = dentry >> dentries_per_clu_bits; -- clu.dir = dir.dir; -- clu.size = dir.size; -- clu.flags = dir.flags; -- -- if (clu.flags == 0x03) { -- clu.dir += clu_offset; -- clu.size -= clu_offset; -- } else { -- /* hint_information */ -- if ((clu_offset > 0) && (fid->hint_last_off > 0) && -- (clu_offset >= fid->hint_last_off)) { -- clu_offset -= fid->hint_last_off; -- clu.dir = fid->hint_last_clu; -- } -- -- while (clu_offset > 0) { -- /* clu.dir = exfat_fat_read(sb, clu.dir); */ -- if (exfat_fat_read(sb, clu.dir, &clu.dir) == -1) { -- ret = -EIO; -- goto out; -- } -- clu_offset--; -- } -- } -- } -- -- while (clu.dir != CLUSTER_32(~0)) { -- if (p_fs->dev_ejected) -- break; -- -- if (dir.dir == CLUSTER_32(0)) /* FAT16 root_dir */ -- i = dentry % dentries_per_clu; -- else -- i = dentry & (dentries_per_clu - 1); -- -- for ( ; i < dentries_per_clu; i++, dentry++) { -- ep = get_entry_in_dir(sb, &clu, i, §or); -- if (!ep) { -- ret = -ENOENT; -- goto out; -- } -- type = exfat_get_entry_type(ep); -- -- if (type == TYPE_UNUSED) -- break; -- -- if ((type != TYPE_FILE) && (type != TYPE_DIR)) -- continue; -- -- exfat_buf_lock(sb, sector); -- dir_entry->Attr = exfat_get_entry_attr(ep); -- -- exfat_get_entry_time(ep, &tm, TM_CREATE); -- dir_entry->CreateTimestamp.Year = tm.year; -- dir_entry->CreateTimestamp.Month = tm.mon; -- dir_entry->CreateTimestamp.Day = tm.day; -- dir_entry->CreateTimestamp.Hour = tm.hour; -- dir_entry->CreateTimestamp.Minute = tm.min; -- dir_entry->CreateTimestamp.Second = tm.sec; -- dir_entry->CreateTimestamp.MilliSecond = 0; -- -- exfat_get_entry_time(ep, &tm, TM_MODIFY); -- dir_entry->ModifyTimestamp.Year = tm.year; -- dir_entry->ModifyTimestamp.Month = tm.mon; -- dir_entry->ModifyTimestamp.Day = tm.day; -- dir_entry->ModifyTimestamp.Hour = tm.hour; -- dir_entry->ModifyTimestamp.Minute = tm.min; -- dir_entry->ModifyTimestamp.Second = tm.sec; -- dir_entry->ModifyTimestamp.MilliSecond = 0; -- -- memset((char *)&dir_entry->AccessTimestamp, 0, -- sizeof(struct date_time_t)); -- -- *uni_name.name = 0x0; -- exfat_get_uni_name_from_ext_entry(sb, &dir, dentry, -- uni_name.name); -- nls_uniname_to_cstring(sb, dir_entry->Name, &uni_name); -- exfat_buf_unlock(sb, sector); -- -- ep = get_entry_in_dir(sb, &clu, i + 1, NULL); -- if (!ep) { -- ret = -ENOENT; -- goto out; -- } -- -- dir_entry->Size = exfat_get_entry_size(ep); -- -- /* hint information */ -- if (dir.dir == CLUSTER_32(0)) { /* FAT16 root_dir */ -- } else { -- fid->hint_last_off = dentry >> -- dentries_per_clu_bits; -- fid->hint_last_clu = clu.dir; -- } -- -- fid->rwoffset = (s64)(++dentry); -- -- if (p_fs->dev_ejected) -- ret = -EIO; -- goto out; -- } -- -- if (dir.dir == CLUSTER_32(0)) -- break; /* FAT16 root_dir */ -- -- if (clu.flags == 0x03) { -- if ((--clu.size) > 0) -- clu.dir++; -- else -- clu.dir = CLUSTER_32(~0); -- } else { -- /* clu.dir = exfat_fat_read(sb, clu.dir); */ -- if (exfat_fat_read(sb, clu.dir, &clu.dir) == -1) { -- ret = -EIO; -- goto out; -- } -- } -- } -- -- *dir_entry->Name = '\0'; -- -- fid->rwoffset = (s64)(++dentry); -- -- if (p_fs->dev_ejected) -- ret = -EIO; -- --out: -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- return ret; --} -- --static int ffsRemoveDir(struct inode *inode, struct file_id_t *fid) --{ -- s32 dentry; -- int ret = 0; -- struct chain_t dir, clu_to_free; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- /* check the validity of the given file id */ -- if (!fid) -- return -EINVAL; -- -- dir.dir = fid->dir.dir; -- dir.size = fid->dir.size; -- dir.flags = fid->dir.flags; -- -- dentry = fid->entry; -- -- /* check if the file is "." or ".." */ -- if (p_fs->vol_type != EXFAT) { -- if ((dir.dir != p_fs->root_dir) && (dentry < 2)) -- return -EPERM; -- } -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- clu_to_free.dir = fid->start_clu; -- clu_to_free.size = (s32)((fid->size - 1) >> p_fs->cluster_size_bits) + 1; -- clu_to_free.flags = fid->flags; -- -- if (!is_dir_empty(sb, &clu_to_free)) { -- ret = -ENOTEMPTY; -- goto out; -- } -- -- fs_set_vol_flags(sb, VOL_DIRTY); -- -- /* (1) update the directory entry */ -- remove_file(inode, &dir, dentry); -- -- /* (2) free the clusters */ -- exfat_free_cluster(sb, &clu_to_free, 1); -- -- fid->size = 0; -- fid->start_clu = CLUSTER_32(~0); -- fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; -- --#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC -- fs_sync(sb, true); -- fs_set_vol_flags(sb, VOL_CLEAN); --#endif -- -- if (p_fs->dev_ejected) -- ret = -EIO; -- --out: -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- return ret; --} -- --/*======================================================================*/ --/* Directory Entry Operations */ --/*======================================================================*/ -- --static int exfat_readdir(struct file *filp, struct dir_context *ctx) --{ -- struct inode *inode = file_inode(filp); -- struct super_block *sb = inode->i_sb; -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- struct fs_info_t *p_fs = &sbi->fs_info; -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- struct dir_entry_t de; -- unsigned long inum; -- loff_t cpos; -- int err = 0; -- -- __lock_super(sb); -- -- cpos = ctx->pos; -- /* Fake . and .. for the root directory. */ -- if ((p_fs->vol_type == EXFAT) || (inode->i_ino == EXFAT_ROOT_INO)) { -- while (cpos < 2) { -- if (inode->i_ino == EXFAT_ROOT_INO) -- inum = EXFAT_ROOT_INO; -- else if (cpos == 0) -- inum = inode->i_ino; -- else /* (cpos == 1) */ -- inum = parent_ino(filp->f_path.dentry); -- -- if (!dir_emit_dots(filp, ctx)) -- goto out; -- cpos++; -- ctx->pos++; -- } -- if (cpos == 2) -- cpos = 0; -- } -- if (cpos & (DENTRY_SIZE - 1)) { -- err = -ENOENT; -- goto out; -- } -- --get_new: -- EXFAT_I(inode)->fid.size = i_size_read(inode); -- EXFAT_I(inode)->fid.rwoffset = cpos >> DENTRY_SIZE_BITS; -- -- err = ffsReadDir(inode, &de); -- if (err) { -- /* at least we tried to read a sector -- * move cpos to next sector position (should be aligned) -- */ -- if (err == -EIO) { -- cpos += 1 << p_bd->sector_size_bits; -- cpos &= ~((1 << p_bd->sector_size_bits) - 1); -- } -- -- goto end_of_dir; -- } -- -- cpos = EXFAT_I(inode)->fid.rwoffset << DENTRY_SIZE_BITS; -- -- if (!de.Name[0]) -- goto end_of_dir; -- -- if (!memcmp(de.ShortName, DOS_CUR_DIR_NAME, DOS_NAME_LENGTH)) { -- inum = inode->i_ino; -- } else if (!memcmp(de.ShortName, DOS_PAR_DIR_NAME, DOS_NAME_LENGTH)) { -- inum = parent_ino(filp->f_path.dentry); -- } else { -- loff_t i_pos = ((loff_t)EXFAT_I(inode)->fid.start_clu << 32) | -- ((EXFAT_I(inode)->fid.rwoffset - 1) & 0xffffffff); -- struct inode *tmp = exfat_iget(sb, i_pos); -- -- if (tmp) { -- inum = tmp->i_ino; -- iput(tmp); -- } else { -- inum = iunique(sb, EXFAT_ROOT_INO); -- } -- } -- -- if (!dir_emit(ctx, de.Name, strlen(de.Name), inum, -- (de.Attr & ATTR_SUBDIR) ? DT_DIR : DT_REG)) -- goto out; -- -- ctx->pos = cpos; -- goto get_new; -- --end_of_dir: -- ctx->pos = cpos; --out: -- __unlock_super(sb); -- return err; --} -- --static int exfat_ioctl_volume_id(struct inode *dir) --{ -- struct super_block *sb = dir->i_sb; -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- struct fs_info_t *p_fs = &sbi->fs_info; -- -- return p_fs->vol_id; --} -- --static long exfat_generic_ioctl(struct file *filp, unsigned int cmd, -- unsigned long arg) --{ -- struct inode *inode = filp->f_path.dentry->d_inode; --#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG -- unsigned int flags; --#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */ -- -- switch (cmd) { -- case EXFAT_IOCTL_GET_VOLUME_ID: -- return exfat_ioctl_volume_id(inode); --#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG -- case EXFAT_IOC_GET_DEBUGFLAGS: { -- struct super_block *sb = inode->i_sb; -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- -- flags = sbi->debug_flags; -- return put_user(flags, (int __user *)arg); -- } -- case EXFAT_IOC_SET_DEBUGFLAGS: { -- struct super_block *sb = inode->i_sb; -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- -- if (!capable(CAP_SYS_ADMIN)) -- return -EPERM; -- -- if (get_user(flags, (int __user *)arg)) -- return -EFAULT; -- -- __lock_super(sb); -- sbi->debug_flags = flags; -- __unlock_super(sb); -- -- return 0; -- } --#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */ -- default: -- return -ENOTTY; /* Inappropriate ioctl for device */ -- } --} -- --static const struct file_operations exfat_dir_operations = { -- .llseek = generic_file_llseek, -- .read = generic_read_dir, -- .iterate = exfat_readdir, -- .unlocked_ioctl = exfat_generic_ioctl, -- .fsync = generic_file_fsync, --}; -- --static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, -- bool excl) --{ -- struct super_block *sb = dir->i_sb; -- struct timespec64 curtime; -- struct inode *inode; -- struct file_id_t fid; -- loff_t i_pos; -- int err; -- -- __lock_super(sb); -- -- pr_debug("%s entered\n", __func__); -- -- err = ffsCreateFile(dir, (u8 *)dentry->d_name.name, FM_REGULAR, &fid); -- if (err) -- goto out; -- -- INC_IVERSION(dir); -- curtime = current_time(dir); -- dir->i_ctime = curtime; -- dir->i_mtime = curtime; -- dir->i_atime = curtime; -- if (IS_DIRSYNC(dir)) -- (void)exfat_sync_inode(dir); -- else -- mark_inode_dirty(dir); -- -- i_pos = ((loff_t)fid.dir.dir << 32) | (fid.entry & 0xffffffff); -- -- inode = exfat_build_inode(sb, &fid, i_pos); -- if (IS_ERR(inode)) { -- err = PTR_ERR(inode); -- goto out; -- } -- INC_IVERSION(inode); -- curtime = current_time(inode); -- inode->i_mtime = curtime; -- inode->i_atime = curtime; -- inode->i_ctime = curtime; -- /* -- * timestamp is already written, so mark_inode_dirty() is unnecessary. -- */ -- -- dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); -- d_instantiate(dentry, inode); -- --out: -- __unlock_super(sb); -- pr_debug("%s exited\n", __func__); -- return err; --} -- --static int exfat_find(struct inode *dir, struct qstr *qname, -- struct file_id_t *fid) --{ -- int err; -- -- if (qname->len == 0) -- return -ENOENT; -- -- err = ffsLookupFile(dir, (u8 *)qname->name, fid); -- if (err) -- return -ENOENT; -- -- return 0; --} -- --static int exfat_d_anon_disconn(struct dentry *dentry) --{ -- return IS_ROOT(dentry) && (dentry->d_flags & DCACHE_DISCONNECTED); --} -- --static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry, -- unsigned int flags) --{ -- struct super_block *sb = dir->i_sb; -- struct inode *inode; -- struct dentry *alias; -- int err; -- struct file_id_t fid; -- loff_t i_pos; -- u64 ret; -- mode_t i_mode; -- -- __lock_super(sb); -- pr_debug("%s entered\n", __func__); -- err = exfat_find(dir, &dentry->d_name, &fid); -- if (err) { -- if (err == -ENOENT) { -- inode = NULL; -- goto out; -- } -- goto error; -- } -- -- i_pos = ((loff_t)fid.dir.dir << 32) | (fid.entry & 0xffffffff); -- inode = exfat_build_inode(sb, &fid, i_pos); -- if (IS_ERR(inode)) { -- err = PTR_ERR(inode); -- goto error; -- } -- -- i_mode = inode->i_mode; -- if (S_ISLNK(i_mode) && !EXFAT_I(inode)->target) { -- EXFAT_I(inode)->target = kmalloc(i_size_read(inode) + 1, -- GFP_KERNEL); -- if (!EXFAT_I(inode)->target) { -- err = -ENOMEM; -- goto error; -- } -- ffsReadFile(dir, &fid, EXFAT_I(inode)->target, -- i_size_read(inode), &ret); -- *(EXFAT_I(inode)->target + i_size_read(inode)) = '\0'; -- } -- -- alias = d_find_alias(inode); -- if (alias && !exfat_d_anon_disconn(alias)) { -- BUG_ON(d_unhashed(alias)); -- if (!S_ISDIR(i_mode)) -- d_move(alias, dentry); -- iput(inode); -- __unlock_super(sb); -- pr_debug("%s exited 1\n", __func__); -- return alias; -- } -- dput(alias); --out: -- __unlock_super(sb); -- dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); -- dentry = d_splice_alias(inode, dentry); -- if (dentry) -- dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); -- pr_debug("%s exited 2\n", __func__); -- return dentry; -- --error: -- __unlock_super(sb); -- pr_debug("%s exited 3\n", __func__); -- return ERR_PTR(err); --} -- --static inline unsigned long exfat_hash(loff_t i_pos) --{ -- return hash_32(i_pos, EXFAT_HASH_BITS); --} -- --static void exfat_attach(struct inode *inode, loff_t i_pos) --{ -- struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); -- struct hlist_head *head = sbi->inode_hashtable + exfat_hash(i_pos); -- -- spin_lock(&sbi->inode_hash_lock); -- EXFAT_I(inode)->i_pos = i_pos; -- hlist_add_head(&EXFAT_I(inode)->i_hash_fat, head); -- spin_unlock(&sbi->inode_hash_lock); --} -- --static void exfat_detach(struct inode *inode) --{ -- struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); -- -- spin_lock(&sbi->inode_hash_lock); -- hlist_del_init(&EXFAT_I(inode)->i_hash_fat); -- EXFAT_I(inode)->i_pos = 0; -- spin_unlock(&sbi->inode_hash_lock); --} -- --static int exfat_unlink(struct inode *dir, struct dentry *dentry) --{ -- struct inode *inode = dentry->d_inode; -- struct super_block *sb = dir->i_sb; -- struct timespec64 curtime; -- int err; -- -- __lock_super(sb); -- -- pr_debug("%s entered\n", __func__); -- -- EXFAT_I(inode)->fid.size = i_size_read(inode); -- -- err = ffsRemoveFile(dir, &(EXFAT_I(inode)->fid)); -- if (err) -- goto out; -- -- INC_IVERSION(dir); -- curtime = current_time(dir); -- dir->i_mtime = curtime; -- dir->i_atime = curtime; -- if (IS_DIRSYNC(dir)) -- (void)exfat_sync_inode(dir); -- else -- mark_inode_dirty(dir); -- -- clear_nlink(inode); -- curtime = current_time(inode); -- inode->i_mtime = curtime; -- inode->i_atime = curtime; -- exfat_detach(inode); -- remove_inode_hash(inode); -- --out: -- __unlock_super(sb); -- pr_debug("%s exited\n", __func__); -- return err; --} -- --static int exfat_symlink(struct inode *dir, struct dentry *dentry, -- const char *target) --{ -- struct super_block *sb = dir->i_sb; -- struct timespec64 curtime; -- struct inode *inode; -- struct file_id_t fid; -- loff_t i_pos; -- int err; -- u64 len = (u64)strlen(target); -- u64 ret; -- -- __lock_super(sb); -- -- pr_debug("%s entered\n", __func__); -- -- err = ffsCreateFile(dir, (u8 *)dentry->d_name.name, FM_SYMLINK, &fid); -- if (err) -- goto out; -- -- -- err = ffsWriteFile(dir, &fid, (char *)target, len, &ret); -- -- if (err) { -- ffsRemoveFile(dir, &fid); -- goto out; -- } -- -- INC_IVERSION(dir); -- curtime = current_time(dir); -- dir->i_ctime = curtime; -- dir->i_mtime = curtime; -- dir->i_atime = curtime; -- if (IS_DIRSYNC(dir)) -- (void)exfat_sync_inode(dir); -- else -- mark_inode_dirty(dir); -- -- i_pos = ((loff_t)fid.dir.dir << 32) | (fid.entry & 0xffffffff); -- -- inode = exfat_build_inode(sb, &fid, i_pos); -- if (IS_ERR(inode)) { -- err = PTR_ERR(inode); -- goto out; -- } -- INC_IVERSION(inode); -- curtime = current_time(inode); -- inode->i_mtime = curtime; -- inode->i_atime = curtime; -- inode->i_ctime = curtime; -- /* timestamp is already written, so mark_inode_dirty() is unneeded. */ -- -- EXFAT_I(inode)->target = kmemdup(target, len + 1, GFP_KERNEL); -- if (!EXFAT_I(inode)->target) { -- err = -ENOMEM; -- goto out; -- } -- -- dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); -- d_instantiate(dentry, inode); -- --out: -- __unlock_super(sb); -- pr_debug("%s exited\n", __func__); -- return err; --} -- --static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) --{ -- struct super_block *sb = dir->i_sb; -- struct timespec64 curtime; -- struct inode *inode; -- struct file_id_t fid; -- loff_t i_pos; -- int err; -- -- __lock_super(sb); -- -- pr_debug("%s entered\n", __func__); -- -- err = ffsCreateDir(dir, (u8 *)dentry->d_name.name, &fid); -- if (err) -- goto out; -- -- INC_IVERSION(dir); -- curtime = current_time(dir); -- dir->i_ctime = curtime; -- dir->i_mtime = curtime; -- dir->i_atime = curtime; -- if (IS_DIRSYNC(dir)) -- (void)exfat_sync_inode(dir); -- else -- mark_inode_dirty(dir); -- inc_nlink(dir); -- -- i_pos = ((loff_t)fid.dir.dir << 32) | (fid.entry & 0xffffffff); -- -- inode = exfat_build_inode(sb, &fid, i_pos); -- if (IS_ERR(inode)) { -- err = PTR_ERR(inode); -- goto out; -- } -- INC_IVERSION(inode); -- curtime = current_time(inode); -- inode->i_mtime = curtime; -- inode->i_atime = curtime; -- inode->i_ctime = curtime; -- /* timestamp is already written, so mark_inode_dirty() is unneeded. */ -- -- dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); -- d_instantiate(dentry, inode); -- --out: -- __unlock_super(sb); -- pr_debug("%s exited\n", __func__); -- return err; --} -- --static int exfat_rmdir(struct inode *dir, struct dentry *dentry) --{ -- struct inode *inode = dentry->d_inode; -- struct super_block *sb = dir->i_sb; -- struct timespec64 curtime; -- int err; -- -- __lock_super(sb); -- -- pr_debug("%s entered\n", __func__); -- -- EXFAT_I(inode)->fid.size = i_size_read(inode); -- -- err = ffsRemoveDir(dir, &(EXFAT_I(inode)->fid)); -- if (err) -- goto out; -- -- INC_IVERSION(dir); -- curtime = current_time(dir); -- dir->i_mtime = curtime; -- dir->i_atime = curtime; -- if (IS_DIRSYNC(dir)) -- (void)exfat_sync_inode(dir); -- else -- mark_inode_dirty(dir); -- drop_nlink(dir); -- -- clear_nlink(inode); -- curtime = current_time(inode); -- inode->i_mtime = curtime; -- inode->i_atime = curtime; -- exfat_detach(inode); -- remove_inode_hash(inode); -- --out: -- __unlock_super(sb); -- pr_debug("%s exited\n", __func__); -- return err; --} -- --static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry, -- struct inode *new_dir, struct dentry *new_dentry, -- unsigned int flags) --{ -- struct inode *old_inode, *new_inode; -- struct super_block *sb = old_dir->i_sb; -- struct timespec64 curtime; -- loff_t i_pos; -- int err; -- -- if (flags) -- return -EINVAL; -- -- __lock_super(sb); -- -- pr_debug("%s entered\n", __func__); -- -- old_inode = old_dentry->d_inode; -- new_inode = new_dentry->d_inode; -- -- EXFAT_I(old_inode)->fid.size = i_size_read(old_inode); -- -- err = ffsMoveFile(old_dir, &(EXFAT_I(old_inode)->fid), new_dir, -- new_dentry); -- if (err) -- goto out; -- -- INC_IVERSION(new_dir); -- curtime = current_time(new_dir); -- new_dir->i_ctime = curtime; -- new_dir->i_mtime = curtime; -- new_dir->i_atime = curtime; -- -- if (IS_DIRSYNC(new_dir)) -- (void)exfat_sync_inode(new_dir); -- else -- mark_inode_dirty(new_dir); -- -- i_pos = ((loff_t)EXFAT_I(old_inode)->fid.dir.dir << 32) | -- (EXFAT_I(old_inode)->fid.entry & 0xffffffff); -- -- exfat_detach(old_inode); -- exfat_attach(old_inode, i_pos); -- if (IS_DIRSYNC(new_dir)) -- (void)exfat_sync_inode(old_inode); -- else -- mark_inode_dirty(old_inode); -- -- if ((S_ISDIR(old_inode->i_mode)) && (old_dir != new_dir)) { -- drop_nlink(old_dir); -- if (!new_inode) -- inc_nlink(new_dir); -- } -- INC_IVERSION(old_dir); -- curtime = current_time(old_dir); -- old_dir->i_ctime = curtime; -- old_dir->i_mtime = curtime; -- if (IS_DIRSYNC(old_dir)) -- (void)exfat_sync_inode(old_dir); -- else -- mark_inode_dirty(old_dir); -- -- if (new_inode) { -- exfat_detach(new_inode); -- drop_nlink(new_inode); -- if (S_ISDIR(new_inode->i_mode)) -- drop_nlink(new_inode); -- new_inode->i_ctime = current_time(new_inode); -- } -- --out: -- __unlock_super(sb); -- pr_debug("%s exited\n", __func__); -- return err; --} -- --static int exfat_cont_expand(struct inode *inode, loff_t size) --{ -- struct address_space *mapping = inode->i_mapping; -- loff_t start = i_size_read(inode), count = size - i_size_read(inode); -- struct timespec64 curtime; -- int err, err2; -- -- err = generic_cont_expand_simple(inode, size); -- if (err != 0) -- return err; -- -- curtime = current_time(inode); -- inode->i_ctime = curtime; -- inode->i_mtime = curtime; -- mark_inode_dirty(inode); -- -- if (IS_SYNC(inode)) { -- err = filemap_fdatawrite_range(mapping, start, -- start + count - 1); -- err2 = sync_mapping_buffers(mapping); -- err = (err) ? (err) : (err2); -- err2 = write_inode_now(inode, 1); -- err = (err) ? (err) : (err2); -- if (!err) -- err = filemap_fdatawait_range(mapping, start, -- start + count - 1); -- } -- return err; --} -- --static int exfat_allow_set_time(struct exfat_sb_info *sbi, struct inode *inode) --{ -- mode_t allow_utime = sbi->options.allow_utime; -- -- if (!uid_eq(current_fsuid(), inode->i_uid)) { -- if (in_group_p(inode->i_gid)) -- allow_utime >>= 3; -- if (allow_utime & MAY_WRITE) -- return 1; -- } -- -- /* use a default check */ -- return 0; --} -- --static int exfat_sanitize_mode(const struct exfat_sb_info *sbi, -- struct inode *inode, umode_t *mode_ptr) --{ -- mode_t i_mode, mask, perm; -- -- i_mode = inode->i_mode; -- -- if (S_ISREG(i_mode) || S_ISLNK(i_mode)) -- mask = sbi->options.fs_fmask; -- else -- mask = sbi->options.fs_dmask; -- -- perm = *mode_ptr & ~(S_IFMT | mask); -- -- /* Of the r and x bits, all (subject to umask) must be present.*/ -- if ((perm & 0555) != (i_mode & 0555)) -- return -EPERM; -- -- if (exfat_mode_can_hold_ro(inode)) { -- /* -- * Of the w bits, either all (subject to umask) or none must be -- * present. -- */ -- if ((perm & 0222) && ((perm & 0222) != (0222 & ~mask))) -- return -EPERM; -- } else { -- /* -- * If exfat_mode_can_hold_ro(inode) is false, can't change w -- * bits. -- */ -- if ((perm & 0222) != (0222 & ~mask)) -- return -EPERM; -- } -- -- *mode_ptr &= S_IFMT | perm; -- -- return 0; --} -- --static void exfat_truncate(struct inode *inode, loff_t old_size) --{ -- struct super_block *sb = inode->i_sb; -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- struct fs_info_t *p_fs = &sbi->fs_info; -- struct timespec64 curtime; -- int err; -- -- __lock_super(sb); -- -- /* -- * This protects against truncating a file bigger than it was then -- * trying to write into the hole. -- */ -- if (EXFAT_I(inode)->mmu_private > i_size_read(inode)) -- EXFAT_I(inode)->mmu_private = i_size_read(inode); -- -- if (EXFAT_I(inode)->fid.start_clu == 0) -- goto out; -- -- err = ffsTruncateFile(inode, old_size, i_size_read(inode)); -- if (err) -- goto out; -- -- curtime = current_time(inode); -- inode->i_ctime = curtime; -- inode->i_mtime = curtime; -- if (IS_DIRSYNC(inode)) -- (void)exfat_sync_inode(inode); -- else -- mark_inode_dirty(inode); -- -- inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1)) & -- ~((loff_t)p_fs->cluster_size - 1)) >> 9; --out: -- __unlock_super(sb); --} -- --static int exfat_setattr(struct dentry *dentry, struct iattr *attr) --{ -- struct exfat_sb_info *sbi = EXFAT_SB(dentry->d_sb); -- struct inode *inode = dentry->d_inode; -- unsigned int ia_valid; -- int error; -- loff_t old_size; -- -- pr_debug("%s entered\n", __func__); -- -- if ((attr->ia_valid & ATTR_SIZE) && -- attr->ia_size > i_size_read(inode)) { -- error = exfat_cont_expand(inode, attr->ia_size); -- if (error || attr->ia_valid == ATTR_SIZE) -- return error; -- attr->ia_valid &= ~ATTR_SIZE; -- } -- -- ia_valid = attr->ia_valid; -- -- if ((ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) && -- exfat_allow_set_time(sbi, inode)) { -- attr->ia_valid &= ~(ATTR_MTIME_SET | -- ATTR_ATIME_SET | -- ATTR_TIMES_SET); -- } -- -- error = setattr_prepare(dentry, attr); -- attr->ia_valid = ia_valid; -- if (error) -- return error; -- -- if (((attr->ia_valid & ATTR_UID) && -- (!uid_eq(attr->ia_uid, sbi->options.fs_uid))) || -- ((attr->ia_valid & ATTR_GID) && -- (!gid_eq(attr->ia_gid, sbi->options.fs_gid))) || -- ((attr->ia_valid & ATTR_MODE) && -- (attr->ia_mode & ~(S_IFREG | S_IFLNK | S_IFDIR | 0777)))) { -- return -EPERM; -- } -- -- /* -- * We don't return -EPERM here. Yes, strange, but this is too -- * old behavior. -- */ -- if (attr->ia_valid & ATTR_MODE) { -- if (exfat_sanitize_mode(sbi, inode, &attr->ia_mode) < 0) -- attr->ia_valid &= ~ATTR_MODE; -- } -- -- EXFAT_I(inode)->fid.size = i_size_read(inode); -- -- if (attr->ia_valid & ATTR_SIZE) { -- old_size = i_size_read(inode); -- down_write(&EXFAT_I(inode)->truncate_lock); -- truncate_setsize(inode, attr->ia_size); -- exfat_truncate(inode, old_size); -- up_write(&EXFAT_I(inode)->truncate_lock); -- } -- setattr_copy(inode, attr); -- mark_inode_dirty(inode); -- -- pr_debug("%s exited\n", __func__); -- return error; --} -- --static int exfat_getattr(const struct path *path, struct kstat *stat, -- u32 request_mask, unsigned int flags) --{ -- struct inode *inode = path->dentry->d_inode; -- -- pr_debug("%s entered\n", __func__); -- -- generic_fillattr(inode, stat); -- stat->blksize = EXFAT_SB(inode->i_sb)->fs_info.cluster_size; -- -- pr_debug("%s exited\n", __func__); -- return 0; --} -- --static const struct inode_operations exfat_dir_inode_operations = { -- .create = exfat_create, -- .lookup = exfat_lookup, -- .unlink = exfat_unlink, -- .symlink = exfat_symlink, -- .mkdir = exfat_mkdir, -- .rmdir = exfat_rmdir, -- .rename = exfat_rename, -- .setattr = exfat_setattr, -- .getattr = exfat_getattr, --}; -- --/*======================================================================*/ --/* File Operations */ --/*======================================================================*/ --static const char *exfat_get_link(struct dentry *dentry, struct inode *inode, -- struct delayed_call *done) --{ -- struct exfat_inode_info *ei = EXFAT_I(inode); -- -- if (ei->target) { -- char *cookie = ei->target; -- -- if (cookie) -- return (char *)(ei->target); -- } -- return NULL; --} -- --static const struct inode_operations exfat_symlink_inode_operations = { -- .get_link = exfat_get_link, --}; -- --static int exfat_file_release(struct inode *inode, struct file *filp) --{ -- struct super_block *sb = inode->i_sb; -- -- EXFAT_I(inode)->fid.size = i_size_read(inode); -- ffsSyncVol(sb, false); -- return 0; --} -- --static const struct file_operations exfat_file_operations = { -- .llseek = generic_file_llseek, -- .read_iter = generic_file_read_iter, -- .write_iter = generic_file_write_iter, -- .mmap = generic_file_mmap, -- .release = exfat_file_release, -- .unlocked_ioctl = exfat_generic_ioctl, -- .fsync = generic_file_fsync, -- .splice_read = generic_file_splice_read, --}; -- --static const struct inode_operations exfat_file_inode_operations = { -- .setattr = exfat_setattr, -- .getattr = exfat_getattr, --}; -- --/*======================================================================*/ --/* Address Space Operations */ --/*======================================================================*/ -- --static int exfat_bmap(struct inode *inode, sector_t sector, sector_t *phys, -- unsigned long *mapped_blocks, int *create) --{ -- struct super_block *sb = inode->i_sb; -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- struct fs_info_t *p_fs = &sbi->fs_info; -- const unsigned long blocksize = sb->s_blocksize; -- const unsigned char blocksize_bits = sb->s_blocksize_bits; -- sector_t last_block; -- int err, clu_offset, sec_offset; -- unsigned int cluster; -- -- *phys = 0; -- *mapped_blocks = 0; -- -- last_block = (i_size_read(inode) + (blocksize - 1)) >> blocksize_bits; -- if (sector >= last_block) { -- if (*create == 0) -- return 0; -- } else { -- *create = 0; -- } -- -- /* cluster offset */ -- clu_offset = sector >> p_fs->sectors_per_clu_bits; -- -- /* sector offset in cluster */ -- sec_offset = sector & (p_fs->sectors_per_clu - 1); -- -- EXFAT_I(inode)->fid.size = i_size_read(inode); -- -- err = ffsMapCluster(inode, clu_offset, &cluster); -- -- if (!err && (cluster != CLUSTER_32(~0))) { -- *phys = START_SECTOR(cluster) + sec_offset; -- *mapped_blocks = p_fs->sectors_per_clu - sec_offset; -- } -- -- return 0; --} -- --static int exfat_get_block(struct inode *inode, sector_t iblock, -- struct buffer_head *bh_result, int create) --{ -- struct super_block *sb = inode->i_sb; -- unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits; -- int err; -- unsigned long mapped_blocks; -- sector_t phys; -- -- __lock_super(sb); -- -- err = exfat_bmap(inode, iblock, &phys, &mapped_blocks, &create); -- if (err) { -- __unlock_super(sb); -- return err; -- } -- -- if (phys) { -- max_blocks = min(mapped_blocks, max_blocks); -- if (create) { -- EXFAT_I(inode)->mmu_private += max_blocks << -- sb->s_blocksize_bits; -- set_buffer_new(bh_result); -- } -- map_bh(bh_result, sb, phys); -- } -- -- bh_result->b_size = max_blocks << sb->s_blocksize_bits; -- __unlock_super(sb); -- -- return 0; --} -- --static int exfat_readpage(struct file *file, struct page *page) --{ -- return mpage_readpage(page, exfat_get_block); --} -- --static int exfat_readpages(struct file *file, struct address_space *mapping, -- struct list_head *pages, unsigned int nr_pages) --{ -- return mpage_readpages(mapping, pages, nr_pages, exfat_get_block); --} -- --static int exfat_writepage(struct page *page, struct writeback_control *wbc) --{ -- return block_write_full_page(page, exfat_get_block, wbc); --} -- --static int exfat_writepages(struct address_space *mapping, -- struct writeback_control *wbc) --{ -- return mpage_writepages(mapping, wbc, exfat_get_block); --} -- --static void exfat_write_failed(struct address_space *mapping, loff_t to) --{ -- struct inode *inode = mapping->host; -- -- if (to > i_size_read(inode)) { -- truncate_pagecache(inode, i_size_read(inode)); -- EXFAT_I(inode)->fid.size = i_size_read(inode); -- exfat_truncate(inode, i_size_read(inode)); -- } --} -- --static int exfat_write_begin(struct file *file, struct address_space *mapping, -- loff_t pos, unsigned int len, unsigned int flags, -- struct page **pagep, void **fsdata) --{ -- int ret; -- -- *pagep = NULL; -- ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, -- exfat_get_block, -- &EXFAT_I(mapping->host)->mmu_private); -- -- if (ret < 0) -- exfat_write_failed(mapping, pos + len); -- return ret; --} -- --static int exfat_write_end(struct file *file, struct address_space *mapping, -- loff_t pos, unsigned int len, unsigned int copied, -- struct page *pagep, void *fsdata) --{ -- struct inode *inode = mapping->host; -- struct file_id_t *fid = &(EXFAT_I(inode)->fid); -- struct timespec64 curtime; -- int err; -- -- err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata); -- -- if (err < len) -- exfat_write_failed(mapping, pos + len); -- -- if (!(err < 0) && !(fid->attr & ATTR_ARCHIVE)) { -- curtime = current_time(inode); -- inode->i_mtime = curtime; -- inode->i_ctime = curtime; -- fid->attr |= ATTR_ARCHIVE; -- mark_inode_dirty(inode); -- } -- return err; --} -- --static ssize_t exfat_direct_IO(struct kiocb *iocb, struct iov_iter *iter) --{ -- struct inode *inode = iocb->ki_filp->f_mapping->host; -- struct address_space *mapping = iocb->ki_filp->f_mapping; -- ssize_t ret; -- int rw; -- -- rw = iov_iter_rw(iter); -- -- if (rw == WRITE) { -- if (EXFAT_I(inode)->mmu_private < iov_iter_count(iter)) -- return 0; -- } -- ret = blockdev_direct_IO(iocb, inode, iter, exfat_get_block); -- -- if ((ret < 0) && (rw & WRITE)) -- exfat_write_failed(mapping, iov_iter_count(iter)); -- return ret; --} -- --static sector_t _exfat_bmap(struct address_space *mapping, sector_t block) --{ -- sector_t blocknr; -- -- /* exfat_get_cluster() assumes the requested blocknr isn't truncated. */ -- down_read(&EXFAT_I(mapping->host)->truncate_lock); -- blocknr = generic_block_bmap(mapping, block, exfat_get_block); -- up_read(&EXFAT_I(mapping->host)->truncate_lock); -- -- return blocknr; --} -- --static const struct address_space_operations exfat_aops = { -- .readpage = exfat_readpage, -- .readpages = exfat_readpages, -- .writepage = exfat_writepage, -- .writepages = exfat_writepages, -- .write_begin = exfat_write_begin, -- .write_end = exfat_write_end, -- .direct_IO = exfat_direct_IO, -- .bmap = _exfat_bmap --}; -- --/*======================================================================*/ --/* Super Operations */ --/*======================================================================*/ -- --static struct inode *exfat_iget(struct super_block *sb, loff_t i_pos) --{ -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- struct exfat_inode_info *info; -- struct hlist_head *head = sbi->inode_hashtable + exfat_hash(i_pos); -- struct inode *inode = NULL; -- -- spin_lock(&sbi->inode_hash_lock); -- hlist_for_each_entry(info, head, i_hash_fat) { -- BUG_ON(info->vfs_inode.i_sb != sb); -- -- if (i_pos != info->i_pos) -- continue; -- inode = igrab(&info->vfs_inode); -- if (inode) -- break; -- } -- spin_unlock(&sbi->inode_hash_lock); -- return inode; --} -- --/* doesn't deal with root inode */ --static int exfat_fill_inode(struct inode *inode, struct file_id_t *fid) --{ -- struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); -- struct fs_info_t *p_fs = &sbi->fs_info; -- struct dir_entry_t info; -- -- memcpy(&(EXFAT_I(inode)->fid), fid, sizeof(struct file_id_t)); -- -- ffsReadStat(inode, &info); -- -- EXFAT_I(inode)->i_pos = 0; -- EXFAT_I(inode)->target = NULL; -- inode->i_uid = sbi->options.fs_uid; -- inode->i_gid = sbi->options.fs_gid; -- INC_IVERSION(inode); -- inode->i_generation = prandom_u32(); -- -- if (info.Attr & ATTR_SUBDIR) { /* directory */ -- inode->i_generation &= ~1; -- inode->i_mode = exfat_make_mode(sbi, info.Attr, 0777); -- inode->i_op = &exfat_dir_inode_operations; -- inode->i_fop = &exfat_dir_operations; -- -- i_size_write(inode, info.Size); -- EXFAT_I(inode)->mmu_private = i_size_read(inode); -- set_nlink(inode, info.NumSubdirs); -- } else if (info.Attr & ATTR_SYMLINK) { /* symbolic link */ -- inode->i_generation |= 1; -- inode->i_mode = exfat_make_mode(sbi, info.Attr, 0777); -- inode->i_op = &exfat_symlink_inode_operations; -- -- i_size_write(inode, info.Size); -- EXFAT_I(inode)->mmu_private = i_size_read(inode); -- } else { /* regular file */ -- inode->i_generation |= 1; -- inode->i_mode = exfat_make_mode(sbi, info.Attr, 0777); -- inode->i_op = &exfat_file_inode_operations; -- inode->i_fop = &exfat_file_operations; -- inode->i_mapping->a_ops = &exfat_aops; -- inode->i_mapping->nrpages = 0; -- -- i_size_write(inode, info.Size); -- EXFAT_I(inode)->mmu_private = i_size_read(inode); -- } -- exfat_save_attr(inode, info.Attr); -- -- inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1)) -- & ~((loff_t)p_fs->cluster_size - 1)) >> 9; -- -- exfat_time_fat2unix(&inode->i_mtime, &info.ModifyTimestamp); -- exfat_time_fat2unix(&inode->i_ctime, &info.CreateTimestamp); -- exfat_time_fat2unix(&inode->i_atime, &info.AccessTimestamp); -- -- return 0; --} -- --static struct inode *exfat_build_inode(struct super_block *sb, -- struct file_id_t *fid, loff_t i_pos) --{ -- struct inode *inode; -- int err; -- -- inode = exfat_iget(sb, i_pos); -- if (inode) -- goto out; -- inode = new_inode(sb); -- if (!inode) { -- inode = ERR_PTR(-ENOMEM); -- goto out; -- } -- inode->i_ino = iunique(sb, EXFAT_ROOT_INO); -- SET_IVERSION(inode, 1); -- err = exfat_fill_inode(inode, fid); -- if (err) { -- iput(inode); -- inode = ERR_PTR(err); -- goto out; -- } -- exfat_attach(inode, i_pos); -- insert_inode_hash(inode); --out: -- return inode; --} -- --static int exfat_sync_inode(struct inode *inode) --{ -- return exfat_write_inode(inode, NULL); --} -- --static struct inode *exfat_alloc_inode(struct super_block *sb) --{ -- struct exfat_inode_info *ei; -- -- ei = kmem_cache_alloc(exfat_inode_cachep, GFP_NOFS); -- if (!ei) -- return NULL; -- -- init_rwsem(&ei->truncate_lock); -- -- return &ei->vfs_inode; --} -- --static void exfat_destroy_inode(struct inode *inode) --{ -- kfree(EXFAT_I(inode)->target); -- EXFAT_I(inode)->target = NULL; -- -- kmem_cache_free(exfat_inode_cachep, EXFAT_I(inode)); --} -- --static int exfat_write_inode(struct inode *inode, struct writeback_control *wbc) --{ -- struct dir_entry_t info; -- -- if (inode->i_ino == EXFAT_ROOT_INO) -- return 0; -- -- info.Attr = exfat_make_attr(inode); -- info.Size = i_size_read(inode); -- -- exfat_time_unix2fat(&inode->i_mtime, &info.ModifyTimestamp); -- exfat_time_unix2fat(&inode->i_ctime, &info.CreateTimestamp); -- exfat_time_unix2fat(&inode->i_atime, &info.AccessTimestamp); -- -- ffsWriteStat(inode, &info); -- -- return 0; --} -- --static void exfat_evict_inode(struct inode *inode) --{ -- truncate_inode_pages(&inode->i_data, 0); -- -- if (!inode->i_nlink) -- i_size_write(inode, 0); -- invalidate_inode_buffers(inode); -- clear_inode(inode); -- exfat_detach(inode); -- -- remove_inode_hash(inode); --} -- --static void exfat_free_super(struct exfat_sb_info *sbi) --{ -- if (sbi->nls_disk) -- unload_nls(sbi->nls_disk); -- if (sbi->nls_io) -- unload_nls(sbi->nls_io); -- if (sbi->options.iocharset != exfat_default_iocharset) -- kfree(sbi->options.iocharset); -- /* mutex_init is in exfat_fill_super function. only for 3.7+ */ -- mutex_destroy(&sbi->s_lock); -- kvfree(sbi); --} -- --static void exfat_put_super(struct super_block *sb) --{ -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- -- if (__is_sb_dirty(sb)) -- exfat_write_super(sb); -- -- ffsUmountVol(sb); -- -- sb->s_fs_info = NULL; -- exfat_free_super(sbi); --} -- --static void exfat_write_super(struct super_block *sb) --{ -- __lock_super(sb); -- -- __set_sb_clean(sb); -- -- if (!sb_rdonly(sb)) -- ffsSyncVol(sb, true); -- -- __unlock_super(sb); --} -- --static int exfat_sync_fs(struct super_block *sb, int wait) --{ -- int err = 0; -- -- if (__is_sb_dirty(sb)) { -- __lock_super(sb); -- __set_sb_clean(sb); -- err = ffsSyncVol(sb, true); -- __unlock_super(sb); -- } -- -- return err; --} -- --static int exfat_statfs(struct dentry *dentry, struct kstatfs *buf) --{ -- struct super_block *sb = dentry->d_sb; -- u64 id = huge_encode_dev(sb->s_bdev->bd_dev); -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct vol_info_t info; -- -- if (p_fs->used_clusters == UINT_MAX) { -- if (ffsGetVolInfo(sb, &info) == -EIO) -- return -EIO; -- -- } else { -- info.FatType = p_fs->vol_type; -- info.ClusterSize = p_fs->cluster_size; -- info.NumClusters = p_fs->num_clusters - 2; -- info.UsedClusters = p_fs->used_clusters; -- info.FreeClusters = info.NumClusters - info.UsedClusters; -- -- if (p_fs->dev_ejected) -- pr_info("[EXFAT] statfs on device that is ejected\n"); -- } -- -- buf->f_type = sb->s_magic; -- buf->f_bsize = info.ClusterSize; -- buf->f_blocks = info.NumClusters; -- buf->f_bfree = info.FreeClusters; -- buf->f_bavail = info.FreeClusters; -- buf->f_fsid.val[0] = (u32)id; -- buf->f_fsid.val[1] = (u32)(id >> 32); -- buf->f_namelen = 260; -- -- return 0; --} -- --static int exfat_remount(struct super_block *sb, int *flags, char *data) --{ -- *flags |= SB_NODIRATIME; -- return 0; --} -- --static int exfat_show_options(struct seq_file *m, struct dentry *root) --{ -- struct exfat_sb_info *sbi = EXFAT_SB(root->d_sb); -- struct exfat_mount_options *opts = &sbi->options; -- -- if (__kuid_val(opts->fs_uid)) -- seq_printf(m, ",uid=%u", __kuid_val(opts->fs_uid)); -- if (__kgid_val(opts->fs_gid)) -- seq_printf(m, ",gid=%u", __kgid_val(opts->fs_gid)); -- seq_printf(m, ",fmask=%04o", opts->fs_fmask); -- seq_printf(m, ",dmask=%04o", opts->fs_dmask); -- if (opts->allow_utime) -- seq_printf(m, ",allow_utime=%04o", opts->allow_utime); -- if (sbi->nls_disk) -- seq_printf(m, ",codepage=%s", sbi->nls_disk->charset); -- if (sbi->nls_io) -- seq_printf(m, ",iocharset=%s", sbi->nls_io->charset); -- seq_printf(m, ",namecase=%u", opts->casesensitive); -- if (opts->errors == EXFAT_ERRORS_CONT) -- seq_puts(m, ",errors=continue"); -- else if (opts->errors == EXFAT_ERRORS_PANIC) -- seq_puts(m, ",errors=panic"); -- else -- seq_puts(m, ",errors=remount-ro"); --#ifdef CONFIG_STAGING_EXFAT_DISCARD -- if (opts->discard) -- seq_puts(m, ",discard"); --#endif -- return 0; --} -- --static const struct super_operations exfat_sops = { -- .alloc_inode = exfat_alloc_inode, -- .destroy_inode = exfat_destroy_inode, -- .write_inode = exfat_write_inode, -- .evict_inode = exfat_evict_inode, -- .put_super = exfat_put_super, -- .sync_fs = exfat_sync_fs, -- .statfs = exfat_statfs, -- .remount_fs = exfat_remount, -- .show_options = exfat_show_options, --}; -- --/*======================================================================*/ --/* Export Operations */ --/*======================================================================*/ -- --static struct inode *exfat_nfs_get_inode(struct super_block *sb, u64 ino, -- u32 generation) --{ -- struct inode *inode = NULL; -- -- if (ino < EXFAT_ROOT_INO) -- return inode; -- inode = ilookup(sb, ino); -- -- if (inode && generation && (inode->i_generation != generation)) { -- iput(inode); -- inode = NULL; -- } -- -- return inode; --} -- --static struct dentry *exfat_fh_to_dentry(struct super_block *sb, -- struct fid *fid, int fh_len, -- int fh_type) --{ -- return generic_fh_to_dentry(sb, fid, fh_len, fh_type, -- exfat_nfs_get_inode); --} -- --static struct dentry *exfat_fh_to_parent(struct super_block *sb, -- struct fid *fid, int fh_len, -- int fh_type) --{ -- return generic_fh_to_parent(sb, fid, fh_len, fh_type, -- exfat_nfs_get_inode); --} -- --static const struct export_operations exfat_export_ops = { -- .fh_to_dentry = exfat_fh_to_dentry, -- .fh_to_parent = exfat_fh_to_parent, --}; -- --/*======================================================================*/ --/* Super Block Read Operations */ --/*======================================================================*/ -- --enum { -- Opt_uid, -- Opt_gid, -- Opt_umask, -- Opt_dmask, -- Opt_fmask, -- Opt_allow_utime, -- Opt_codepage, -- Opt_charset, -- Opt_namecase, -- Opt_debug, -- Opt_err_cont, -- Opt_err_panic, -- Opt_err_ro, -- Opt_utf8_hack, -- Opt_err, --#ifdef CONFIG_STAGING_EXFAT_DISCARD -- Opt_discard, --#endif /* EXFAT_CONFIG_DISCARD */ --}; -- --static const match_table_t exfat_tokens = { -- {Opt_uid, "uid=%u"}, -- {Opt_gid, "gid=%u"}, -- {Opt_umask, "umask=%o"}, -- {Opt_dmask, "dmask=%o"}, -- {Opt_fmask, "fmask=%o"}, -- {Opt_allow_utime, "allow_utime=%o"}, -- {Opt_codepage, "codepage=%u"}, -- {Opt_charset, "iocharset=%s"}, -- {Opt_namecase, "namecase=%u"}, -- {Opt_debug, "debug"}, -- {Opt_err_cont, "errors=continue"}, -- {Opt_err_panic, "errors=panic"}, -- {Opt_err_ro, "errors=remount-ro"}, -- {Opt_utf8_hack, "utf8"}, --#ifdef CONFIG_STAGING_EXFAT_DISCARD -- {Opt_discard, "discard"}, --#endif /* CONFIG_STAGING_EXFAT_DISCARD */ -- {Opt_err, NULL} --}; -- --static int parse_options(char *options, int silent, int *debug, -- struct exfat_mount_options *opts) --{ -- char *p; -- substring_t args[MAX_OPT_ARGS]; -- int option; -- char *iocharset; -- -- opts->fs_uid = current_uid(); -- opts->fs_gid = current_gid(); -- opts->fs_fmask = current->fs->umask; -- opts->fs_dmask = current->fs->umask; -- opts->allow_utime = U16_MAX; -- opts->codepage = exfat_default_codepage; -- opts->iocharset = exfat_default_iocharset; -- opts->casesensitive = 0; -- opts->errors = EXFAT_ERRORS_RO; --#ifdef CONFIG_STAGING_EXFAT_DISCARD -- opts->discard = 0; --#endif -- *debug = 0; -- -- if (!options) -- goto out; -- -- while ((p = strsep(&options, ","))) { -- int token; -- -- if (!*p) -- continue; -- -- token = match_token(p, exfat_tokens, args); -- switch (token) { -- case Opt_uid: -- if (match_int(&args[0], &option)) -- return 0; -- opts->fs_uid = KUIDT_INIT(option); -- break; -- case Opt_gid: -- if (match_int(&args[0], &option)) -- return 0; -- opts->fs_gid = KGIDT_INIT(option); -- break; -- case Opt_umask: -- case Opt_dmask: -- case Opt_fmask: -- if (match_octal(&args[0], &option)) -- return 0; -- if (token != Opt_dmask) -- opts->fs_fmask = option; -- if (token != Opt_fmask) -- opts->fs_dmask = option; -- break; -- case Opt_allow_utime: -- if (match_octal(&args[0], &option)) -- return 0; -- opts->allow_utime = option & 0022; -- break; -- case Opt_codepage: -- if (match_int(&args[0], &option)) -- return 0; -- opts->codepage = option; -- break; -- case Opt_charset: -- if (opts->iocharset != exfat_default_iocharset) -- kfree(opts->iocharset); -- iocharset = match_strdup(&args[0]); -- if (!iocharset) -- return -ENOMEM; -- opts->iocharset = iocharset; -- break; -- case Opt_namecase: -- if (match_int(&args[0], &option)) -- return 0; -- opts->casesensitive = option; -- break; -- case Opt_err_cont: -- opts->errors = EXFAT_ERRORS_CONT; -- break; -- case Opt_err_panic: -- opts->errors = EXFAT_ERRORS_PANIC; -- break; -- case Opt_err_ro: -- opts->errors = EXFAT_ERRORS_RO; -- break; -- case Opt_debug: -- *debug = 1; -- break; --#ifdef CONFIG_STAGING_EXFAT_DISCARD -- case Opt_discard: -- opts->discard = 1; -- break; --#endif /* CONFIG_STAGING_EXFAT_DISCARD */ -- case Opt_utf8_hack: -- break; -- default: -- if (!silent) -- pr_err("[EXFAT] Unrecognized mount option %s or missing value\n", -- p); -- return -EINVAL; -- } -- } -- --out: -- if (opts->allow_utime == U16_MAX) -- opts->allow_utime = ~opts->fs_dmask & 0022; -- -- return 0; --} -- --static void exfat_hash_init(struct super_block *sb) --{ -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- int i; -- -- spin_lock_init(&sbi->inode_hash_lock); -- for (i = 0; i < EXFAT_HASH_SIZE; i++) -- INIT_HLIST_HEAD(&sbi->inode_hashtable[i]); --} -- --static int exfat_read_root(struct inode *inode) --{ -- struct super_block *sb = inode->i_sb; -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- struct fs_info_t *p_fs = &sbi->fs_info; -- struct timespec64 curtime; -- struct dir_entry_t info; -- -- EXFAT_I(inode)->fid.dir.dir = p_fs->root_dir; -- EXFAT_I(inode)->fid.dir.flags = 0x01; -- EXFAT_I(inode)->fid.entry = -1; -- EXFAT_I(inode)->fid.start_clu = p_fs->root_dir; -- EXFAT_I(inode)->fid.flags = 0x01; -- EXFAT_I(inode)->fid.type = TYPE_DIR; -- EXFAT_I(inode)->fid.rwoffset = 0; -- EXFAT_I(inode)->fid.hint_last_off = -1; -- -- EXFAT_I(inode)->target = NULL; -- -- ffsReadStat(inode, &info); -- -- inode->i_uid = sbi->options.fs_uid; -- inode->i_gid = sbi->options.fs_gid; -- INC_IVERSION(inode); -- inode->i_generation = 0; -- inode->i_mode = exfat_make_mode(sbi, ATTR_SUBDIR, 0777); -- inode->i_op = &exfat_dir_inode_operations; -- inode->i_fop = &exfat_dir_operations; -- -- i_size_write(inode, info.Size); -- inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1)) -- & ~((loff_t)p_fs->cluster_size - 1)) >> 9; -- EXFAT_I(inode)->i_pos = ((loff_t)p_fs->root_dir << 32) | 0xffffffff; -- EXFAT_I(inode)->mmu_private = i_size_read(inode); -- -- exfat_save_attr(inode, ATTR_SUBDIR); -- curtime = current_time(inode); -- inode->i_mtime = curtime; -- inode->i_atime = curtime; -- inode->i_ctime = curtime; -- set_nlink(inode, info.NumSubdirs + 2); -- -- return 0; --} -- --static void setup_dops(struct super_block *sb) --{ -- if (EXFAT_SB(sb)->options.casesensitive == 0) -- sb->s_d_op = &exfat_ci_dentry_ops; -- else -- sb->s_d_op = &exfat_dentry_ops; --} -- --static int exfat_fill_super(struct super_block *sb, void *data, int silent) --{ -- struct inode *root_inode = NULL; -- struct exfat_sb_info *sbi; -- int debug, ret; -- long error; -- -- /* -- * GFP_KERNEL is ok here, because while we do hold the -- * supeblock lock, memory pressure can't call back into -- * the filesystem, since we're only just about to mount -- * it and have no inodes etc active! -- */ -- sbi = kvzalloc(sizeof(*sbi), GFP_KERNEL); -- if (!sbi) -- return -ENOMEM; -- mutex_init(&sbi->s_lock); -- sb->s_fs_info = sbi; -- sb->s_flags |= SB_NODIRATIME; -- sb->s_magic = EXFAT_SUPER_MAGIC; -- sb->s_op = &exfat_sops; -- sb->s_export_op = &exfat_export_ops; -- -- error = parse_options(data, silent, &debug, &sbi->options); -- if (error) -- goto out_fail; -- -- setup_dops(sb); -- -- error = -EIO; -- sb_min_blocksize(sb, 512); -- sb->s_maxbytes = 0x7fffffffffffffffLL; /* maximum file size */ -- -- ret = ffsMountVol(sb); -- if (ret) { -- if (!silent) -- pr_err("[EXFAT] ffsMountVol failed\n"); -- -- goto out_fail; -- } -- -- /* set up enough so that it can read an inode */ -- exfat_hash_init(sb); -- -- /* -- * The low byte of FAT's first entry must have same value with -- * media-field. But in real world, too many devices is -- * writing wrong value. So, removed that validity check. -- * -- * if (FAT_FIRST_ENT(sb, media) != first) -- */ -- -- sbi->nls_io = load_nls(sbi->options.iocharset); -- -- error = -ENOMEM; -- root_inode = new_inode(sb); -- if (!root_inode) -- goto out_fail2; -- root_inode->i_ino = EXFAT_ROOT_INO; -- SET_IVERSION(root_inode, 1); -- -- error = exfat_read_root(root_inode); -- if (error < 0) -- goto out_fail2; -- error = -ENOMEM; -- exfat_attach(root_inode, EXFAT_I(root_inode)->i_pos); -- insert_inode_hash(root_inode); -- sb->s_root = d_make_root(root_inode); -- if (!sb->s_root) { -- pr_err("[EXFAT] Getting the root inode failed\n"); -- goto out_fail2; -- } -- -- return 0; -- --out_fail2: -- ffsUmountVol(sb); --out_fail: -- if (root_inode) -- iput(root_inode); -- sb->s_fs_info = NULL; -- exfat_free_super(sbi); -- return error; --} -- --static struct dentry *exfat_fs_mount(struct file_system_type *fs_type, -- int flags, const char *dev_name, -- void *data) --{ -- return mount_bdev(fs_type, flags, dev_name, data, exfat_fill_super); --} -- --static void init_once(void *foo) --{ -- struct exfat_inode_info *ei = (struct exfat_inode_info *)foo; -- -- INIT_HLIST_NODE(&ei->i_hash_fat); -- inode_init_once(&ei->vfs_inode); --} -- --static int __init exfat_init_inodecache(void) --{ -- exfat_inode_cachep = kmem_cache_create("exfat_inode_cache", -- sizeof(struct exfat_inode_info), -- 0, -- (SLAB_RECLAIM_ACCOUNT | -- SLAB_MEM_SPREAD), -- init_once); -- if (!exfat_inode_cachep) -- return -ENOMEM; -- return 0; --} -- --static void __exit exfat_destroy_inodecache(void) --{ -- /* -- * Make sure all delayed rcu free inodes are flushed before we -- * destroy cache. -- */ -- rcu_barrier(); -- kmem_cache_destroy(exfat_inode_cachep); --} -- --#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG --static void exfat_debug_kill_sb(struct super_block *sb) --{ -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- struct block_device *bdev = sb->s_bdev; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- long flags; -- -- if (sbi) { -- flags = sbi->debug_flags; -- -- if (flags & EXFAT_DEBUGFLAGS_INVALID_UMOUNT) { -- /* -- * invalidate_bdev drops all device cache include -- * dirty. We use this to simulate device removal. -- */ -- mutex_lock(&p_fs->v_mutex); -- exfat_fat_release_all(sb); -- exfat_buf_release_all(sb); -- mutex_unlock(&p_fs->v_mutex); -- -- invalidate_bdev(bdev); -- } -- } -- -- kill_block_super(sb); --} --#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */ -- --static struct file_system_type exfat_fs_type = { -- .owner = THIS_MODULE, -- .name = "exfat", -- .mount = exfat_fs_mount, --#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG -- .kill_sb = exfat_debug_kill_sb, --#else -- .kill_sb = kill_block_super, --#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */ -- .fs_flags = FS_REQUIRES_DEV, --}; -- --static int __init init_exfat(void) --{ -- int err; -- -- BUILD_BUG_ON(sizeof(struct dentry_t) != DENTRY_SIZE); -- BUILD_BUG_ON(sizeof(struct dos_dentry_t) != DENTRY_SIZE); -- BUILD_BUG_ON(sizeof(struct ext_dentry_t) != DENTRY_SIZE); -- BUILD_BUG_ON(sizeof(struct file_dentry_t) != DENTRY_SIZE); -- BUILD_BUG_ON(sizeof(struct strm_dentry_t) != DENTRY_SIZE); -- BUILD_BUG_ON(sizeof(struct name_dentry_t) != DENTRY_SIZE); -- BUILD_BUG_ON(sizeof(struct bmap_dentry_t) != DENTRY_SIZE); -- BUILD_BUG_ON(sizeof(struct case_dentry_t) != DENTRY_SIZE); -- BUILD_BUG_ON(sizeof(struct volm_dentry_t) != DENTRY_SIZE); -- -- pr_info("exFAT: Version %s\n", EXFAT_VERSION); -- -- err = exfat_init_inodecache(); -- if (err) -- return err; -- -- err = register_filesystem(&exfat_fs_type); -- if (err) -- return err; -- -- return 0; --} -- --static void __exit exit_exfat(void) --{ -- exfat_destroy_inodecache(); -- unregister_filesystem(&exfat_fs_type); --} -- --module_init(init_exfat); --module_exit(exit_exfat); -- --MODULE_LICENSE("GPL"); --MODULE_DESCRIPTION("exFAT Filesystem Driver"); --MODULE_ALIAS_FS("exfat"); -diff -Nurp linux-5.6.3.orig/drivers/staging/exfat/exfat_upcase.c linux-5.6.3/drivers/staging/exfat/exfat_upcase.c ---- linux-5.6.3.orig/drivers/staging/exfat/exfat_upcase.c 2020-03-30 01:25:41.000000000 +0300 -+++ linux-5.6.3/drivers/staging/exfat/exfat_upcase.c 1970-01-01 02:00:00.000000000 +0200 -@@ -1,740 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0-or-later --/* -- * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -- */ -- --#include --#include "exfat.h" -- --const u8 uni_upcase[NUM_UPCASE << 1] = { -- 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, -- 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, -- 0x08, 0x00, 0x09, 0x00, 0x0A, 0x00, 0x0B, 0x00, -- 0x0C, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x0F, 0x00, -- 0x10, 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, 0x00, -- 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x17, 0x00, -- 0x18, 0x00, 0x19, 0x00, 0x1A, 0x00, 0x1B, 0x00, -- 0x1C, 0x00, 0x1D, 0x00, 0x1E, 0x00, 0x1F, 0x00, -- 0x20, 0x00, 0x21, 0x00, 0x22, 0x00, 0x23, 0x00, -- 0x24, 0x00, 0x25, 0x00, 0x26, 0x00, 0x27, 0x00, -- 0x28, 0x00, 0x29, 0x00, 0x2A, 0x00, 0x2B, 0x00, -- 0x2C, 0x00, 0x2D, 0x00, 0x2E, 0x00, 0x2F, 0x00, -- 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, -- 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37, 0x00, -- 0x38, 0x00, 0x39, 0x00, 0x3A, 0x00, 0x3B, 0x00, -- 0x3C, 0x00, 0x3D, 0x00, 0x3E, 0x00, 0x3F, 0x00, -- 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, -- 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, -- 0x48, 0x00, 0x49, 0x00, 0x4A, 0x00, 0x4B, 0x00, -- 0x4C, 0x00, 0x4D, 0x00, 0x4E, 0x00, 0x4F, 0x00, -- 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00, -- 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00, -- 0x58, 0x00, 0x59, 0x00, 0x5A, 0x00, 0x5B, 0x00, -- 0x5C, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x5F, 0x00, -- 0x60, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, -- 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, -- 0x48, 0x00, 0x49, 0x00, 0x4A, 0x00, 0x4B, 0x00, -- 0x4C, 0x00, 0x4D, 0x00, 0x4E, 0x00, 0x4F, 0x00, -- 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00, -- 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00, -- 0x58, 0x00, 0x59, 0x00, 0x5A, 0x00, 0x7B, 0x00, -- 0x7C, 0x00, 0x7D, 0x00, 0x7E, 0x00, 0x7F, 0x00, -- 0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, -- 0x84, 0x00, 0x85, 0x00, 0x86, 0x00, 0x87, 0x00, -- 0x88, 0x00, 0x89, 0x00, 0x8A, 0x00, 0x8B, 0x00, -- 0x8C, 0x00, 0x8D, 0x00, 0x8E, 0x00, 0x8F, 0x00, -- 0x90, 0x00, 0x91, 0x00, 0x92, 0x00, 0x93, 0x00, -- 0x94, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00, -- 0x98, 0x00, 0x99, 0x00, 0x9A, 0x00, 0x9B, 0x00, -- 0x9C, 0x00, 0x9D, 0x00, 0x9E, 0x00, 0x9F, 0x00, -- 0xA0, 0x00, 0xA1, 0x00, 0xA2, 0x00, 0xA3, 0x00, -- 0xA4, 0x00, 0xA5, 0x00, 0xA6, 0x00, 0xA7, 0x00, -- 0xA8, 0x00, 0xA9, 0x00, 0xAA, 0x00, 0xAB, 0x00, -- 0xAC, 0x00, 0xAD, 0x00, 0xAE, 0x00, 0xAF, 0x00, -- 0xB0, 0x00, 0xB1, 0x00, 0xB2, 0x00, 0xB3, 0x00, -- 0xB4, 0x00, 0xB5, 0x00, 0xB6, 0x00, 0xB7, 0x00, -- 0xB8, 0x00, 0xB9, 0x00, 0xBA, 0x00, 0xBB, 0x00, -- 0xBC, 0x00, 0xBD, 0x00, 0xBE, 0x00, 0xBF, 0x00, -- 0xC0, 0x00, 0xC1, 0x00, 0xC2, 0x00, 0xC3, 0x00, -- 0xC4, 0x00, 0xC5, 0x00, 0xC6, 0x00, 0xC7, 0x00, -- 0xC8, 0x00, 0xC9, 0x00, 0xCA, 0x00, 0xCB, 0x00, -- 0xCC, 0x00, 0xCD, 0x00, 0xCE, 0x00, 0xCF, 0x00, -- 0xD0, 0x00, 0xD1, 0x00, 0xD2, 0x00, 0xD3, 0x00, -- 0xD4, 0x00, 0xD5, 0x00, 0xD6, 0x00, 0xD7, 0x00, -- 0xD8, 0x00, 0xD9, 0x00, 0xDA, 0x00, 0xDB, 0x00, -- 0xDC, 0x00, 0xDD, 0x00, 0xDE, 0x00, 0xDF, 0x00, -- 0xC0, 0x00, 0xC1, 0x00, 0xC2, 0x00, 0xC3, 0x00, -- 0xC4, 0x00, 0xC5, 0x00, 0xC6, 0x00, 0xC7, 0x00, -- 0xC8, 0x00, 0xC9, 0x00, 0xCA, 0x00, 0xCB, 0x00, -- 0xCC, 0x00, 0xCD, 0x00, 0xCE, 0x00, 0xCF, 0x00, -- 0xD0, 0x00, 0xD1, 0x00, 0xD2, 0x00, 0xD3, 0x00, -- 0xD4, 0x00, 0xD5, 0x00, 0xD6, 0x00, 0xF7, 0x00, -- 0xD8, 0x00, 0xD9, 0x00, 0xDA, 0x00, 0xDB, 0x00, -- 0xDC, 0x00, 0xDD, 0x00, 0xDE, 0x00, 0x78, 0x01, -- 0x00, 0x01, 0x00, 0x01, 0x02, 0x01, 0x02, 0x01, -- 0x04, 0x01, 0x04, 0x01, 0x06, 0x01, 0x06, 0x01, -- 0x08, 0x01, 0x08, 0x01, 0x0A, 0x01, 0x0A, 0x01, -- 0x0C, 0x01, 0x0C, 0x01, 0x0E, 0x01, 0x0E, 0x01, -- 0x10, 0x01, 0x10, 0x01, 0x12, 0x01, 0x12, 0x01, -- 0x14, 0x01, 0x14, 0x01, 0x16, 0x01, 0x16, 0x01, -- 0x18, 0x01, 0x18, 0x01, 0x1A, 0x01, 0x1A, 0x01, -- 0x1C, 0x01, 0x1C, 0x01, 0x1E, 0x01, 0x1E, 0x01, -- 0x20, 0x01, 0x20, 0x01, 0x22, 0x01, 0x22, 0x01, -- 0x24, 0x01, 0x24, 0x01, 0x26, 0x01, 0x26, 0x01, -- 0x28, 0x01, 0x28, 0x01, 0x2A, 0x01, 0x2A, 0x01, -- 0x2C, 0x01, 0x2C, 0x01, 0x2E, 0x01, 0x2E, 0x01, -- 0x30, 0x01, 0x31, 0x01, 0x32, 0x01, 0x32, 0x01, -- 0x34, 0x01, 0x34, 0x01, 0x36, 0x01, 0x36, 0x01, -- 0x38, 0x01, 0x39, 0x01, 0x39, 0x01, 0x3B, 0x01, -- 0x3B, 0x01, 0x3D, 0x01, 0x3D, 0x01, 0x3F, 0x01, -- 0x3F, 0x01, 0x41, 0x01, 0x41, 0x01, 0x43, 0x01, -- 0x43, 0x01, 0x45, 0x01, 0x45, 0x01, 0x47, 0x01, -- 0x47, 0x01, 0x49, 0x01, 0x4A, 0x01, 0x4A, 0x01, -- 0x4C, 0x01, 0x4C, 0x01, 0x4E, 0x01, 0x4E, 0x01, -- 0x50, 0x01, 0x50, 0x01, 0x52, 0x01, 0x52, 0x01, -- 0x54, 0x01, 0x54, 0x01, 0x56, 0x01, 0x56, 0x01, -- 0x58, 0x01, 0x58, 0x01, 0x5A, 0x01, 0x5A, 0x01, -- 0x5C, 0x01, 0x5C, 0x01, 0x5E, 0x01, 0x5E, 0x01, -- 0x60, 0x01, 0x60, 0x01, 0x62, 0x01, 0x62, 0x01, -- 0x64, 0x01, 0x64, 0x01, 0x66, 0x01, 0x66, 0x01, -- 0x68, 0x01, 0x68, 0x01, 0x6A, 0x01, 0x6A, 0x01, -- 0x6C, 0x01, 0x6C, 0x01, 0x6E, 0x01, 0x6E, 0x01, -- 0x70, 0x01, 0x70, 0x01, 0x72, 0x01, 0x72, 0x01, -- 0x74, 0x01, 0x74, 0x01, 0x76, 0x01, 0x76, 0x01, -- 0x78, 0x01, 0x79, 0x01, 0x79, 0x01, 0x7B, 0x01, -- 0x7B, 0x01, 0x7D, 0x01, 0x7D, 0x01, 0x7F, 0x01, -- 0x43, 0x02, 0x81, 0x01, 0x82, 0x01, 0x82, 0x01, -- 0x84, 0x01, 0x84, 0x01, 0x86, 0x01, 0x87, 0x01, -- 0x87, 0x01, 0x89, 0x01, 0x8A, 0x01, 0x8B, 0x01, -- 0x8B, 0x01, 0x8D, 0x01, 0x8E, 0x01, 0x8F, 0x01, -- 0x90, 0x01, 0x91, 0x01, 0x91, 0x01, 0x93, 0x01, -- 0x94, 0x01, 0xF6, 0x01, 0x96, 0x01, 0x97, 0x01, -- 0x98, 0x01, 0x98, 0x01, 0x3D, 0x02, 0x9B, 0x01, -- 0x9C, 0x01, 0x9D, 0x01, 0x20, 0x02, 0x9F, 0x01, -- 0xA0, 0x01, 0xA0, 0x01, 0xA2, 0x01, 0xA2, 0x01, -- 0xA4, 0x01, 0xA4, 0x01, 0xA6, 0x01, 0xA7, 0x01, -- 0xA7, 0x01, 0xA9, 0x01, 0xAA, 0x01, 0xAB, 0x01, -- 0xAC, 0x01, 0xAC, 0x01, 0xAE, 0x01, 0xAF, 0x01, -- 0xAF, 0x01, 0xB1, 0x01, 0xB2, 0x01, 0xB3, 0x01, -- 0xB3, 0x01, 0xB5, 0x01, 0xB5, 0x01, 0xB7, 0x01, -- 0xB8, 0x01, 0xB8, 0x01, 0xBA, 0x01, 0xBB, 0x01, -- 0xBC, 0x01, 0xBC, 0x01, 0xBE, 0x01, 0xF7, 0x01, -- 0xC0, 0x01, 0xC1, 0x01, 0xC2, 0x01, 0xC3, 0x01, -- 0xC4, 0x01, 0xC5, 0x01, 0xC4, 0x01, 0xC7, 0x01, -- 0xC8, 0x01, 0xC7, 0x01, 0xCA, 0x01, 0xCB, 0x01, -- 0xCA, 0x01, 0xCD, 0x01, 0xCD, 0x01, 0xCF, 0x01, -- 0xCF, 0x01, 0xD1, 0x01, 0xD1, 0x01, 0xD3, 0x01, -- 0xD3, 0x01, 0xD5, 0x01, 0xD5, 0x01, 0xD7, 0x01, -- 0xD7, 0x01, 0xD9, 0x01, 0xD9, 0x01, 0xDB, 0x01, -- 0xDB, 0x01, 0x8E, 0x01, 0xDE, 0x01, 0xDE, 0x01, -- 0xE0, 0x01, 0xE0, 0x01, 0xE2, 0x01, 0xE2, 0x01, -- 0xE4, 0x01, 0xE4, 0x01, 0xE6, 0x01, 0xE6, 0x01, -- 0xE8, 0x01, 0xE8, 0x01, 0xEA, 0x01, 0xEA, 0x01, -- 0xEC, 0x01, 0xEC, 0x01, 0xEE, 0x01, 0xEE, 0x01, -- 0xF0, 0x01, 0xF1, 0x01, 0xF2, 0x01, 0xF1, 0x01, -- 0xF4, 0x01, 0xF4, 0x01, 0xF6, 0x01, 0xF7, 0x01, -- 0xF8, 0x01, 0xF8, 0x01, 0xFA, 0x01, 0xFA, 0x01, -- 0xFC, 0x01, 0xFC, 0x01, 0xFE, 0x01, 0xFE, 0x01, -- 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, -- 0x04, 0x02, 0x04, 0x02, 0x06, 0x02, 0x06, 0x02, -- 0x08, 0x02, 0x08, 0x02, 0x0A, 0x02, 0x0A, 0x02, -- 0x0C, 0x02, 0x0C, 0x02, 0x0E, 0x02, 0x0E, 0x02, -- 0x10, 0x02, 0x10, 0x02, 0x12, 0x02, 0x12, 0x02, -- 0x14, 0x02, 0x14, 0x02, 0x16, 0x02, 0x16, 0x02, -- 0x18, 0x02, 0x18, 0x02, 0x1A, 0x02, 0x1A, 0x02, -- 0x1C, 0x02, 0x1C, 0x02, 0x1E, 0x02, 0x1E, 0x02, -- 0x20, 0x02, 0x21, 0x02, 0x22, 0x02, 0x22, 0x02, -- 0x24, 0x02, 0x24, 0x02, 0x26, 0x02, 0x26, 0x02, -- 0x28, 0x02, 0x28, 0x02, 0x2A, 0x02, 0x2A, 0x02, -- 0x2C, 0x02, 0x2C, 0x02, 0x2E, 0x02, 0x2E, 0x02, -- 0x30, 0x02, 0x30, 0x02, 0x32, 0x02, 0x32, 0x02, -- 0x34, 0x02, 0x35, 0x02, 0x36, 0x02, 0x37, 0x02, -- 0x38, 0x02, 0x39, 0x02, 0x65, 0x2C, 0x3B, 0x02, -- 0x3B, 0x02, 0x3D, 0x02, 0x66, 0x2C, 0x3F, 0x02, -- 0x40, 0x02, 0x41, 0x02, 0x41, 0x02, 0x43, 0x02, -- 0x44, 0x02, 0x45, 0x02, 0x46, 0x02, 0x46, 0x02, -- 0x48, 0x02, 0x48, 0x02, 0x4A, 0x02, 0x4A, 0x02, -- 0x4C, 0x02, 0x4C, 0x02, 0x4E, 0x02, 0x4E, 0x02, -- 0x50, 0x02, 0x51, 0x02, 0x52, 0x02, 0x81, 0x01, -- 0x86, 0x01, 0x55, 0x02, 0x89, 0x01, 0x8A, 0x01, -- 0x58, 0x02, 0x8F, 0x01, 0x5A, 0x02, 0x90, 0x01, -- 0x5C, 0x02, 0x5D, 0x02, 0x5E, 0x02, 0x5F, 0x02, -- 0x93, 0x01, 0x61, 0x02, 0x62, 0x02, 0x94, 0x01, -- 0x64, 0x02, 0x65, 0x02, 0x66, 0x02, 0x67, 0x02, -- 0x97, 0x01, 0x96, 0x01, 0x6A, 0x02, 0x62, 0x2C, -- 0x6C, 0x02, 0x6D, 0x02, 0x6E, 0x02, 0x9C, 0x01, -- 0x70, 0x02, 0x71, 0x02, 0x9D, 0x01, 0x73, 0x02, -- 0x74, 0x02, 0x9F, 0x01, 0x76, 0x02, 0x77, 0x02, -- 0x78, 0x02, 0x79, 0x02, 0x7A, 0x02, 0x7B, 0x02, -- 0x7C, 0x02, 0x64, 0x2C, 0x7E, 0x02, 0x7F, 0x02, -- 0xA6, 0x01, 0x81, 0x02, 0x82, 0x02, 0xA9, 0x01, -- 0x84, 0x02, 0x85, 0x02, 0x86, 0x02, 0x87, 0x02, -- 0xAE, 0x01, 0x44, 0x02, 0xB1, 0x01, 0xB2, 0x01, -- 0x45, 0x02, 0x8D, 0x02, 0x8E, 0x02, 0x8F, 0x02, -- 0x90, 0x02, 0x91, 0x02, 0xB7, 0x01, 0x93, 0x02, -- 0x94, 0x02, 0x95, 0x02, 0x96, 0x02, 0x97, 0x02, -- 0x98, 0x02, 0x99, 0x02, 0x9A, 0x02, 0x9B, 0x02, -- 0x9C, 0x02, 0x9D, 0x02, 0x9E, 0x02, 0x9F, 0x02, -- 0xA0, 0x02, 0xA1, 0x02, 0xA2, 0x02, 0xA3, 0x02, -- 0xA4, 0x02, 0xA5, 0x02, 0xA6, 0x02, 0xA7, 0x02, -- 0xA8, 0x02, 0xA9, 0x02, 0xAA, 0x02, 0xAB, 0x02, -- 0xAC, 0x02, 0xAD, 0x02, 0xAE, 0x02, 0xAF, 0x02, -- 0xB0, 0x02, 0xB1, 0x02, 0xB2, 0x02, 0xB3, 0x02, -- 0xB4, 0x02, 0xB5, 0x02, 0xB6, 0x02, 0xB7, 0x02, -- 0xB8, 0x02, 0xB9, 0x02, 0xBA, 0x02, 0xBB, 0x02, -- 0xBC, 0x02, 0xBD, 0x02, 0xBE, 0x02, 0xBF, 0x02, -- 0xC0, 0x02, 0xC1, 0x02, 0xC2, 0x02, 0xC3, 0x02, -- 0xC4, 0x02, 0xC5, 0x02, 0xC6, 0x02, 0xC7, 0x02, -- 0xC8, 0x02, 0xC9, 0x02, 0xCA, 0x02, 0xCB, 0x02, -- 0xCC, 0x02, 0xCD, 0x02, 0xCE, 0x02, 0xCF, 0x02, -- 0xD0, 0x02, 0xD1, 0x02, 0xD2, 0x02, 0xD3, 0x02, -- 0xD4, 0x02, 0xD5, 0x02, 0xD6, 0x02, 0xD7, 0x02, -- 0xD8, 0x02, 0xD9, 0x02, 0xDA, 0x02, 0xDB, 0x02, -- 0xDC, 0x02, 0xDD, 0x02, 0xDE, 0x02, 0xDF, 0x02, -- 0xE0, 0x02, 0xE1, 0x02, 0xE2, 0x02, 0xE3, 0x02, -- 0xE4, 0x02, 0xE5, 0x02, 0xE6, 0x02, 0xE7, 0x02, -- 0xE8, 0x02, 0xE9, 0x02, 0xEA, 0x02, 0xEB, 0x02, -- 0xEC, 0x02, 0xED, 0x02, 0xEE, 0x02, 0xEF, 0x02, -- 0xF0, 0x02, 0xF1, 0x02, 0xF2, 0x02, 0xF3, 0x02, -- 0xF4, 0x02, 0xF5, 0x02, 0xF6, 0x02, 0xF7, 0x02, -- 0xF8, 0x02, 0xF9, 0x02, 0xFA, 0x02, 0xFB, 0x02, -- 0xFC, 0x02, 0xFD, 0x02, 0xFE, 0x02, 0xFF, 0x02, -- 0x00, 0x03, 0x01, 0x03, 0x02, 0x03, 0x03, 0x03, -- 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x07, 0x03, -- 0x08, 0x03, 0x09, 0x03, 0x0A, 0x03, 0x0B, 0x03, -- 0x0C, 0x03, 0x0D, 0x03, 0x0E, 0x03, 0x0F, 0x03, -- 0x10, 0x03, 0x11, 0x03, 0x12, 0x03, 0x13, 0x03, -- 0x14, 0x03, 0x15, 0x03, 0x16, 0x03, 0x17, 0x03, -- 0x18, 0x03, 0x19, 0x03, 0x1A, 0x03, 0x1B, 0x03, -- 0x1C, 0x03, 0x1D, 0x03, 0x1E, 0x03, 0x1F, 0x03, -- 0x20, 0x03, 0x21, 0x03, 0x22, 0x03, 0x23, 0x03, -- 0x24, 0x03, 0x25, 0x03, 0x26, 0x03, 0x27, 0x03, -- 0x28, 0x03, 0x29, 0x03, 0x2A, 0x03, 0x2B, 0x03, -- 0x2C, 0x03, 0x2D, 0x03, 0x2E, 0x03, 0x2F, 0x03, -- 0x30, 0x03, 0x31, 0x03, 0x32, 0x03, 0x33, 0x03, -- 0x34, 0x03, 0x35, 0x03, 0x36, 0x03, 0x37, 0x03, -- 0x38, 0x03, 0x39, 0x03, 0x3A, 0x03, 0x3B, 0x03, -- 0x3C, 0x03, 0x3D, 0x03, 0x3E, 0x03, 0x3F, 0x03, -- 0x40, 0x03, 0x41, 0x03, 0x42, 0x03, 0x43, 0x03, -- 0x44, 0x03, 0x45, 0x03, 0x46, 0x03, 0x47, 0x03, -- 0x48, 0x03, 0x49, 0x03, 0x4A, 0x03, 0x4B, 0x03, -- 0x4C, 0x03, 0x4D, 0x03, 0x4E, 0x03, 0x4F, 0x03, -- 0x50, 0x03, 0x51, 0x03, 0x52, 0x03, 0x53, 0x03, -- 0x54, 0x03, 0x55, 0x03, 0x56, 0x03, 0x57, 0x03, -- 0x58, 0x03, 0x59, 0x03, 0x5A, 0x03, 0x5B, 0x03, -- 0x5C, 0x03, 0x5D, 0x03, 0x5E, 0x03, 0x5F, 0x03, -- 0x60, 0x03, 0x61, 0x03, 0x62, 0x03, 0x63, 0x03, -- 0x64, 0x03, 0x65, 0x03, 0x66, 0x03, 0x67, 0x03, -- 0x68, 0x03, 0x69, 0x03, 0x6A, 0x03, 0x6B, 0x03, -- 0x6C, 0x03, 0x6D, 0x03, 0x6E, 0x03, 0x6F, 0x03, -- 0x70, 0x03, 0x71, 0x03, 0x72, 0x03, 0x73, 0x03, -- 0x74, 0x03, 0x75, 0x03, 0x76, 0x03, 0x77, 0x03, -- 0x78, 0x03, 0x79, 0x03, 0x7A, 0x03, 0xFD, 0x03, -- 0xFE, 0x03, 0xFF, 0x03, 0x7E, 0x03, 0x7F, 0x03, -- 0x80, 0x03, 0x81, 0x03, 0x82, 0x03, 0x83, 0x03, -- 0x84, 0x03, 0x85, 0x03, 0x86, 0x03, 0x87, 0x03, -- 0x88, 0x03, 0x89, 0x03, 0x8A, 0x03, 0x8B, 0x03, -- 0x8C, 0x03, 0x8D, 0x03, 0x8E, 0x03, 0x8F, 0x03, -- 0x90, 0x03, 0x91, 0x03, 0x92, 0x03, 0x93, 0x03, -- 0x94, 0x03, 0x95, 0x03, 0x96, 0x03, 0x97, 0x03, -- 0x98, 0x03, 0x99, 0x03, 0x9A, 0x03, 0x9B, 0x03, -- 0x9C, 0x03, 0x9D, 0x03, 0x9E, 0x03, 0x9F, 0x03, -- 0xA0, 0x03, 0xA1, 0x03, 0xA2, 0x03, 0xA3, 0x03, -- 0xA4, 0x03, 0xA5, 0x03, 0xA6, 0x03, 0xA7, 0x03, -- 0xA8, 0x03, 0xA9, 0x03, 0xAA, 0x03, 0xAB, 0x03, -- 0x86, 0x03, 0x88, 0x03, 0x89, 0x03, 0x8A, 0x03, -- 0xB0, 0x03, 0x91, 0x03, 0x92, 0x03, 0x93, 0x03, -- 0x94, 0x03, 0x95, 0x03, 0x96, 0x03, 0x97, 0x03, -- 0x98, 0x03, 0x99, 0x03, 0x9A, 0x03, 0x9B, 0x03, -- 0x9C, 0x03, 0x9D, 0x03, 0x9E, 0x03, 0x9F, 0x03, -- 0xA0, 0x03, 0xA1, 0x03, 0xA3, 0x03, 0xA3, 0x03, -- 0xA4, 0x03, 0xA5, 0x03, 0xA6, 0x03, 0xA7, 0x03, -- 0xA8, 0x03, 0xA9, 0x03, 0xAA, 0x03, 0xAB, 0x03, -- 0x8C, 0x03, 0x8E, 0x03, 0x8F, 0x03, 0xCF, 0x03, -- 0xD0, 0x03, 0xD1, 0x03, 0xD2, 0x03, 0xD3, 0x03, -- 0xD4, 0x03, 0xD5, 0x03, 0xD6, 0x03, 0xD7, 0x03, -- 0xD8, 0x03, 0xD8, 0x03, 0xDA, 0x03, 0xDA, 0x03, -- 0xDC, 0x03, 0xDC, 0x03, 0xDE, 0x03, 0xDE, 0x03, -- 0xE0, 0x03, 0xE0, 0x03, 0xE2, 0x03, 0xE2, 0x03, -- 0xE4, 0x03, 0xE4, 0x03, 0xE6, 0x03, 0xE6, 0x03, -- 0xE8, 0x03, 0xE8, 0x03, 0xEA, 0x03, 0xEA, 0x03, -- 0xEC, 0x03, 0xEC, 0x03, 0xEE, 0x03, 0xEE, 0x03, -- 0xF0, 0x03, 0xF1, 0x03, 0xF9, 0x03, 0xF3, 0x03, -- 0xF4, 0x03, 0xF5, 0x03, 0xF6, 0x03, 0xF7, 0x03, -- 0xF7, 0x03, 0xF9, 0x03, 0xFA, 0x03, 0xFA, 0x03, -- 0xFC, 0x03, 0xFD, 0x03, 0xFE, 0x03, 0xFF, 0x03, -- 0x00, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x04, -- 0x04, 0x04, 0x05, 0x04, 0x06, 0x04, 0x07, 0x04, -- 0x08, 0x04, 0x09, 0x04, 0x0A, 0x04, 0x0B, 0x04, -- 0x0C, 0x04, 0x0D, 0x04, 0x0E, 0x04, 0x0F, 0x04, -- 0x10, 0x04, 0x11, 0x04, 0x12, 0x04, 0x13, 0x04, -- 0x14, 0x04, 0x15, 0x04, 0x16, 0x04, 0x17, 0x04, -- 0x18, 0x04, 0x19, 0x04, 0x1A, 0x04, 0x1B, 0x04, -- 0x1C, 0x04, 0x1D, 0x04, 0x1E, 0x04, 0x1F, 0x04, -- 0x20, 0x04, 0x21, 0x04, 0x22, 0x04, 0x23, 0x04, -- 0x24, 0x04, 0x25, 0x04, 0x26, 0x04, 0x27, 0x04, -- 0x28, 0x04, 0x29, 0x04, 0x2A, 0x04, 0x2B, 0x04, -- 0x2C, 0x04, 0x2D, 0x04, 0x2E, 0x04, 0x2F, 0x04, -- 0x10, 0x04, 0x11, 0x04, 0x12, 0x04, 0x13, 0x04, -- 0x14, 0x04, 0x15, 0x04, 0x16, 0x04, 0x17, 0x04, -- 0x18, 0x04, 0x19, 0x04, 0x1A, 0x04, 0x1B, 0x04, -- 0x1C, 0x04, 0x1D, 0x04, 0x1E, 0x04, 0x1F, 0x04, -- 0x20, 0x04, 0x21, 0x04, 0x22, 0x04, 0x23, 0x04, -- 0x24, 0x04, 0x25, 0x04, 0x26, 0x04, 0x27, 0x04, -- 0x28, 0x04, 0x29, 0x04, 0x2A, 0x04, 0x2B, 0x04, -- 0x2C, 0x04, 0x2D, 0x04, 0x2E, 0x04, 0x2F, 0x04, -- 0x00, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x04, -- 0x04, 0x04, 0x05, 0x04, 0x06, 0x04, 0x07, 0x04, -- 0x08, 0x04, 0x09, 0x04, 0x0A, 0x04, 0x0B, 0x04, -- 0x0C, 0x04, 0x0D, 0x04, 0x0E, 0x04, 0x0F, 0x04, -- 0x60, 0x04, 0x60, 0x04, 0x62, 0x04, 0x62, 0x04, -- 0x64, 0x04, 0x64, 0x04, 0x66, 0x04, 0x66, 0x04, -- 0x68, 0x04, 0x68, 0x04, 0x6A, 0x04, 0x6A, 0x04, -- 0x6C, 0x04, 0x6C, 0x04, 0x6E, 0x04, 0x6E, 0x04, -- 0x70, 0x04, 0x70, 0x04, 0x72, 0x04, 0x72, 0x04, -- 0x74, 0x04, 0x74, 0x04, 0x76, 0x04, 0x76, 0x04, -- 0x78, 0x04, 0x78, 0x04, 0x7A, 0x04, 0x7A, 0x04, -- 0x7C, 0x04, 0x7C, 0x04, 0x7E, 0x04, 0x7E, 0x04, -- 0x80, 0x04, 0x80, 0x04, 0x82, 0x04, 0x83, 0x04, -- 0x84, 0x04, 0x85, 0x04, 0x86, 0x04, 0x87, 0x04, -- 0x88, 0x04, 0x89, 0x04, 0x8A, 0x04, 0x8A, 0x04, -- 0x8C, 0x04, 0x8C, 0x04, 0x8E, 0x04, 0x8E, 0x04, -- 0x90, 0x04, 0x90, 0x04, 0x92, 0x04, 0x92, 0x04, -- 0x94, 0x04, 0x94, 0x04, 0x96, 0x04, 0x96, 0x04, -- 0x98, 0x04, 0x98, 0x04, 0x9A, 0x04, 0x9A, 0x04, -- 0x9C, 0x04, 0x9C, 0x04, 0x9E, 0x04, 0x9E, 0x04, -- 0xA0, 0x04, 0xA0, 0x04, 0xA2, 0x04, 0xA2, 0x04, -- 0xA4, 0x04, 0xA4, 0x04, 0xA6, 0x04, 0xA6, 0x04, -- 0xA8, 0x04, 0xA8, 0x04, 0xAA, 0x04, 0xAA, 0x04, -- 0xAC, 0x04, 0xAC, 0x04, 0xAE, 0x04, 0xAE, 0x04, -- 0xB0, 0x04, 0xB0, 0x04, 0xB2, 0x04, 0xB2, 0x04, -- 0xB4, 0x04, 0xB4, 0x04, 0xB6, 0x04, 0xB6, 0x04, -- 0xB8, 0x04, 0xB8, 0x04, 0xBA, 0x04, 0xBA, 0x04, -- 0xBC, 0x04, 0xBC, 0x04, 0xBE, 0x04, 0xBE, 0x04, -- 0xC0, 0x04, 0xC1, 0x04, 0xC1, 0x04, 0xC3, 0x04, -- 0xC3, 0x04, 0xC5, 0x04, 0xC5, 0x04, 0xC7, 0x04, -- 0xC7, 0x04, 0xC9, 0x04, 0xC9, 0x04, 0xCB, 0x04, -- 0xCB, 0x04, 0xCD, 0x04, 0xCD, 0x04, 0xC0, 0x04, -- 0xD0, 0x04, 0xD0, 0x04, 0xD2, 0x04, 0xD2, 0x04, -- 0xD4, 0x04, 0xD4, 0x04, 0xD6, 0x04, 0xD6, 0x04, -- 0xD8, 0x04, 0xD8, 0x04, 0xDA, 0x04, 0xDA, 0x04, -- 0xDC, 0x04, 0xDC, 0x04, 0xDE, 0x04, 0xDE, 0x04, -- 0xE0, 0x04, 0xE0, 0x04, 0xE2, 0x04, 0xE2, 0x04, -- 0xE4, 0x04, 0xE4, 0x04, 0xE6, 0x04, 0xE6, 0x04, -- 0xE8, 0x04, 0xE8, 0x04, 0xEA, 0x04, 0xEA, 0x04, -- 0xEC, 0x04, 0xEC, 0x04, 0xEE, 0x04, 0xEE, 0x04, -- 0xF0, 0x04, 0xF0, 0x04, 0xF2, 0x04, 0xF2, 0x04, -- 0xF4, 0x04, 0xF4, 0x04, 0xF6, 0x04, 0xF6, 0x04, -- 0xF8, 0x04, 0xF8, 0x04, 0xFA, 0x04, 0xFA, 0x04, -- 0xFC, 0x04, 0xFC, 0x04, 0xFE, 0x04, 0xFE, 0x04, -- 0x00, 0x05, 0x00, 0x05, 0x02, 0x05, 0x02, 0x05, -- 0x04, 0x05, 0x04, 0x05, 0x06, 0x05, 0x06, 0x05, -- 0x08, 0x05, 0x08, 0x05, 0x0A, 0x05, 0x0A, 0x05, -- 0x0C, 0x05, 0x0C, 0x05, 0x0E, 0x05, 0x0E, 0x05, -- 0x10, 0x05, 0x10, 0x05, 0x12, 0x05, 0x12, 0x05, -- 0x14, 0x05, 0x15, 0x05, 0x16, 0x05, 0x17, 0x05, -- 0x18, 0x05, 0x19, 0x05, 0x1A, 0x05, 0x1B, 0x05, -- 0x1C, 0x05, 0x1D, 0x05, 0x1E, 0x05, 0x1F, 0x05, -- 0x20, 0x05, 0x21, 0x05, 0x22, 0x05, 0x23, 0x05, -- 0x24, 0x05, 0x25, 0x05, 0x26, 0x05, 0x27, 0x05, -- 0x28, 0x05, 0x29, 0x05, 0x2A, 0x05, 0x2B, 0x05, -- 0x2C, 0x05, 0x2D, 0x05, 0x2E, 0x05, 0x2F, 0x05, -- 0x30, 0x05, 0x31, 0x05, 0x32, 0x05, 0x33, 0x05, -- 0x34, 0x05, 0x35, 0x05, 0x36, 0x05, 0x37, 0x05, -- 0x38, 0x05, 0x39, 0x05, 0x3A, 0x05, 0x3B, 0x05, -- 0x3C, 0x05, 0x3D, 0x05, 0x3E, 0x05, 0x3F, 0x05, -- 0x40, 0x05, 0x41, 0x05, 0x42, 0x05, 0x43, 0x05, -- 0x44, 0x05, 0x45, 0x05, 0x46, 0x05, 0x47, 0x05, -- 0x48, 0x05, 0x49, 0x05, 0x4A, 0x05, 0x4B, 0x05, -- 0x4C, 0x05, 0x4D, 0x05, 0x4E, 0x05, 0x4F, 0x05, -- 0x50, 0x05, 0x51, 0x05, 0x52, 0x05, 0x53, 0x05, -- 0x54, 0x05, 0x55, 0x05, 0x56, 0x05, 0x57, 0x05, -- 0x58, 0x05, 0x59, 0x05, 0x5A, 0x05, 0x5B, 0x05, -- 0x5C, 0x05, 0x5D, 0x05, 0x5E, 0x05, 0x5F, 0x05, -- 0x60, 0x05, 0x31, 0x05, 0x32, 0x05, 0x33, 0x05, -- 0x34, 0x05, 0x35, 0x05, 0x36, 0x05, 0x37, 0x05, -- 0x38, 0x05, 0x39, 0x05, 0x3A, 0x05, 0x3B, 0x05, -- 0x3C, 0x05, 0x3D, 0x05, 0x3E, 0x05, 0x3F, 0x05, -- 0x40, 0x05, 0x41, 0x05, 0x42, 0x05, 0x43, 0x05, -- 0x44, 0x05, 0x45, 0x05, 0x46, 0x05, 0x47, 0x05, -- 0x48, 0x05, 0x49, 0x05, 0x4A, 0x05, 0x4B, 0x05, -- 0x4C, 0x05, 0x4D, 0x05, 0x4E, 0x05, 0x4F, 0x05, -- 0x50, 0x05, 0x51, 0x05, 0x52, 0x05, 0x53, 0x05, -- 0x54, 0x05, 0x55, 0x05, 0x56, 0x05, 0xFF, 0xFF, -- 0xF6, 0x17, 0x63, 0x2C, 0x7E, 0x1D, 0x7F, 0x1D, -- 0x80, 0x1D, 0x81, 0x1D, 0x82, 0x1D, 0x83, 0x1D, -- 0x84, 0x1D, 0x85, 0x1D, 0x86, 0x1D, 0x87, 0x1D, -- 0x88, 0x1D, 0x89, 0x1D, 0x8A, 0x1D, 0x8B, 0x1D, -- 0x8C, 0x1D, 0x8D, 0x1D, 0x8E, 0x1D, 0x8F, 0x1D, -- 0x90, 0x1D, 0x91, 0x1D, 0x92, 0x1D, 0x93, 0x1D, -- 0x94, 0x1D, 0x95, 0x1D, 0x96, 0x1D, 0x97, 0x1D, -- 0x98, 0x1D, 0x99, 0x1D, 0x9A, 0x1D, 0x9B, 0x1D, -- 0x9C, 0x1D, 0x9D, 0x1D, 0x9E, 0x1D, 0x9F, 0x1D, -- 0xA0, 0x1D, 0xA1, 0x1D, 0xA2, 0x1D, 0xA3, 0x1D, -- 0xA4, 0x1D, 0xA5, 0x1D, 0xA6, 0x1D, 0xA7, 0x1D, -- 0xA8, 0x1D, 0xA9, 0x1D, 0xAA, 0x1D, 0xAB, 0x1D, -- 0xAC, 0x1D, 0xAD, 0x1D, 0xAE, 0x1D, 0xAF, 0x1D, -- 0xB0, 0x1D, 0xB1, 0x1D, 0xB2, 0x1D, 0xB3, 0x1D, -- 0xB4, 0x1D, 0xB5, 0x1D, 0xB6, 0x1D, 0xB7, 0x1D, -- 0xB8, 0x1D, 0xB9, 0x1D, 0xBA, 0x1D, 0xBB, 0x1D, -- 0xBC, 0x1D, 0xBD, 0x1D, 0xBE, 0x1D, 0xBF, 0x1D, -- 0xC0, 0x1D, 0xC1, 0x1D, 0xC2, 0x1D, 0xC3, 0x1D, -- 0xC4, 0x1D, 0xC5, 0x1D, 0xC6, 0x1D, 0xC7, 0x1D, -- 0xC8, 0x1D, 0xC9, 0x1D, 0xCA, 0x1D, 0xCB, 0x1D, -- 0xCC, 0x1D, 0xCD, 0x1D, 0xCE, 0x1D, 0xCF, 0x1D, -- 0xD0, 0x1D, 0xD1, 0x1D, 0xD2, 0x1D, 0xD3, 0x1D, -- 0xD4, 0x1D, 0xD5, 0x1D, 0xD6, 0x1D, 0xD7, 0x1D, -- 0xD8, 0x1D, 0xD9, 0x1D, 0xDA, 0x1D, 0xDB, 0x1D, -- 0xDC, 0x1D, 0xDD, 0x1D, 0xDE, 0x1D, 0xDF, 0x1D, -- 0xE0, 0x1D, 0xE1, 0x1D, 0xE2, 0x1D, 0xE3, 0x1D, -- 0xE4, 0x1D, 0xE5, 0x1D, 0xE6, 0x1D, 0xE7, 0x1D, -- 0xE8, 0x1D, 0xE9, 0x1D, 0xEA, 0x1D, 0xEB, 0x1D, -- 0xEC, 0x1D, 0xED, 0x1D, 0xEE, 0x1D, 0xEF, 0x1D, -- 0xF0, 0x1D, 0xF1, 0x1D, 0xF2, 0x1D, 0xF3, 0x1D, -- 0xF4, 0x1D, 0xF5, 0x1D, 0xF6, 0x1D, 0xF7, 0x1D, -- 0xF8, 0x1D, 0xF9, 0x1D, 0xFA, 0x1D, 0xFB, 0x1D, -- 0xFC, 0x1D, 0xFD, 0x1D, 0xFE, 0x1D, 0xFF, 0x1D, -- 0x00, 0x1E, 0x00, 0x1E, 0x02, 0x1E, 0x02, 0x1E, -- 0x04, 0x1E, 0x04, 0x1E, 0x06, 0x1E, 0x06, 0x1E, -- 0x08, 0x1E, 0x08, 0x1E, 0x0A, 0x1E, 0x0A, 0x1E, -- 0x0C, 0x1E, 0x0C, 0x1E, 0x0E, 0x1E, 0x0E, 0x1E, -- 0x10, 0x1E, 0x10, 0x1E, 0x12, 0x1E, 0x12, 0x1E, -- 0x14, 0x1E, 0x14, 0x1E, 0x16, 0x1E, 0x16, 0x1E, -- 0x18, 0x1E, 0x18, 0x1E, 0x1A, 0x1E, 0x1A, 0x1E, -- 0x1C, 0x1E, 0x1C, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, -- 0x20, 0x1E, 0x20, 0x1E, 0x22, 0x1E, 0x22, 0x1E, -- 0x24, 0x1E, 0x24, 0x1E, 0x26, 0x1E, 0x26, 0x1E, -- 0x28, 0x1E, 0x28, 0x1E, 0x2A, 0x1E, 0x2A, 0x1E, -- 0x2C, 0x1E, 0x2C, 0x1E, 0x2E, 0x1E, 0x2E, 0x1E, -- 0x30, 0x1E, 0x30, 0x1E, 0x32, 0x1E, 0x32, 0x1E, -- 0x34, 0x1E, 0x34, 0x1E, 0x36, 0x1E, 0x36, 0x1E, -- 0x38, 0x1E, 0x38, 0x1E, 0x3A, 0x1E, 0x3A, 0x1E, -- 0x3C, 0x1E, 0x3C, 0x1E, 0x3E, 0x1E, 0x3E, 0x1E, -- 0x40, 0x1E, 0x40, 0x1E, 0x42, 0x1E, 0x42, 0x1E, -- 0x44, 0x1E, 0x44, 0x1E, 0x46, 0x1E, 0x46, 0x1E, -- 0x48, 0x1E, 0x48, 0x1E, 0x4A, 0x1E, 0x4A, 0x1E, -- 0x4C, 0x1E, 0x4C, 0x1E, 0x4E, 0x1E, 0x4E, 0x1E, -- 0x50, 0x1E, 0x50, 0x1E, 0x52, 0x1E, 0x52, 0x1E, -- 0x54, 0x1E, 0x54, 0x1E, 0x56, 0x1E, 0x56, 0x1E, -- 0x58, 0x1E, 0x58, 0x1E, 0x5A, 0x1E, 0x5A, 0x1E, -- 0x5C, 0x1E, 0x5C, 0x1E, 0x5E, 0x1E, 0x5E, 0x1E, -- 0x60, 0x1E, 0x60, 0x1E, 0x62, 0x1E, 0x62, 0x1E, -- 0x64, 0x1E, 0x64, 0x1E, 0x66, 0x1E, 0x66, 0x1E, -- 0x68, 0x1E, 0x68, 0x1E, 0x6A, 0x1E, 0x6A, 0x1E, -- 0x6C, 0x1E, 0x6C, 0x1E, 0x6E, 0x1E, 0x6E, 0x1E, -- 0x70, 0x1E, 0x70, 0x1E, 0x72, 0x1E, 0x72, 0x1E, -- 0x74, 0x1E, 0x74, 0x1E, 0x76, 0x1E, 0x76, 0x1E, -- 0x78, 0x1E, 0x78, 0x1E, 0x7A, 0x1E, 0x7A, 0x1E, -- 0x7C, 0x1E, 0x7C, 0x1E, 0x7E, 0x1E, 0x7E, 0x1E, -- 0x80, 0x1E, 0x80, 0x1E, 0x82, 0x1E, 0x82, 0x1E, -- 0x84, 0x1E, 0x84, 0x1E, 0x86, 0x1E, 0x86, 0x1E, -- 0x88, 0x1E, 0x88, 0x1E, 0x8A, 0x1E, 0x8A, 0x1E, -- 0x8C, 0x1E, 0x8C, 0x1E, 0x8E, 0x1E, 0x8E, 0x1E, -- 0x90, 0x1E, 0x90, 0x1E, 0x92, 0x1E, 0x92, 0x1E, -- 0x94, 0x1E, 0x94, 0x1E, 0x96, 0x1E, 0x97, 0x1E, -- 0x98, 0x1E, 0x99, 0x1E, 0x9A, 0x1E, 0x9B, 0x1E, -- 0x9C, 0x1E, 0x9D, 0x1E, 0x9E, 0x1E, 0x9F, 0x1E, -- 0xA0, 0x1E, 0xA0, 0x1E, 0xA2, 0x1E, 0xA2, 0x1E, -- 0xA4, 0x1E, 0xA4, 0x1E, 0xA6, 0x1E, 0xA6, 0x1E, -- 0xA8, 0x1E, 0xA8, 0x1E, 0xAA, 0x1E, 0xAA, 0x1E, -- 0xAC, 0x1E, 0xAC, 0x1E, 0xAE, 0x1E, 0xAE, 0x1E, -- 0xB0, 0x1E, 0xB0, 0x1E, 0xB2, 0x1E, 0xB2, 0x1E, -- 0xB4, 0x1E, 0xB4, 0x1E, 0xB6, 0x1E, 0xB6, 0x1E, -- 0xB8, 0x1E, 0xB8, 0x1E, 0xBA, 0x1E, 0xBA, 0x1E, -- 0xBC, 0x1E, 0xBC, 0x1E, 0xBE, 0x1E, 0xBE, 0x1E, -- 0xC0, 0x1E, 0xC0, 0x1E, 0xC2, 0x1E, 0xC2, 0x1E, -- 0xC4, 0x1E, 0xC4, 0x1E, 0xC6, 0x1E, 0xC6, 0x1E, -- 0xC8, 0x1E, 0xC8, 0x1E, 0xCA, 0x1E, 0xCA, 0x1E, -- 0xCC, 0x1E, 0xCC, 0x1E, 0xCE, 0x1E, 0xCE, 0x1E, -- 0xD0, 0x1E, 0xD0, 0x1E, 0xD2, 0x1E, 0xD2, 0x1E, -- 0xD4, 0x1E, 0xD4, 0x1E, 0xD6, 0x1E, 0xD6, 0x1E, -- 0xD8, 0x1E, 0xD8, 0x1E, 0xDA, 0x1E, 0xDA, 0x1E, -- 0xDC, 0x1E, 0xDC, 0x1E, 0xDE, 0x1E, 0xDE, 0x1E, -- 0xE0, 0x1E, 0xE0, 0x1E, 0xE2, 0x1E, 0xE2, 0x1E, -- 0xE4, 0x1E, 0xE4, 0x1E, 0xE6, 0x1E, 0xE6, 0x1E, -- 0xE8, 0x1E, 0xE8, 0x1E, 0xEA, 0x1E, 0xEA, 0x1E, -- 0xEC, 0x1E, 0xEC, 0x1E, 0xEE, 0x1E, 0xEE, 0x1E, -- 0xF0, 0x1E, 0xF0, 0x1E, 0xF2, 0x1E, 0xF2, 0x1E, -- 0xF4, 0x1E, 0xF4, 0x1E, 0xF6, 0x1E, 0xF6, 0x1E, -- 0xF8, 0x1E, 0xF8, 0x1E, 0xFA, 0x1E, 0xFB, 0x1E, -- 0xFC, 0x1E, 0xFD, 0x1E, 0xFE, 0x1E, 0xFF, 0x1E, -- 0x08, 0x1F, 0x09, 0x1F, 0x0A, 0x1F, 0x0B, 0x1F, -- 0x0C, 0x1F, 0x0D, 0x1F, 0x0E, 0x1F, 0x0F, 0x1F, -- 0x08, 0x1F, 0x09, 0x1F, 0x0A, 0x1F, 0x0B, 0x1F, -- 0x0C, 0x1F, 0x0D, 0x1F, 0x0E, 0x1F, 0x0F, 0x1F, -- 0x18, 0x1F, 0x19, 0x1F, 0x1A, 0x1F, 0x1B, 0x1F, -- 0x1C, 0x1F, 0x1D, 0x1F, 0x16, 0x1F, 0x17, 0x1F, -- 0x18, 0x1F, 0x19, 0x1F, 0x1A, 0x1F, 0x1B, 0x1F, -- 0x1C, 0x1F, 0x1D, 0x1F, 0x1E, 0x1F, 0x1F, 0x1F, -- 0x28, 0x1F, 0x29, 0x1F, 0x2A, 0x1F, 0x2B, 0x1F, -- 0x2C, 0x1F, 0x2D, 0x1F, 0x2E, 0x1F, 0x2F, 0x1F, -- 0x28, 0x1F, 0x29, 0x1F, 0x2A, 0x1F, 0x2B, 0x1F, -- 0x2C, 0x1F, 0x2D, 0x1F, 0x2E, 0x1F, 0x2F, 0x1F, -- 0x38, 0x1F, 0x39, 0x1F, 0x3A, 0x1F, 0x3B, 0x1F, -- 0x3C, 0x1F, 0x3D, 0x1F, 0x3E, 0x1F, 0x3F, 0x1F, -- 0x38, 0x1F, 0x39, 0x1F, 0x3A, 0x1F, 0x3B, 0x1F, -- 0x3C, 0x1F, 0x3D, 0x1F, 0x3E, 0x1F, 0x3F, 0x1F, -- 0x48, 0x1F, 0x49, 0x1F, 0x4A, 0x1F, 0x4B, 0x1F, -- 0x4C, 0x1F, 0x4D, 0x1F, 0x46, 0x1F, 0x47, 0x1F, -- 0x48, 0x1F, 0x49, 0x1F, 0x4A, 0x1F, 0x4B, 0x1F, -- 0x4C, 0x1F, 0x4D, 0x1F, 0x4E, 0x1F, 0x4F, 0x1F, -- 0x50, 0x1F, 0x59, 0x1F, 0x52, 0x1F, 0x5B, 0x1F, -- 0x54, 0x1F, 0x5D, 0x1F, 0x56, 0x1F, 0x5F, 0x1F, -- 0x58, 0x1F, 0x59, 0x1F, 0x5A, 0x1F, 0x5B, 0x1F, -- 0x5C, 0x1F, 0x5D, 0x1F, 0x5E, 0x1F, 0x5F, 0x1F, -- 0x68, 0x1F, 0x69, 0x1F, 0x6A, 0x1F, 0x6B, 0x1F, -- 0x6C, 0x1F, 0x6D, 0x1F, 0x6E, 0x1F, 0x6F, 0x1F, -- 0x68, 0x1F, 0x69, 0x1F, 0x6A, 0x1F, 0x6B, 0x1F, -- 0x6C, 0x1F, 0x6D, 0x1F, 0x6E, 0x1F, 0x6F, 0x1F, -- 0xBA, 0x1F, 0xBB, 0x1F, 0xC8, 0x1F, 0xC9, 0x1F, -- 0xCA, 0x1F, 0xCB, 0x1F, 0xDA, 0x1F, 0xDB, 0x1F, -- 0xF8, 0x1F, 0xF9, 0x1F, 0xEA, 0x1F, 0xEB, 0x1F, -- 0xFA, 0x1F, 0xFB, 0x1F, 0x7E, 0x1F, 0x7F, 0x1F, -- 0x88, 0x1F, 0x89, 0x1F, 0x8A, 0x1F, 0x8B, 0x1F, -- 0x8C, 0x1F, 0x8D, 0x1F, 0x8E, 0x1F, 0x8F, 0x1F, -- 0x88, 0x1F, 0x89, 0x1F, 0x8A, 0x1F, 0x8B, 0x1F, -- 0x8C, 0x1F, 0x8D, 0x1F, 0x8E, 0x1F, 0x8F, 0x1F, -- 0x98, 0x1F, 0x99, 0x1F, 0x9A, 0x1F, 0x9B, 0x1F, -- 0x9C, 0x1F, 0x9D, 0x1F, 0x9E, 0x1F, 0x9F, 0x1F, -- 0x98, 0x1F, 0x99, 0x1F, 0x9A, 0x1F, 0x9B, 0x1F, -- 0x9C, 0x1F, 0x9D, 0x1F, 0x9E, 0x1F, 0x9F, 0x1F, -- 0xA8, 0x1F, 0xA9, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F, -- 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 0x1F, 0xAF, 0x1F, -- 0xA8, 0x1F, 0xA9, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F, -- 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 0x1F, 0xAF, 0x1F, -- 0xB8, 0x1F, 0xB9, 0x1F, 0xB2, 0x1F, 0xBC, 0x1F, -- 0xB4, 0x1F, 0xB5, 0x1F, 0xB6, 0x1F, 0xB7, 0x1F, -- 0xB8, 0x1F, 0xB9, 0x1F, 0xBA, 0x1F, 0xBB, 0x1F, -- 0xBC, 0x1F, 0xBD, 0x1F, 0xBE, 0x1F, 0xBF, 0x1F, -- 0xC0, 0x1F, 0xC1, 0x1F, 0xC2, 0x1F, 0xC3, 0x1F, -- 0xC4, 0x1F, 0xC5, 0x1F, 0xC6, 0x1F, 0xC7, 0x1F, -- 0xC8, 0x1F, 0xC9, 0x1F, 0xCA, 0x1F, 0xCB, 0x1F, -- 0xC3, 0x1F, 0xCD, 0x1F, 0xCE, 0x1F, 0xCF, 0x1F, -- 0xD8, 0x1F, 0xD9, 0x1F, 0xD2, 0x1F, 0xD3, 0x1F, -- 0xD4, 0x1F, 0xD5, 0x1F, 0xD6, 0x1F, 0xD7, 0x1F, -- 0xD8, 0x1F, 0xD9, 0x1F, 0xDA, 0x1F, 0xDB, 0x1F, -- 0xDC, 0x1F, 0xDD, 0x1F, 0xDE, 0x1F, 0xDF, 0x1F, -- 0xE8, 0x1F, 0xE9, 0x1F, 0xE2, 0x1F, 0xE3, 0x1F, -- 0xE4, 0x1F, 0xEC, 0x1F, 0xE6, 0x1F, 0xE7, 0x1F, -- 0xE8, 0x1F, 0xE9, 0x1F, 0xEA, 0x1F, 0xEB, 0x1F, -- 0xEC, 0x1F, 0xED, 0x1F, 0xEE, 0x1F, 0xEF, 0x1F, -- 0xF0, 0x1F, 0xF1, 0x1F, 0xF2, 0x1F, 0xF3, 0x1F, -- 0xF4, 0x1F, 0xF5, 0x1F, 0xF6, 0x1F, 0xF7, 0x1F, -- 0xF8, 0x1F, 0xF9, 0x1F, 0xFA, 0x1F, 0xFB, 0x1F, -- 0xF3, 0x1F, 0xFD, 0x1F, 0xFE, 0x1F, 0xFF, 0x1F, -- 0x00, 0x20, 0x01, 0x20, 0x02, 0x20, 0x03, 0x20, -- 0x04, 0x20, 0x05, 0x20, 0x06, 0x20, 0x07, 0x20, -- 0x08, 0x20, 0x09, 0x20, 0x0A, 0x20, 0x0B, 0x20, -- 0x0C, 0x20, 0x0D, 0x20, 0x0E, 0x20, 0x0F, 0x20, -- 0x10, 0x20, 0x11, 0x20, 0x12, 0x20, 0x13, 0x20, -- 0x14, 0x20, 0x15, 0x20, 0x16, 0x20, 0x17, 0x20, -- 0x18, 0x20, 0x19, 0x20, 0x1A, 0x20, 0x1B, 0x20, -- 0x1C, 0x20, 0x1D, 0x20, 0x1E, 0x20, 0x1F, 0x20, -- 0x20, 0x20, 0x21, 0x20, 0x22, 0x20, 0x23, 0x20, -- 0x24, 0x20, 0x25, 0x20, 0x26, 0x20, 0x27, 0x20, -- 0x28, 0x20, 0x29, 0x20, 0x2A, 0x20, 0x2B, 0x20, -- 0x2C, 0x20, 0x2D, 0x20, 0x2E, 0x20, 0x2F, 0x20, -- 0x30, 0x20, 0x31, 0x20, 0x32, 0x20, 0x33, 0x20, -- 0x34, 0x20, 0x35, 0x20, 0x36, 0x20, 0x37, 0x20, -- 0x38, 0x20, 0x39, 0x20, 0x3A, 0x20, 0x3B, 0x20, -- 0x3C, 0x20, 0x3D, 0x20, 0x3E, 0x20, 0x3F, 0x20, -- 0x40, 0x20, 0x41, 0x20, 0x42, 0x20, 0x43, 0x20, -- 0x44, 0x20, 0x45, 0x20, 0x46, 0x20, 0x47, 0x20, -- 0x48, 0x20, 0x49, 0x20, 0x4A, 0x20, 0x4B, 0x20, -- 0x4C, 0x20, 0x4D, 0x20, 0x4E, 0x20, 0x4F, 0x20, -- 0x50, 0x20, 0x51, 0x20, 0x52, 0x20, 0x53, 0x20, -- 0x54, 0x20, 0x55, 0x20, 0x56, 0x20, 0x57, 0x20, -- 0x58, 0x20, 0x59, 0x20, 0x5A, 0x20, 0x5B, 0x20, -- 0x5C, 0x20, 0x5D, 0x20, 0x5E, 0x20, 0x5F, 0x20, -- 0x60, 0x20, 0x61, 0x20, 0x62, 0x20, 0x63, 0x20, -- 0x64, 0x20, 0x65, 0x20, 0x66, 0x20, 0x67, 0x20, -- 0x68, 0x20, 0x69, 0x20, 0x6A, 0x20, 0x6B, 0x20, -- 0x6C, 0x20, 0x6D, 0x20, 0x6E, 0x20, 0x6F, 0x20, -- 0x70, 0x20, 0x71, 0x20, 0x72, 0x20, 0x73, 0x20, -- 0x74, 0x20, 0x75, 0x20, 0x76, 0x20, 0x77, 0x20, -- 0x78, 0x20, 0x79, 0x20, 0x7A, 0x20, 0x7B, 0x20, -- 0x7C, 0x20, 0x7D, 0x20, 0x7E, 0x20, 0x7F, 0x20, -- 0x80, 0x20, 0x81, 0x20, 0x82, 0x20, 0x83, 0x20, -- 0x84, 0x20, 0x85, 0x20, 0x86, 0x20, 0x87, 0x20, -- 0x88, 0x20, 0x89, 0x20, 0x8A, 0x20, 0x8B, 0x20, -- 0x8C, 0x20, 0x8D, 0x20, 0x8E, 0x20, 0x8F, 0x20, -- 0x90, 0x20, 0x91, 0x20, 0x92, 0x20, 0x93, 0x20, -- 0x94, 0x20, 0x95, 0x20, 0x96, 0x20, 0x97, 0x20, -- 0x98, 0x20, 0x99, 0x20, 0x9A, 0x20, 0x9B, 0x20, -- 0x9C, 0x20, 0x9D, 0x20, 0x9E, 0x20, 0x9F, 0x20, -- 0xA0, 0x20, 0xA1, 0x20, 0xA2, 0x20, 0xA3, 0x20, -- 0xA4, 0x20, 0xA5, 0x20, 0xA6, 0x20, 0xA7, 0x20, -- 0xA8, 0x20, 0xA9, 0x20, 0xAA, 0x20, 0xAB, 0x20, -- 0xAC, 0x20, 0xAD, 0x20, 0xAE, 0x20, 0xAF, 0x20, -- 0xB0, 0x20, 0xB1, 0x20, 0xB2, 0x20, 0xB3, 0x20, -- 0xB4, 0x20, 0xB5, 0x20, 0xB6, 0x20, 0xB7, 0x20, -- 0xB8, 0x20, 0xB9, 0x20, 0xBA, 0x20, 0xBB, 0x20, -- 0xBC, 0x20, 0xBD, 0x20, 0xBE, 0x20, 0xBF, 0x20, -- 0xC0, 0x20, 0xC1, 0x20, 0xC2, 0x20, 0xC3, 0x20, -- 0xC4, 0x20, 0xC5, 0x20, 0xC6, 0x20, 0xC7, 0x20, -- 0xC8, 0x20, 0xC9, 0x20, 0xCA, 0x20, 0xCB, 0x20, -- 0xCC, 0x20, 0xCD, 0x20, 0xCE, 0x20, 0xCF, 0x20, -- 0xD0, 0x20, 0xD1, 0x20, 0xD2, 0x20, 0xD3, 0x20, -- 0xD4, 0x20, 0xD5, 0x20, 0xD6, 0x20, 0xD7, 0x20, -- 0xD8, 0x20, 0xD9, 0x20, 0xDA, 0x20, 0xDB, 0x20, -- 0xDC, 0x20, 0xDD, 0x20, 0xDE, 0x20, 0xDF, 0x20, -- 0xE0, 0x20, 0xE1, 0x20, 0xE2, 0x20, 0xE3, 0x20, -- 0xE4, 0x20, 0xE5, 0x20, 0xE6, 0x20, 0xE7, 0x20, -- 0xE8, 0x20, 0xE9, 0x20, 0xEA, 0x20, 0xEB, 0x20, -- 0xEC, 0x20, 0xED, 0x20, 0xEE, 0x20, 0xEF, 0x20, -- 0xF0, 0x20, 0xF1, 0x20, 0xF2, 0x20, 0xF3, 0x20, -- 0xF4, 0x20, 0xF5, 0x20, 0xF6, 0x20, 0xF7, 0x20, -- 0xF8, 0x20, 0xF9, 0x20, 0xFA, 0x20, 0xFB, 0x20, -- 0xFC, 0x20, 0xFD, 0x20, 0xFE, 0x20, 0xFF, 0x20, -- 0x00, 0x21, 0x01, 0x21, 0x02, 0x21, 0x03, 0x21, -- 0x04, 0x21, 0x05, 0x21, 0x06, 0x21, 0x07, 0x21, -- 0x08, 0x21, 0x09, 0x21, 0x0A, 0x21, 0x0B, 0x21, -- 0x0C, 0x21, 0x0D, 0x21, 0x0E, 0x21, 0x0F, 0x21, -- 0x10, 0x21, 0x11, 0x21, 0x12, 0x21, 0x13, 0x21, -- 0x14, 0x21, 0x15, 0x21, 0x16, 0x21, 0x17, 0x21, -- 0x18, 0x21, 0x19, 0x21, 0x1A, 0x21, 0x1B, 0x21, -- 0x1C, 0x21, 0x1D, 0x21, 0x1E, 0x21, 0x1F, 0x21, -- 0x20, 0x21, 0x21, 0x21, 0x22, 0x21, 0x23, 0x21, -- 0x24, 0x21, 0x25, 0x21, 0x26, 0x21, 0x27, 0x21, -- 0x28, 0x21, 0x29, 0x21, 0x2A, 0x21, 0x2B, 0x21, -- 0x2C, 0x21, 0x2D, 0x21, 0x2E, 0x21, 0x2F, 0x21, -- 0x30, 0x21, 0x31, 0x21, 0x32, 0x21, 0x33, 0x21, -- 0x34, 0x21, 0x35, 0x21, 0x36, 0x21, 0x37, 0x21, -- 0x38, 0x21, 0x39, 0x21, 0x3A, 0x21, 0x3B, 0x21, -- 0x3C, 0x21, 0x3D, 0x21, 0x3E, 0x21, 0x3F, 0x21, -- 0x40, 0x21, 0x41, 0x21, 0x42, 0x21, 0x43, 0x21, -- 0x44, 0x21, 0x45, 0x21, 0x46, 0x21, 0x47, 0x21, -- 0x48, 0x21, 0x49, 0x21, 0x4A, 0x21, 0x4B, 0x21, -- 0x4C, 0x21, 0x4D, 0x21, 0x32, 0x21, 0x4F, 0x21, -- 0x50, 0x21, 0x51, 0x21, 0x52, 0x21, 0x53, 0x21, -- 0x54, 0x21, 0x55, 0x21, 0x56, 0x21, 0x57, 0x21, -- 0x58, 0x21, 0x59, 0x21, 0x5A, 0x21, 0x5B, 0x21, -- 0x5C, 0x21, 0x5D, 0x21, 0x5E, 0x21, 0x5F, 0x21, -- 0x60, 0x21, 0x61, 0x21, 0x62, 0x21, 0x63, 0x21, -- 0x64, 0x21, 0x65, 0x21, 0x66, 0x21, 0x67, 0x21, -- 0x68, 0x21, 0x69, 0x21, 0x6A, 0x21, 0x6B, 0x21, -- 0x6C, 0x21, 0x6D, 0x21, 0x6E, 0x21, 0x6F, 0x21, -- 0x60, 0x21, 0x61, 0x21, 0x62, 0x21, 0x63, 0x21, -- 0x64, 0x21, 0x65, 0x21, 0x66, 0x21, 0x67, 0x21, -- 0x68, 0x21, 0x69, 0x21, 0x6A, 0x21, 0x6B, 0x21, -- 0x6C, 0x21, 0x6D, 0x21, 0x6E, 0x21, 0x6F, 0x21, -- 0x80, 0x21, 0x81, 0x21, 0x82, 0x21, 0x83, 0x21, -- 0x83, 0x21, 0xFF, 0xFF, 0x4B, 0x03, 0xB6, 0x24, -- 0xB7, 0x24, 0xB8, 0x24, 0xB9, 0x24, 0xBA, 0x24, -- 0xBB, 0x24, 0xBC, 0x24, 0xBD, 0x24, 0xBE, 0x24, -- 0xBF, 0x24, 0xC0, 0x24, 0xC1, 0x24, 0xC2, 0x24, -- 0xC3, 0x24, 0xC4, 0x24, 0xC5, 0x24, 0xC6, 0x24, -- 0xC7, 0x24, 0xC8, 0x24, 0xC9, 0x24, 0xCA, 0x24, -- 0xCB, 0x24, 0xCC, 0x24, 0xCD, 0x24, 0xCE, 0x24, -- 0xCF, 0x24, 0xFF, 0xFF, 0x46, 0x07, 0x00, 0x2C, -- 0x01, 0x2C, 0x02, 0x2C, 0x03, 0x2C, 0x04, 0x2C, -- 0x05, 0x2C, 0x06, 0x2C, 0x07, 0x2C, 0x08, 0x2C, -- 0x09, 0x2C, 0x0A, 0x2C, 0x0B, 0x2C, 0x0C, 0x2C, -- 0x0D, 0x2C, 0x0E, 0x2C, 0x0F, 0x2C, 0x10, 0x2C, -- 0x11, 0x2C, 0x12, 0x2C, 0x13, 0x2C, 0x14, 0x2C, -- 0x15, 0x2C, 0x16, 0x2C, 0x17, 0x2C, 0x18, 0x2C, -- 0x19, 0x2C, 0x1A, 0x2C, 0x1B, 0x2C, 0x1C, 0x2C, -- 0x1D, 0x2C, 0x1E, 0x2C, 0x1F, 0x2C, 0x20, 0x2C, -- 0x21, 0x2C, 0x22, 0x2C, 0x23, 0x2C, 0x24, 0x2C, -- 0x25, 0x2C, 0x26, 0x2C, 0x27, 0x2C, 0x28, 0x2C, -- 0x29, 0x2C, 0x2A, 0x2C, 0x2B, 0x2C, 0x2C, 0x2C, -- 0x2D, 0x2C, 0x2E, 0x2C, 0x5F, 0x2C, 0x60, 0x2C, -- 0x60, 0x2C, 0x62, 0x2C, 0x63, 0x2C, 0x64, 0x2C, -- 0x65, 0x2C, 0x66, 0x2C, 0x67, 0x2C, 0x67, 0x2C, -- 0x69, 0x2C, 0x69, 0x2C, 0x6B, 0x2C, 0x6B, 0x2C, -- 0x6D, 0x2C, 0x6E, 0x2C, 0x6F, 0x2C, 0x70, 0x2C, -- 0x71, 0x2C, 0x72, 0x2C, 0x73, 0x2C, 0x74, 0x2C, -- 0x75, 0x2C, 0x75, 0x2C, 0x77, 0x2C, 0x78, 0x2C, -- 0x79, 0x2C, 0x7A, 0x2C, 0x7B, 0x2C, 0x7C, 0x2C, -- 0x7D, 0x2C, 0x7E, 0x2C, 0x7F, 0x2C, 0x80, 0x2C, -- 0x80, 0x2C, 0x82, 0x2C, 0x82, 0x2C, 0x84, 0x2C, -- 0x84, 0x2C, 0x86, 0x2C, 0x86, 0x2C, 0x88, 0x2C, -- 0x88, 0x2C, 0x8A, 0x2C, 0x8A, 0x2C, 0x8C, 0x2C, -- 0x8C, 0x2C, 0x8E, 0x2C, 0x8E, 0x2C, 0x90, 0x2C, -- 0x90, 0x2C, 0x92, 0x2C, 0x92, 0x2C, 0x94, 0x2C, -- 0x94, 0x2C, 0x96, 0x2C, 0x96, 0x2C, 0x98, 0x2C, -- 0x98, 0x2C, 0x9A, 0x2C, 0x9A, 0x2C, 0x9C, 0x2C, -- 0x9C, 0x2C, 0x9E, 0x2C, 0x9E, 0x2C, 0xA0, 0x2C, -- 0xA0, 0x2C, 0xA2, 0x2C, 0xA2, 0x2C, 0xA4, 0x2C, -- 0xA4, 0x2C, 0xA6, 0x2C, 0xA6, 0x2C, 0xA8, 0x2C, -- 0xA8, 0x2C, 0xAA, 0x2C, 0xAA, 0x2C, 0xAC, 0x2C, -- 0xAC, 0x2C, 0xAE, 0x2C, 0xAE, 0x2C, 0xB0, 0x2C, -- 0xB0, 0x2C, 0xB2, 0x2C, 0xB2, 0x2C, 0xB4, 0x2C, -- 0xB4, 0x2C, 0xB6, 0x2C, 0xB6, 0x2C, 0xB8, 0x2C, -- 0xB8, 0x2C, 0xBA, 0x2C, 0xBA, 0x2C, 0xBC, 0x2C, -- 0xBC, 0x2C, 0xBE, 0x2C, 0xBE, 0x2C, 0xC0, 0x2C, -- 0xC0, 0x2C, 0xC2, 0x2C, 0xC2, 0x2C, 0xC4, 0x2C, -- 0xC4, 0x2C, 0xC6, 0x2C, 0xC6, 0x2C, 0xC8, 0x2C, -- 0xC8, 0x2C, 0xCA, 0x2C, 0xCA, 0x2C, 0xCC, 0x2C, -- 0xCC, 0x2C, 0xCE, 0x2C, 0xCE, 0x2C, 0xD0, 0x2C, -- 0xD0, 0x2C, 0xD2, 0x2C, 0xD2, 0x2C, 0xD4, 0x2C, -- 0xD4, 0x2C, 0xD6, 0x2C, 0xD6, 0x2C, 0xD8, 0x2C, -- 0xD8, 0x2C, 0xDA, 0x2C, 0xDA, 0x2C, 0xDC, 0x2C, -- 0xDC, 0x2C, 0xDE, 0x2C, 0xDE, 0x2C, 0xE0, 0x2C, -- 0xE0, 0x2C, 0xE2, 0x2C, 0xE2, 0x2C, 0xE4, 0x2C, -- 0xE5, 0x2C, 0xE6, 0x2C, 0xE7, 0x2C, 0xE8, 0x2C, -- 0xE9, 0x2C, 0xEA, 0x2C, 0xEB, 0x2C, 0xEC, 0x2C, -- 0xED, 0x2C, 0xEE, 0x2C, 0xEF, 0x2C, 0xF0, 0x2C, -- 0xF1, 0x2C, 0xF2, 0x2C, 0xF3, 0x2C, 0xF4, 0x2C, -- 0xF5, 0x2C, 0xF6, 0x2C, 0xF7, 0x2C, 0xF8, 0x2C, -- 0xF9, 0x2C, 0xFA, 0x2C, 0xFB, 0x2C, 0xFC, 0x2C, -- 0xFD, 0x2C, 0xFE, 0x2C, 0xFF, 0x2C, 0xA0, 0x10, -- 0xA1, 0x10, 0xA2, 0x10, 0xA3, 0x10, 0xA4, 0x10, -- 0xA5, 0x10, 0xA6, 0x10, 0xA7, 0x10, 0xA8, 0x10, -- 0xA9, 0x10, 0xAA, 0x10, 0xAB, 0x10, 0xAC, 0x10, -- 0xAD, 0x10, 0xAE, 0x10, 0xAF, 0x10, 0xB0, 0x10, -- 0xB1, 0x10, 0xB2, 0x10, 0xB3, 0x10, 0xB4, 0x10, -- 0xB5, 0x10, 0xB6, 0x10, 0xB7, 0x10, 0xB8, 0x10, -- 0xB9, 0x10, 0xBA, 0x10, 0xBB, 0x10, 0xBC, 0x10, -- 0xBD, 0x10, 0xBE, 0x10, 0xBF, 0x10, 0xC0, 0x10, -- 0xC1, 0x10, 0xC2, 0x10, 0xC3, 0x10, 0xC4, 0x10, -- 0xC5, 0x10, 0xFF, 0xFF, 0x1B, 0xD2, 0x21, 0xFF, -- 0x22, 0xFF, 0x23, 0xFF, 0x24, 0xFF, 0x25, 0xFF, -- 0x26, 0xFF, 0x27, 0xFF, 0x28, 0xFF, 0x29, 0xFF, -- 0x2A, 0xFF, 0x2B, 0xFF, 0x2C, 0xFF, 0x2D, 0xFF, -- 0x2E, 0xFF, 0x2F, 0xFF, 0x30, 0xFF, 0x31, 0xFF, -- 0x32, 0xFF, 0x33, 0xFF, 0x34, 0xFF, 0x35, 0xFF, -- 0x36, 0xFF, 0x37, 0xFF, 0x38, 0xFF, 0x39, 0xFF, -- 0x3A, 0xFF, 0x5B, 0xFF, 0x5C, 0xFF, 0x5D, 0xFF, -- 0x5E, 0xFF, 0x5F, 0xFF, 0x60, 0xFF, 0x61, 0xFF, -- 0x62, 0xFF, 0x63, 0xFF, 0x64, 0xFF, 0x65, 0xFF, -- 0x66, 0xFF, 0x67, 0xFF, 0x68, 0xFF, 0x69, 0xFF, -- 0x6A, 0xFF, 0x6B, 0xFF, 0x6C, 0xFF, 0x6D, 0xFF, -- 0x6E, 0xFF, 0x6F, 0xFF, 0x70, 0xFF, 0x71, 0xFF, -- 0x72, 0xFF, 0x73, 0xFF, 0x74, 0xFF, 0x75, 0xFF, -- 0x76, 0xFF, 0x77, 0xFF, 0x78, 0xFF, 0x79, 0xFF, -- 0x7A, 0xFF, 0x7B, 0xFF, 0x7C, 0xFF, 0x7D, 0xFF, -- 0x7E, 0xFF, 0x7F, 0xFF, 0x80, 0xFF, 0x81, 0xFF, -- 0x82, 0xFF, 0x83, 0xFF, 0x84, 0xFF, 0x85, 0xFF, -- 0x86, 0xFF, 0x87, 0xFF, 0x88, 0xFF, 0x89, 0xFF, -- 0x8A, 0xFF, 0x8B, 0xFF, 0x8C, 0xFF, 0x8D, 0xFF, -- 0x8E, 0xFF, 0x8F, 0xFF, 0x90, 0xFF, 0x91, 0xFF, -- 0x92, 0xFF, 0x93, 0xFF, 0x94, 0xFF, 0x95, 0xFF, -- 0x96, 0xFF, 0x97, 0xFF, 0x98, 0xFF, 0x99, 0xFF, -- 0x9A, 0xFF, 0x9B, 0xFF, 0x9C, 0xFF, 0x9D, 0xFF, -- 0x9E, 0xFF, 0x9F, 0xFF, 0xA0, 0xFF, 0xA1, 0xFF, -- 0xA2, 0xFF, 0xA3, 0xFF, 0xA4, 0xFF, 0xA5, 0xFF, -- 0xA6, 0xFF, 0xA7, 0xFF, 0xA8, 0xFF, 0xA9, 0xFF, -- 0xAA, 0xFF, 0xAB, 0xFF, 0xAC, 0xFF, 0xAD, 0xFF, -- 0xAE, 0xFF, 0xAF, 0xFF, 0xB0, 0xFF, 0xB1, 0xFF, -- 0xB2, 0xFF, 0xB3, 0xFF, 0xB4, 0xFF, 0xB5, 0xFF, -- 0xB6, 0xFF, 0xB7, 0xFF, 0xB8, 0xFF, 0xB9, 0xFF, -- 0xBA, 0xFF, 0xBB, 0xFF, 0xBC, 0xFF, 0xBD, 0xFF, -- 0xBE, 0xFF, 0xBF, 0xFF, 0xC0, 0xFF, 0xC1, 0xFF, -- 0xC2, 0xFF, 0xC3, 0xFF, 0xC4, 0xFF, 0xC5, 0xFF, -- 0xC6, 0xFF, 0xC7, 0xFF, 0xC8, 0xFF, 0xC9, 0xFF, -- 0xCA, 0xFF, 0xCB, 0xFF, 0xCC, 0xFF, 0xCD, 0xFF, -- 0xCE, 0xFF, 0xCF, 0xFF, 0xD0, 0xFF, 0xD1, 0xFF, -- 0xD2, 0xFF, 0xD3, 0xFF, 0xD4, 0xFF, 0xD5, 0xFF, -- 0xD6, 0xFF, 0xD7, 0xFF, 0xD8, 0xFF, 0xD9, 0xFF, -- 0xDA, 0xFF, 0xDB, 0xFF, 0xDC, 0xFF, 0xDD, 0xFF, -- 0xDE, 0xFF, 0xDF, 0xFF, 0xE0, 0xFF, 0xE1, 0xFF, -- 0xE2, 0xFF, 0xE3, 0xFF, 0xE4, 0xFF, 0xE5, 0xFF, -- 0xE6, 0xFF, 0xE7, 0xFF, 0xE8, 0xFF, 0xE9, 0xFF, -- 0xEA, 0xFF, 0xEB, 0xFF, 0xEC, 0xFF, 0xED, 0xFF, -- 0xEE, 0xFF, 0xEF, 0xFF, 0xF0, 0xFF, 0xF1, 0xFF, -- 0xF2, 0xFF, 0xF3, 0xFF, 0xF4, 0xFF, 0xF5, 0xFF, -- 0xF6, 0xFF, 0xF7, 0xFF, 0xF8, 0xFF, 0xF9, 0xFF, -- 0xFA, 0xFF, 0xFB, 0xFF, 0xFC, 0xFF, 0xFD, 0xFF, -- 0xFE, 0xFF, 0xFF, 0xFF --}; -diff -Nurp linux-5.6.3.orig/drivers/staging/exfat/Kconfig linux-5.6.3/drivers/staging/exfat/Kconfig ---- linux-5.6.3.orig/drivers/staging/exfat/Kconfig 2020-03-30 01:25:41.000000000 +0300 -+++ linux-5.6.3/drivers/staging/exfat/Kconfig 1970-01-01 02:00:00.000000000 +0200 -@@ -1,41 +0,0 @@ --# SPDX-License-Identifier: GPL-2.0 --config STAGING_EXFAT_FS -- tristate "exFAT fs support" -- depends on BLOCK -- select NLS -- help -- This adds support for the exFAT file system. -- --config STAGING_EXFAT_DISCARD -- bool "enable discard support" -- depends on STAGING_EXFAT_FS -- default y -- --config STAGING_EXFAT_DELAYED_SYNC -- bool "enable delayed sync" -- depends on STAGING_EXFAT_FS -- default n -- --config STAGING_EXFAT_KERNEL_DEBUG -- bool "enable kernel debug features via ioctl" -- depends on STAGING_EXFAT_FS -- default n -- --config STAGING_EXFAT_DEBUG_MSG -- bool "print debug messages" -- depends on STAGING_EXFAT_FS -- default n -- --config STAGING_EXFAT_DEFAULT_CODEPAGE -- int "Default codepage for exFAT" -- default 437 -- depends on STAGING_EXFAT_FS -- help -- This option should be set to the codepage of your exFAT filesystems. -- --config STAGING_EXFAT_DEFAULT_IOCHARSET -- string "Default iocharset for exFAT" -- default "utf8" -- depends on STAGING_EXFAT_FS -- help -- Set this to the default input/output character set you'd like exFAT to use. -diff -Nurp linux-5.6.3.orig/drivers/staging/exfat/Makefile linux-5.6.3/drivers/staging/exfat/Makefile ---- linux-5.6.3.orig/drivers/staging/exfat/Makefile 2020-03-30 01:25:41.000000000 +0300 -+++ linux-5.6.3/drivers/staging/exfat/Makefile 1970-01-01 02:00:00.000000000 +0200 -@@ -1,10 +0,0 @@ --# SPDX-License-Identifier: GPL-2.0-or-later -- --obj-$(CONFIG_STAGING_EXFAT_FS) += exfat.o -- --exfat-y := exfat_core.o \ -- exfat_super.o \ -- exfat_blkdev.o \ -- exfat_cache.o \ -- exfat_nls.o \ -- exfat_upcase.o -diff -Nurp linux-5.6.3.orig/drivers/staging/exfat/TODO linux-5.6.3/drivers/staging/exfat/TODO ---- linux-5.6.3.orig/drivers/staging/exfat/TODO 2020-03-30 01:25:41.000000000 +0300 -+++ linux-5.6.3/drivers/staging/exfat/TODO 1970-01-01 02:00:00.000000000 +0200 -@@ -1,69 +0,0 @@ --A laundry list of things that need looking at, most of which will --require more work than the average checkpatch cleanup... -- --Note that some of these entries may not be bugs - they're things --that need to be looked at, and *possibly* fixed. -- --Clean up the ffsCamelCase function names. -- --Fix (thing)->flags to not use magic numbers - multiple offenders -- --Sort out all the s32/u32/u8 nonsense - most of these should be plain int. -- --exfat_core.c - ffsReadFile - the goto err_out seem to leak a brelse(). --same for ffsWriteFile. -- --All the calls to fs_sync() need to be looked at, particularly in the --context of EXFAT_DELAYED_SYNC. Currently, if that's defined, we only --flush to disk when sync() gets called. We should be doing at least --metadata flushes at appropriate times. -- --ffsTruncateFile - if (old_size <= new_size) { --That doesn't look right. How did it ever work? Are they relying on lazy --block allocation when actual writes happen? If nothing else, it never --does the 'fid->size = new_size' and do the inode update.... -- --ffsSetAttr() is just dangling in the breeze, not wired up at all... -- --Convert global mutexes to a per-superblock mutex. -- --Right now, we load exactly one UTF-8 table. Check to see --if that plays nice with different codepage and iocharset values --for simultanous mounts of different devices -- --exfat_rmdir() checks for -EBUSY but ffsRemoveDir() doesn't return it. --In fact, there's a complete lack of -EBUSY testing anywhere. -- --There's probably a few missing checks for -EEXIST -- --check return codes of sync_dirty_buffer() -- --Why is remove_file doing a num_entries++?? -- --Double check a lot of can't-happen parameter checks (for null pointers for --things that have only one call site and can't pass a null, etc). -- --All the DEBUG stuff can probably be tossed, including the ioctl(). Either --that, or convert to a proper fault-injection system. -- --exfat_remount does exactly one thing. Fix to actually deal with remount --options, particularly handling R/O correctly. For that matter, allow --R/O mounts in the first place. -- --Figure out why the VFAT code used multi_sector_(read|write) but the --exfat code doesn't use it. The difference matters on SSDs with wear leveling. -- --exfat_fat_sync(), exfat_buf_sync(), and sync_alloc_bitmap() --aren't called anyplace.... -- --Create helper function for exfat_set_entry_time() and exfat_set_entry_type() --because it's sort of ugly to be calling the same functionn directly and --other code calling through the fs_func struc ponters... -- --clean up the remaining vol_type checks, which are of two types: --some are ?: operators with magic numbers, and the rest are places --where we're doing stuff with '.' and '..'. -- --Patches to: -- Greg Kroah-Hartman -- Valdis Kletnieks -diff -Nurp linux-5.6.3.orig/drivers/staging/Kconfig linux-5.6.3/drivers/staging/Kconfig ---- linux-5.6.3.orig/drivers/staging/Kconfig 2020-03-30 01:25:41.000000000 +0300 -+++ linux-5.6.3/drivers/staging/Kconfig 2020-04-10 13:23:50.104394573 +0300 -@@ -115,8 +115,6 @@ source "drivers/staging/kpc2000/Kconfig" - source "drivers/staging/wusbcore/Kconfig" - source "drivers/staging/uwb/Kconfig" - --source "drivers/staging/exfat/Kconfig" -- - source "drivers/staging/qlge/Kconfig" - - source "drivers/staging/hp/Kconfig" -diff -Nurp linux-5.6.3.orig/drivers/staging/Makefile linux-5.6.3/drivers/staging/Makefile ---- linux-5.6.3.orig/drivers/staging/Makefile 2020-03-30 01:25:41.000000000 +0300 -+++ linux-5.6.3/drivers/staging/Makefile 2020-04-10 13:23:55.703656045 +0300 -@@ -48,7 +48,6 @@ obj-$(CONFIG_FIELDBUS_DEV) += fieldb - obj-$(CONFIG_KPC2000) += kpc2000/ - obj-$(CONFIG_UWB) += uwb/ - obj-$(CONFIG_USB_WUSB) += wusbcore/ --obj-$(CONFIG_STAGING_EXFAT_FS) += exfat/ - obj-$(CONFIG_QLGE) += qlge/ - obj-$(CONFIG_NET_VENDOR_HP) += hp/ - obj-$(CONFIG_WFX) += wfx/ -diff -Nurp linux-5.6.3.orig/MAINTAINERS linux-5.6.3/MAINTAINERS ---- linux-5.6.3.orig/MAINTAINERS 2020-03-30 01:25:41.000000000 +0300 -+++ linux-5.6.3/MAINTAINERS 2020-04-10 13:23:25.806260135 +0300 -@@ -6304,12 +6304,6 @@ F: include/trace/events/mdio.h - F: include/uapi/linux/mdio.h - F: include/uapi/linux/mii.h - --EXFAT FILE SYSTEM --M: Valdis Kletnieks --L: linux-fsdevel@vger.kernel.org --S: Maintained --F: drivers/staging/exfat/ -- - EXT2 FILE SYSTEM - M: Jan Kara - L: linux-ext4@vger.kernel.org diff --git a/kernel/kernel/files/patches/mageia/fs-exfat-update-file-system-parameter-handling.patch b/kernel/kernel/files/patches/mageia/fs-exfat-update-file-system-parameter-handling.patch deleted file mode 100644 index 9e07cd45..00000000 --- a/kernel/kernel/files/patches/mageia/fs-exfat-update-file-system-parameter-handling.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 9acd0d53800c55c6e2186e29b6433daf24617451 Mon Sep 17 00:00:00 2001 -From: Valdis Kletnieks -Date: Mon, 2 Mar 2020 15:21:45 +0900 -Subject: [PATCH] exfat: update file system parameter handling - -Al Viro recently reworked the way file system parameters are handled -Update super.c to work with it in linux-next 20200203. - -Signed-off-by: Valdis Kletnieks -Reviewed-by: Christoph Hellwig -Acked-by: Namjae Jeon -Signed-off-by: Al Viro ---- - fs/exfat/super.c | 28 +++++++++++----------------- - 1 file changed, 11 insertions(+), 17 deletions(-) - -diff --git a/fs/exfat/super.c b/fs/exfat/super.c -index f06e0b53e393..16ed202ef527 100644 ---- a/fs/exfat/super.c -+++ b/fs/exfat/super.c -@@ -214,7 +214,14 @@ enum { - Opt_time_offset, - }; - --static const struct fs_parameter_spec exfat_param_specs[] = { -+static const struct constant_table exfat_param_enums[] = { -+ { "continue", EXFAT_ERRORS_CONT }, -+ { "panic", EXFAT_ERRORS_PANIC }, -+ { "remount-ro", EXFAT_ERRORS_RO }, -+ {} -+}; -+ -+static const struct fs_parameter_spec exfat_parameters[] = { - fsparam_u32("uid", Opt_uid), - fsparam_u32("gid", Opt_gid), - fsparam_u32oct("umask", Opt_umask), -@@ -222,25 +229,12 @@ static const struct fs_parameter_spec exfat_param_specs[] = { - fsparam_u32oct("fmask", Opt_fmask), - fsparam_u32oct("allow_utime", Opt_allow_utime), - fsparam_string("iocharset", Opt_charset), -- fsparam_enum("errors", Opt_errors), -+ fsparam_enum("errors", Opt_errors, exfat_param_enums), - fsparam_flag("discard", Opt_discard), - fsparam_s32("time_offset", Opt_time_offset), - {} - }; - --static const struct fs_parameter_enum exfat_param_enums[] = { -- { Opt_errors, "continue", EXFAT_ERRORS_CONT }, -- { Opt_errors, "panic", EXFAT_ERRORS_PANIC }, -- { Opt_errors, "remount-ro", EXFAT_ERRORS_RO }, -- {} --}; -- --static const struct fs_parameter_description exfat_parameters = { -- .name = "exfat", -- .specs = exfat_param_specs, -- .enums = exfat_param_enums, --}; -- - static int exfat_parse_param(struct fs_context *fc, struct fs_parameter *param) - { - struct exfat_sb_info *sbi = fc->s_fs_info; -@@ -248,7 +242,7 @@ static int exfat_parse_param(struct fs_context *fc, struct fs_parameter *param) - struct fs_parse_result result; - int opt; - -- opt = fs_parse(fc, &exfat_parameters, param, &result); -+ opt = fs_parse(fc, exfat_parameters, param, &result); - if (opt < 0) - return opt; - -@@ -665,7 +659,7 @@ static struct file_system_type exfat_fs_type = { - .owner = THIS_MODULE, - .name = "exfat", - .init_fs_context = exfat_init_fs_context, -- .parameters = &exfat_parameters, -+ .parameters = exfat_parameters, - .kill_sb = kill_block_super, - .fs_flags = FS_REQUIRES_DEV, - }; --- -2.26.0 - diff --git a/kernel/kernel/pspec.xml b/kernel/kernel/pspec.xml index 6b61ec35..fc40e2cc 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://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-5.6.tar.gz + https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-5.7.tar.gz configs/kernel-x86_64-config scripts/generate-module-list @@ -33,27 +33,11 @@ - patches/linux/patch-5.6.19.xz + patches/linux/patch-5.7.13.xz patches/mageia/fs-aufs-5.6.patch patches/mageia/fs-aufs-5.6-modular.patch patches/mageia/fs-aufs-5.6-fix.patch - patches/mageia/fs-exfat-remove-from-staging.patch - patches/mageia/fs-exfat-add-in-memory-and-on-disk-structures-and-heade.patch - patches/mageia/fs-exfat-add-super-block-operations.patch - patches/mageia/fs-exfat-add-inode-operations.patch - patches/mageia/fs-exfat-add-directory-operations.patch - patches/mageia/fs-exfat-add-file-operations.patch - patches/mageia/fs-exfat-add-fat-entry-operations.patch - patches/mageia/fs-exfat-add-bitmap-operations.patch - patches/mageia/fs-exfat-add-exfat-cache.patch - patches/mageia/fs-exfat-add-misc-operations.patch - patches/mageia/fs-exfat-add-nls-operations.patch - patches/mageia/fs-exfat-add-Kconfig-and-Makefile.patch - patches/mageia/fs-MAINTAINERS-add-exfat-filesystem.patch - patches/mageia/fs-exfat-update-file-system-parameter-handling.patch - patches/mageia/fs-exfat-add-module_alias_fs.patch - patches/mageia/fs-exfat-fix-discard-support.patch patches/mageia/CVE-2019-12379.patch @@ -113,6 +97,17 @@ + + 2020-08-05 + 5.7.13 + Version bump. + security + + systemRestart + + Mustafa Cinasal + muscnsl@gmail.com + 2020-06-17 5.6.19